1157091Simp/* Implementation of the internal dcigettext function.
2157091Simp   Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
3157091Simp
4157091Simp   This program is free software; you can redistribute it and/or modify it
5157091Simp   under the terms of the GNU Library General Public License as published
6157091Simp   by the Free Software Foundation; either version 2, or (at your option)
7157091Simp   any later version.
8157091Simp
9157091Simp   This program is distributed in the hope that it will be useful,
10157091Simp   but WITHOUT ANY WARRANTY; without even the implied warranty of
11157091Simp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12157091Simp   Library General Public License for more details.
13185265Simp
14185265Simp   You should have received a copy of the GNU Library General Public
15185265Simp   License along with this program; if not, write to the Free Software
16185265Simp   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
17185265Simp   USA.  */
18185265Simp
19185265Simp/* Tell glibc's <string.h> to provide a prototype for mempcpy().
20185265Simp   This must come before <config.h> because <config.h> may include
21185265Simp   <features.h>, and once <features.h> has been included, it's too late.  */
22185265Simp#ifndef _GNU_SOURCE
23185265Simp# define _GNU_SOURCE	1
24157091Simp#endif
25157091Simp
26157091Simp#ifdef HAVE_CONFIG_H
27157091Simp# include <config.h>
28157091Simp#endif
29157091Simp
30157091Simp#include <sys/types.h>
31157091Simp
32157091Simp#ifdef __GNUC__
33157091Simp# define alloca __builtin_alloca
34157091Simp# define HAVE_ALLOCA 1
35157091Simp#else
36157091Simp# ifdef _MSC_VER
37157091Simp#  include <malloc.h>
38157091Simp#  define alloca _alloca
39157091Simp# else
40157091Simp#  if defined HAVE_ALLOCA_H || defined _LIBC
41157091Simp#   include <alloca.h>
42157091Simp#  else
43157091Simp#   ifdef _AIX
44157091Simp #pragma alloca
45157091Simp#   else
46157091Simp#    ifndef alloca
47157091Simpchar *alloca ();
48157091Simp#    endif
49157091Simp#   endif
50157091Simp#  endif
51157091Simp# endif
52157091Simp#endif
53157091Simp
54157091Simp#include <errno.h>
55157091Simp#ifndef errno
56157091Simpextern int errno;
57157091Simp#endif
58157091Simp#ifndef __set_errno
59157091Simp# define __set_errno(val) errno = (val)
60157091Simp#endif
61157091Simp
62157091Simp#include <stddef.h>
63157091Simp#include <stdlib.h>
64157091Simp#include <string.h>
65157091Simp
66157091Simp#if defined HAVE_UNISTD_H || defined _LIBC
67157091Simp# include <unistd.h>
68157091Simp#endif
69160365Simp
70157091Simp#include <locale.h>
71160365Simp
72160365Simp#ifdef _LIBC
73160365Simp  /* Guess whether integer division by zero raises signal SIGFPE.
74157091Simp     Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
75157091Simp# if defined __alpha__ || defined __arm__ || defined __i386__ \
76157091Simp     || defined __m68k__ || defined __s390__
77157091Simp#  define INTDIV0_RAISES_SIGFPE 1
78157091Simp# else
79157091Simp#  define INTDIV0_RAISES_SIGFPE 0
80157091Simp# endif
81157091Simp#endif
82157091Simp#if !INTDIV0_RAISES_SIGFPE
83157091Simp# include <signal.h>
84157091Simp#endif
85157091Simp
86157091Simp#if defined HAVE_SYS_PARAM_H || defined _LIBC
87157091Simp# include <sys/param.h>
88157091Simp#endif
89157091Simp
90157091Simp#include "gettextP.h"
91157091Simp#include "plural-exp.h"
92163525Simp#ifdef _LIBC
93163525Simp# include <libintl.h>
94157091Simp#else
95157091Simp# include "libgnuintl.h"
96157091Simp#endif
97157091Simp#include "hash-string.h"
98157091Simp
99157091Simp/* Thread safetyness.  */
100163525Simp#ifdef _LIBC
101163525Simp# include <bits/libc-lock.h>
102157091Simp#else
103157091Simp/* Provide dummy implementation if this is outside glibc.  */
104157091Simp# define __libc_lock_define_initialized(CLASS, NAME)
105157091Simp# define __libc_lock_lock(NAME)
106157091Simp# define __libc_lock_unlock(NAME)
107157091Simp# define __libc_rwlock_define_initialized(CLASS, NAME)
108157091Simp# define __libc_rwlock_rdlock(NAME)
109157091Simp# define __libc_rwlock_unlock(NAME)
110157091Simp#endif
111157091Simp
112157091Simp/* Alignment of types.  */
113157091Simp#if defined __GNUC__ && __GNUC__ >= 2
114157091Simp# define alignof(TYPE) __alignof__ (TYPE)
115157091Simp#else
116157091Simp# define alignof(TYPE) \
117157091Simp    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
118157091Simp#endif
119157091Simp
120157091Simp/* The internal variables in the standalone libintl.a must have different
121157091Simp   names than the internal variables in GNU libc, otherwise programs
122157091Simp   using libintl.a cannot be linked statically.  */
123157091Simp#if !defined _LIBC
124157091Simp# define _nl_default_default_domain libintl_nl_default_default_domain
125157091Simp# define _nl_current_default_domain libintl_nl_current_default_domain
126157091Simp# define _nl_default_dirname libintl_nl_default_dirname
127157091Simp# define _nl_domain_bindings libintl_nl_domain_bindings
128166901Spiso#endif
129157091Simp
130157091Simp/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
131157091Simp#ifndef offsetof
132157091Simp# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
133157091Simp#endif
134157091Simp
135157091Simp/* @@ end of prolog @@ */
136157091Simp
137157091Simp#ifdef _LIBC
138157091Simp/* Rename the non ANSI C functions.  This is required by the standard
139157091Simp   because some ANSI C functions will require linking with this object
140163525Simp   file and the name space must not be polluted.  */
141163525Simp# define getcwd __getcwd
142163525Simp# ifndef stpcpy
143163525Simp#  define stpcpy __stpcpy
144163525Simp# endif
145163525Simp# define tfind __tfind
146163525Simp#else
147163525Simp# if !defined HAVE_GETCWD
148163525Simpchar *getwd ();
149163525Simp#  define getcwd(buf, max) getwd (buf)
150163525Simp# else
151163525Simpchar *getcwd ();
152163525Simp# endif
153225882Skevlo# ifndef HAVE_STPCPY
154157091Simpstatic char *stpcpy PARAMS ((char *dest, const char *src));
155157091Simp# endif
156157091Simp# ifndef HAVE_MEMPCPY
157157091Simpstatic void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
158157091Simp# endif
159157091Simp#endif
160157091Simp
161157091Simp/* Amount to increase buffer size by in each try.  */
162157091Simp#define PATH_INCR 32
163157091Simp
164157091Simp/* The following is from pathmax.h.  */
165157091Simp/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
166157091Simp   PATH_MAX but might cause redefinition warnings when sys/param.h is
167157091Simp   later included (as on MORE/BSD 4.3).  */
168157091Simp#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
169157091Simp# include <limits.h>
170157091Simp#endif
171157091Simp
172157091Simp#ifndef _POSIX_PATH_MAX
173157091Simp# define _POSIX_PATH_MAX 255
174157091Simp#endif
175157091Simp
176157091Simp#if !defined PATH_MAX && defined _PC_PATH_MAX
177157091Simp# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
178157091Simp#endif
179157091Simp
180163525Simp/* Don't include sys/param.h if it already has been.  */
181157091Simp#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
182157091Simp# include <sys/param.h>
183157091Simp#endif
184157091Simp
185157091Simp#if !defined PATH_MAX && defined MAXPATHLEN
186157091Simp# define PATH_MAX MAXPATHLEN
187157091Simp#endif
188157091Simp
189157091Simp#ifndef PATH_MAX
190157091Simp# define PATH_MAX _POSIX_PATH_MAX
191157091Simp#endif
192157091Simp
193157091Simp/* Pathname support.
194157091Simp   ISSLASH(C)           tests whether C is a directory separator character.
195157091Simp   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
196157091Simp                        it may be concatenated to a directory pathname.
197157091Simp   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
198157091Simp */
199157091Simp#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
200157091Simp  /* Win32, OS/2, DOS */
201157091Simp# define ISSLASH(C) ((C) == '/' || (C) == '\\')
202157091Simp# define HAS_DEVICE(P) \
203157091Simp    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
204157091Simp     && (P)[1] == ':')
205157091Simp# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
206157091Simp# define IS_PATH_WITH_DIR(P) \
207157091Simp    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
208157091Simp#else
209157091Simp  /* Unix */
210157091Simp# define ISSLASH(C) ((C) == '/')
211157091Simp# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
212157091Simp# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
213157091Simp#endif
214157091Simp
215157091Simp/* This is the type used for the search tree where known translations
216157091Simp   are stored.  */
217236989Simpstruct known_translation_t
218157091Simp{
219157091Simp  /* Domain in which to search.  */
220157091Simp  char *domainname;
221157091Simp
222157091Simp  /* The category.  */
223157091Simp  int category;
224157091Simp
225157091Simp  /* State of the catalog counter at the point the string was found.  */
226157091Simp  int counter;
227157091Simp
228157091Simp  /* Catalog where the string was found.  */
229157091Simp  struct loaded_l10nfile *domain;
230157091Simp
231157091Simp  /* And finally the translation.  */
232157091Simp  const char *translation;
233157091Simp  size_t translation_length;
234157091Simp
235157091Simp  /* Pointer to the string in question.  */
236157091Simp  char msgid[ZERO];
237157091Simp};
238157091Simp
239157091Simp/* Root of the search tree with known translations.  We can use this
240157091Simp   only if the system provides the `tsearch' function family.  */
241157091Simp#if defined HAVE_TSEARCH || defined _LIBC
242157091Simp# include <search.h>
243157091Simp
244163525Simpstatic void *root;
245157091Simp
246163525Simp# ifdef _LIBC
247157091Simp#  define tsearch __tsearch
248157091Simp# endif
249163525Simp
250163525Simp/* Function to compare two entries in the table of known translations.  */
251163525Simpstatic int transcmp PARAMS ((const void *p1, const void *p2));
252163525Simpstatic int
253163525Simptranscmp (p1, p2)
254163525Simp     const void *p1;
255157091Simp     const void *p2;
256157091Simp{
257157091Simp  const struct known_translation_t *s1;
258157091Simp  const struct known_translation_t *s2;
259157091Simp  int result;
260157091Simp
261157091Simp  s1 = (const struct known_translation_t *) p1;
262157091Simp  s2 = (const struct known_translation_t *) p2;
263157091Simp
264157091Simp  result = strcmp (s1->msgid, s2->msgid);
265157091Simp  if (result == 0)
266157091Simp    {
267157091Simp      result = strcmp (s1->domainname, s2->domainname);
268157091Simp      if (result == 0)
269157091Simp	/* We compare the category last (though this is the cheapest
270157091Simp	   operation) since it is hopefully always the same (namely
271	   LC_MESSAGES).  */
272	result = s1->category - s2->category;
273    }
274
275  return result;
276}
277#endif
278
279#ifndef INTVARDEF
280# define INTVARDEF(name)
281#endif
282#ifndef INTUSE
283# define INTUSE(name) name
284#endif
285
286/* Name of the default domain used for gettext(3) prior any call to
287   textdomain(3).  The default value for this is "messages".  */
288const char _nl_default_default_domain[] attribute_hidden = "messages";
289
290/* Value used as the default domain for gettext(3).  */
291const char *_nl_current_default_domain attribute_hidden
292     = _nl_default_default_domain;
293
294/* Contains the default location of the message catalogs.  */
295#if defined __EMX__
296extern const char _nl_default_dirname[];
297#else
298const char _nl_default_dirname[] = LOCALEDIR;
299INTVARDEF (_nl_default_dirname)
300#endif
301
302/* List with bindings of specific domains created by bindtextdomain()
303   calls.  */
304struct binding *_nl_domain_bindings;
305
306/* Prototypes for local functions.  */
307static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
308				    unsigned long int n,
309				    const char *translation,
310				    size_t translation_len))
311     internal_function;
312static const char *guess_category_value PARAMS ((int category,
313						 const char *categoryname))
314     internal_function;
315#ifdef _LIBC
316# include "../locale/localeinfo.h"
317# define category_to_name(category)	_nl_category_names[category]
318#else
319static const char *category_to_name PARAMS ((int category)) internal_function;
320#endif
321
322
323/* For those loosing systems which don't have `alloca' we have to add
324   some additional code emulating it.  */
325#ifdef HAVE_ALLOCA
326/* Nothing has to be done.  */
327# define freea(p) /* nothing */
328# define ADD_BLOCK(list, address) /* nothing */
329# define FREE_BLOCKS(list) /* nothing */
330#else
331struct block_list
332{
333  void *address;
334  struct block_list *next;
335};
336# define ADD_BLOCK(list, addr)						      \
337  do {									      \
338    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
339    /* If we cannot get a free block we cannot add the new element to	      \
340       the list.  */							      \
341    if (newp != NULL) {							      \
342      newp->address = (addr);						      \
343      newp->next = (list);						      \
344      (list) = newp;							      \
345    }									      \
346  } while (0)
347# define FREE_BLOCKS(list)						      \
348  do {									      \
349    while (list != NULL) {						      \
350      struct block_list *old = list;					      \
351      list = list->next;						      \
352      free (old->address);						      \
353      free (old);							      \
354    }									      \
355  } while (0)
356# undef alloca
357# define alloca(size) (malloc (size))
358# define freea(p) free (p)
359#endif	/* have alloca */
360
361
362#ifdef _LIBC
363/* List of blocks allocated for translations.  */
364typedef struct transmem_list
365{
366  struct transmem_list *next;
367  char data[ZERO];
368} transmem_block_t;
369static struct transmem_list *transmem_list;
370#else
371typedef unsigned char transmem_block_t;
372#endif
373
374
375/* Names for the libintl functions are a problem.  They must not clash
376   with existing names and they should follow ANSI C.  But this source
377   code is also used in GNU C Library where the names have a __
378   prefix.  So we have to make a difference here.  */
379#ifdef _LIBC
380# define DCIGETTEXT __dcigettext
381#else
382# define DCIGETTEXT libintl_dcigettext
383#endif
384
385/* Lock variable to protect the global data in the gettext implementation.  */
386#ifdef _LIBC
387__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
388#endif
389
390/* Checking whether the binaries runs SUID must be done and glibc provides
391   easier methods therefore we make a difference here.  */
392#ifdef _LIBC
393# define ENABLE_SECURE __libc_enable_secure
394# define DETERMINE_SECURE
395#else
396# ifndef HAVE_GETUID
397#  define getuid() 0
398# endif
399# ifndef HAVE_GETGID
400#  define getgid() 0
401# endif
402# ifndef HAVE_GETEUID
403#  define geteuid() getuid()
404# endif
405# ifndef HAVE_GETEGID
406#  define getegid() getgid()
407# endif
408static int enable_secure;
409# define ENABLE_SECURE (enable_secure == 1)
410# define DETERMINE_SECURE \
411  if (enable_secure == 0)						      \
412    {									      \
413      if (getuid () != geteuid () || getgid () != getegid ())		      \
414	enable_secure = 1;						      \
415      else								      \
416	enable_secure = -1;						      \
417    }
418#endif
419
420/* Get the function to evaluate the plural expression.  */
421#include "eval-plural.h"
422
423/* Look up MSGID in the DOMAINNAME message catalog for the current
424   CATEGORY locale and, if PLURAL is nonzero, search over string
425   depending on the plural form determined by N.  */
426char *
427DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
428     const char *domainname;
429     const char *msgid1;
430     const char *msgid2;
431     int plural;
432     unsigned long int n;
433     int category;
434{
435#ifndef HAVE_ALLOCA
436  struct block_list *block_list = NULL;
437#endif
438  struct loaded_l10nfile *domain;
439  struct binding *binding;
440  const char *categoryname;
441  const char *categoryvalue;
442  char *dirname, *xdomainname;
443  char *single_locale;
444  char *retval;
445  size_t retlen;
446  int saved_errno;
447#if defined HAVE_TSEARCH || defined _LIBC
448  struct known_translation_t *search;
449  struct known_translation_t **foundp = NULL;
450  size_t msgid_len;
451#endif
452  size_t domainname_len;
453
454  /* If no real MSGID is given return NULL.  */
455  if (msgid1 == NULL)
456    return NULL;
457
458#ifdef _LIBC
459  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
460    /* Bogus.  */
461    return (plural == 0
462	    ? (char *) msgid1
463	    /* Use the Germanic plural rule.  */
464	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
465#endif
466
467  __libc_rwlock_rdlock (_nl_state_lock);
468
469  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
470     CATEGORY is not LC_MESSAGES this might not make much sense but the
471     definition left this undefined.  */
472  if (domainname == NULL)
473    domainname = _nl_current_default_domain;
474
475  /* OS/2 specific: backward compatibility with older libintl versions  */
476#ifdef LC_MESSAGES_COMPAT
477  if (category == LC_MESSAGES_COMPAT)
478    category = LC_MESSAGES;
479#endif
480
481#if defined HAVE_TSEARCH || defined _LIBC
482  msgid_len = strlen (msgid1) + 1;
483
484  /* Try to find the translation among those which we found at
485     some time.  */
486  search = (struct known_translation_t *)
487	   alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
488  memcpy (search->msgid, msgid1, msgid_len);
489  search->domainname = (char *) domainname;
490  search->category = category;
491
492  foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
493  freea (search);
494  if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
495    {
496      /* Now deal with plural.  */
497      if (plural)
498	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
499				(*foundp)->translation_length);
500      else
501	retval = (char *) (*foundp)->translation;
502
503      __libc_rwlock_unlock (_nl_state_lock);
504      return retval;
505    }
506#endif
507
508  /* Preserve the `errno' value.  */
509  saved_errno = errno;
510
511  /* See whether this is a SUID binary or not.  */
512  DETERMINE_SECURE;
513
514  /* First find matching binding.  */
515  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
516    {
517      int compare = strcmp (domainname, binding->domainname);
518      if (compare == 0)
519	/* We found it!  */
520	break;
521      if (compare < 0)
522	{
523	  /* It is not in the list.  */
524	  binding = NULL;
525	  break;
526	}
527    }
528
529  if (binding == NULL)
530    dirname = (char *) INTUSE(_nl_default_dirname);
531  else if (IS_ABSOLUTE_PATH (binding->dirname))
532    dirname = binding->dirname;
533  else
534    {
535      /* We have a relative path.  Make it absolute now.  */
536      size_t dirname_len = strlen (binding->dirname) + 1;
537      size_t path_max;
538      char *ret;
539
540      path_max = (unsigned int) PATH_MAX;
541      path_max += 2;		/* The getcwd docs say to do this.  */
542
543      for (;;)
544	{
545	  dirname = (char *) alloca (path_max + dirname_len);
546	  ADD_BLOCK (block_list, dirname);
547
548	  __set_errno (0);
549	  ret = getcwd (dirname, path_max);
550	  if (ret != NULL || errno != ERANGE)
551	    break;
552
553	  path_max += path_max / 2;
554	  path_max += PATH_INCR;
555	}
556
557      if (ret == NULL)
558	/* We cannot get the current working directory.  Don't signal an
559	   error but simply return the default string.  */
560	goto return_untranslated;
561
562      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
563    }
564
565  /* Now determine the symbolic name of CATEGORY and its value.  */
566  categoryname = category_to_name (category);
567  categoryvalue = guess_category_value (category, categoryname);
568
569  domainname_len = strlen (domainname);
570  xdomainname = (char *) alloca (strlen (categoryname)
571				 + domainname_len + 5);
572  ADD_BLOCK (block_list, xdomainname);
573
574  stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
575		  domainname, domainname_len),
576	  ".mo");
577
578  /* Creating working area.  */
579  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
580  ADD_BLOCK (block_list, single_locale);
581
582
583  /* Search for the given string.  This is a loop because we perhaps
584     got an ordered list of languages to consider for the translation.  */
585  while (1)
586    {
587      /* Make CATEGORYVALUE point to the next element of the list.  */
588      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
589	++categoryvalue;
590      if (categoryvalue[0] == '\0')
591	{
592	  /* The whole contents of CATEGORYVALUE has been searched but
593	     no valid entry has been found.  We solve this situation
594	     by implicitly appending a "C" entry, i.e. no translation
595	     will take place.  */
596	  single_locale[0] = 'C';
597	  single_locale[1] = '\0';
598	}
599      else
600	{
601	  char *cp = single_locale;
602	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
603	    *cp++ = *categoryvalue++;
604	  *cp = '\0';
605
606	  /* When this is a SUID binary we must not allow accessing files
607	     outside the dedicated directories.  */
608	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
609	    /* Ingore this entry.  */
610	    continue;
611	}
612
613      /* If the current locale value is C (or POSIX) we don't load a
614	 domain.  Return the MSGID.  */
615      if (strcmp (single_locale, "C") == 0
616	  || strcmp (single_locale, "POSIX") == 0)
617	break;
618
619      /* Find structure describing the message catalog matching the
620	 DOMAINNAME and CATEGORY.  */
621      domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
622
623      if (domain != NULL)
624	{
625	  retval = _nl_find_msg (domain, binding, msgid1, &retlen);
626
627	  if (retval == NULL)
628	    {
629	      int cnt;
630
631	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
632		{
633		  retval = _nl_find_msg (domain->successor[cnt], binding,
634					 msgid1, &retlen);
635
636		  if (retval != NULL)
637		    {
638		      domain = domain->successor[cnt];
639		      break;
640		    }
641		}
642	    }
643
644	  if (retval != NULL)
645	    {
646	      /* Found the translation of MSGID1 in domain DOMAIN:
647		 starting at RETVAL, RETLEN bytes.  */
648	      FREE_BLOCKS (block_list);
649#if defined HAVE_TSEARCH || defined _LIBC
650	      if (foundp == NULL)
651		{
652		  /* Create a new entry and add it to the search tree.  */
653		  struct known_translation_t *newp;
654
655		  newp = (struct known_translation_t *)
656		    malloc (offsetof (struct known_translation_t, msgid)
657			    + msgid_len + domainname_len + 1);
658		  if (newp != NULL)
659		    {
660		      newp->domainname =
661			mempcpy (newp->msgid, msgid1, msgid_len);
662		      memcpy (newp->domainname, domainname, domainname_len + 1);
663		      newp->category = category;
664		      newp->counter = _nl_msg_cat_cntr;
665		      newp->domain = domain;
666		      newp->translation = retval;
667		      newp->translation_length = retlen;
668
669		      /* Insert the entry in the search tree.  */
670		      foundp = (struct known_translation_t **)
671			tsearch (newp, &root, transcmp);
672		      if (foundp == NULL
673			  || __builtin_expect (*foundp != newp, 0))
674			/* The insert failed.  */
675			free (newp);
676		    }
677		}
678	      else
679		{
680		  /* We can update the existing entry.  */
681		  (*foundp)->counter = _nl_msg_cat_cntr;
682		  (*foundp)->domain = domain;
683		  (*foundp)->translation = retval;
684		  (*foundp)->translation_length = retlen;
685		}
686#endif
687	      __set_errno (saved_errno);
688
689	      /* Now deal with plural.  */
690	      if (plural)
691		retval = plural_lookup (domain, n, retval, retlen);
692
693	      __libc_rwlock_unlock (_nl_state_lock);
694	      return retval;
695	    }
696	}
697    }
698
699 return_untranslated:
700  /* Return the untranslated MSGID.  */
701  FREE_BLOCKS (block_list);
702  __libc_rwlock_unlock (_nl_state_lock);
703#ifndef _LIBC
704  if (!ENABLE_SECURE)
705    {
706      extern void _nl_log_untranslated PARAMS ((const char *logfilename,
707						const char *domainname,
708						const char *msgid1,
709						const char *msgid2,
710						int plural));
711      const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
712
713      if (logfilename != NULL && logfilename[0] != '\0')
714	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
715    }
716#endif
717  __set_errno (saved_errno);
718  return (plural == 0
719	  ? (char *) msgid1
720	  /* Use the Germanic plural rule.  */
721	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
722}
723
724
725char *
726internal_function
727_nl_find_msg (domain_file, domainbinding, msgid, lengthp)
728     struct loaded_l10nfile *domain_file;
729     struct binding *domainbinding;
730     const char *msgid;
731     size_t *lengthp;
732{
733  struct loaded_domain *domain;
734  nls_uint32 nstrings;
735  size_t act;
736  char *result;
737  size_t resultlen;
738
739  if (domain_file->decided == 0)
740    _nl_load_domain (domain_file, domainbinding);
741
742  if (domain_file->data == NULL)
743    return NULL;
744
745  domain = (struct loaded_domain *) domain_file->data;
746
747  nstrings = domain->nstrings;
748
749  /* Locate the MSGID and its translation.  */
750  if (domain->hash_tab != NULL)
751    {
752      /* Use the hashing table.  */
753      nls_uint32 len = strlen (msgid);
754      nls_uint32 hash_val = hash_string (msgid);
755      nls_uint32 idx = hash_val % domain->hash_size;
756      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
757
758      while (1)
759	{
760	  nls_uint32 nstr =
761	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
762
763	  if (nstr == 0)
764	    /* Hash table entry is empty.  */
765	    return NULL;
766
767	  nstr--;
768
769	  /* Compare msgid with the original string at index nstr.
770	     We compare the lengths with >=, not ==, because plural entries
771	     are represented by strings with an embedded NUL.  */
772	  if (nstr < nstrings
773	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
774		&& (strcmp (msgid,
775			    domain->data + W (domain->must_swap,
776					      domain->orig_tab[nstr].offset))
777		    == 0)
778	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
779		&& (strcmp (msgid,
780			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
781		    == 0))
782	    {
783	      act = nstr;
784	      goto found;
785	    }
786
787	  if (idx >= domain->hash_size - incr)
788	    idx -= domain->hash_size - incr;
789	  else
790	    idx += incr;
791	}
792      /* NOTREACHED */
793    }
794  else
795    {
796      /* Try the default method:  binary search in the sorted array of
797	 messages.  */
798      size_t top, bottom;
799
800      bottom = 0;
801      top = nstrings;
802      while (bottom < top)
803	{
804	  int cmp_val;
805
806	  act = (bottom + top) / 2;
807	  cmp_val = strcmp (msgid, (domain->data
808				    + W (domain->must_swap,
809					 domain->orig_tab[act].offset)));
810	  if (cmp_val < 0)
811	    top = act;
812	  else if (cmp_val > 0)
813	    bottom = act + 1;
814	  else
815	    goto found;
816	}
817      /* No translation was found.  */
818      return NULL;
819    }
820
821 found:
822  /* The translation was found at index ACT.  If we have to convert the
823     string to use a different character set, this is the time.  */
824  if (act < nstrings)
825    {
826      result = (char *)
827	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
828      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
829    }
830  else
831    {
832      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
833      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
834    }
835
836#if defined _LIBC || HAVE_ICONV
837  if (domain->codeset_cntr
838      != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
839    {
840      /* The domain's codeset has changed through bind_textdomain_codeset()
841	 since the message catalog was initialized or last accessed.  We
842	 have to reinitialize the converter.  */
843      _nl_free_domain_conv (domain);
844      _nl_init_domain_conv (domain_file, domain, domainbinding);
845    }
846
847  if (
848# ifdef _LIBC
849      domain->conv != (__gconv_t) -1
850# else
851#  if HAVE_ICONV
852      domain->conv != (iconv_t) -1
853#  endif
854# endif
855      )
856    {
857      /* We are supposed to do a conversion.  First allocate an
858	 appropriate table with the same structure as the table
859	 of translations in the file, where we can put the pointers
860	 to the converted strings in.
861	 There is a slight complication with plural entries.  They
862	 are represented by consecutive NUL terminated strings.  We
863	 handle this case by converting RESULTLEN bytes, including
864	 NULs.  */
865
866      if (domain->conv_tab == NULL
867	  && ((domain->conv_tab =
868		 (char **) calloc (nstrings + domain->n_sysdep_strings,
869				   sizeof (char *)))
870	      == NULL))
871	/* Mark that we didn't succeed allocating a table.  */
872	domain->conv_tab = (char **) -1;
873
874      if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
875	/* Nothing we can do, no more memory.  */
876	goto converted;
877
878      if (domain->conv_tab[act] == NULL)
879	{
880	  /* We haven't used this string so far, so it is not
881	     translated yet.  Do this now.  */
882	  /* We use a bit more efficient memory handling.
883	     We allocate always larger blocks which get used over
884	     time.  This is faster than many small allocations.   */
885	  __libc_lock_define_initialized (static, lock)
886# define INITIAL_BLOCK_SIZE	4080
887	  static unsigned char *freemem;
888	  static size_t freemem_size;
889
890	  const unsigned char *inbuf;
891	  unsigned char *outbuf;
892	  int malloc_count;
893# ifndef _LIBC
894	  transmem_block_t *transmem_list = NULL;
895# endif
896
897	  __libc_lock_lock (lock);
898
899	  inbuf = (const unsigned char *) result;
900	  outbuf = freemem + sizeof (size_t);
901
902	  malloc_count = 0;
903	  while (1)
904	    {
905	      transmem_block_t *newmem;
906# ifdef _LIBC
907	      size_t non_reversible;
908	      int res;
909
910	      if (freemem_size < sizeof (size_t))
911		goto resize_freemem;
912
913	      res = __gconv (domain->conv,
914			     &inbuf, inbuf + resultlen,
915			     &outbuf,
916			     outbuf + freemem_size - sizeof (size_t),
917			     &non_reversible);
918
919	      if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
920		break;
921
922	      if (res != __GCONV_FULL_OUTPUT)
923		{
924		  __libc_lock_unlock (lock);
925		  goto converted;
926		}
927
928	      inbuf = result;
929# else
930#  if HAVE_ICONV
931	      const char *inptr = (const char *) inbuf;
932	      size_t inleft = resultlen;
933	      char *outptr = (char *) outbuf;
934	      size_t outleft;
935
936	      if (freemem_size < sizeof (size_t))
937		goto resize_freemem;
938
939	      outleft = freemem_size - sizeof (size_t);
940	      if (iconv (domain->conv,
941			 (ICONV_CONST char **) &inptr, &inleft,
942			 &outptr, &outleft)
943		  != (size_t) (-1))
944		{
945		  outbuf = (unsigned char *) outptr;
946		  break;
947		}
948	      if (errno != E2BIG)
949		{
950		  __libc_lock_unlock (lock);
951		  goto converted;
952		}
953#  endif
954# endif
955
956	    resize_freemem:
957	      /* We must allocate a new buffer or resize the old one.  */
958	      if (malloc_count > 0)
959		{
960		  ++malloc_count;
961		  freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
962		  newmem = (transmem_block_t *) realloc (transmem_list,
963							 freemem_size);
964# ifdef _LIBC
965		  if (newmem != NULL)
966		    transmem_list = transmem_list->next;
967		  else
968		    {
969		      struct transmem_list *old = transmem_list;
970
971		      transmem_list = transmem_list->next;
972		      free (old);
973		    }
974# endif
975		}
976	      else
977		{
978		  malloc_count = 1;
979		  freemem_size = INITIAL_BLOCK_SIZE;
980		  newmem = (transmem_block_t *) malloc (freemem_size);
981		}
982	      if (__builtin_expect (newmem == NULL, 0))
983		{
984		  freemem = NULL;
985		  freemem_size = 0;
986		  __libc_lock_unlock (lock);
987		  goto converted;
988		}
989
990# ifdef _LIBC
991	      /* Add the block to the list of blocks we have to free
992                 at some point.  */
993	      newmem->next = transmem_list;
994	      transmem_list = newmem;
995
996	      freemem = newmem->data;
997	      freemem_size -= offsetof (struct transmem_list, data);
998# else
999	      transmem_list = newmem;
1000	      freemem = newmem;
1001# endif
1002
1003	      outbuf = freemem + sizeof (size_t);
1004	    }
1005
1006	  /* We have now in our buffer a converted string.  Put this
1007	     into the table of conversions.  */
1008	  *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1009	  domain->conv_tab[act] = (char *) freemem;
1010	  /* Shrink freemem, but keep it aligned.  */
1011	  freemem_size -= outbuf - freemem;
1012	  freemem = outbuf;
1013	  freemem += freemem_size & (alignof (size_t) - 1);
1014	  freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1015
1016	  __libc_lock_unlock (lock);
1017	}
1018
1019      /* Now domain->conv_tab[act] contains the translation of all
1020	 the plural variants.  */
1021      result = domain->conv_tab[act] + sizeof (size_t);
1022      resultlen = *(size_t *) domain->conv_tab[act];
1023    }
1024
1025 converted:
1026  /* The result string is converted.  */
1027
1028#endif /* _LIBC || HAVE_ICONV */
1029
1030  *lengthp = resultlen;
1031  return result;
1032}
1033
1034
1035/* Look up a plural variant.  */
1036static char *
1037internal_function
1038plural_lookup (domain, n, translation, translation_len)
1039     struct loaded_l10nfile *domain;
1040     unsigned long int n;
1041     const char *translation;
1042     size_t translation_len;
1043{
1044  struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1045  unsigned long int index;
1046  const char *p;
1047
1048  index = plural_eval (domaindata->plural, n);
1049  if (index >= domaindata->nplurals)
1050    /* This should never happen.  It means the plural expression and the
1051       given maximum value do not match.  */
1052    index = 0;
1053
1054  /* Skip INDEX strings at TRANSLATION.  */
1055  p = translation;
1056  while (index-- > 0)
1057    {
1058#ifdef _LIBC
1059      p = __rawmemchr (p, '\0');
1060#else
1061      p = strchr (p, '\0');
1062#endif
1063      /* And skip over the NUL byte.  */
1064      p++;
1065
1066      if (p >= translation + translation_len)
1067	/* This should never happen.  It means the plural expression
1068	   evaluated to a value larger than the number of variants
1069	   available for MSGID1.  */
1070	return (char *) translation;
1071    }
1072  return (char *) p;
1073}
1074
1075#ifndef _LIBC
1076/* Return string representation of locale CATEGORY.  */
1077static const char *
1078internal_function
1079category_to_name (category)
1080     int category;
1081{
1082  const char *retval;
1083
1084  switch (category)
1085  {
1086#ifdef LC_COLLATE
1087  case LC_COLLATE:
1088    retval = "LC_COLLATE";
1089    break;
1090#endif
1091#ifdef LC_CTYPE
1092  case LC_CTYPE:
1093    retval = "LC_CTYPE";
1094    break;
1095#endif
1096#ifdef LC_MONETARY
1097  case LC_MONETARY:
1098    retval = "LC_MONETARY";
1099    break;
1100#endif
1101#ifdef LC_NUMERIC
1102  case LC_NUMERIC:
1103    retval = "LC_NUMERIC";
1104    break;
1105#endif
1106#ifdef LC_TIME
1107  case LC_TIME:
1108    retval = "LC_TIME";
1109    break;
1110#endif
1111#ifdef LC_MESSAGES
1112  case LC_MESSAGES:
1113    retval = "LC_MESSAGES";
1114    break;
1115#endif
1116#ifdef LC_RESPONSE
1117  case LC_RESPONSE:
1118    retval = "LC_RESPONSE";
1119    break;
1120#endif
1121#ifdef LC_ALL
1122  case LC_ALL:
1123    /* This might not make sense but is perhaps better than any other
1124       value.  */
1125    retval = "LC_ALL";
1126    break;
1127#endif
1128  default:
1129    /* If you have a better idea for a default value let me know.  */
1130    retval = "LC_XXX";
1131  }
1132
1133  return retval;
1134}
1135#endif
1136
1137/* Guess value of current locale from value of the environment variables.  */
1138static const char *
1139internal_function
1140guess_category_value (category, categoryname)
1141     int category;
1142     const char *categoryname;
1143{
1144  const char *language;
1145  const char *retval;
1146
1147  /* The highest priority value is the `LANGUAGE' environment
1148     variable.  But we don't use the value if the currently selected
1149     locale is the C locale.  This is a GNU extension.  */
1150  language = getenv ("LANGUAGE");
1151  if (language != NULL && language[0] == '\0')
1152    language = NULL;
1153
1154  /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1155     `LC_xxx', and `LANG'.  On some systems this can be done by the
1156     `setlocale' function itself.  */
1157#ifdef _LIBC
1158  retval = __current_locale_name (category);
1159#else
1160  retval = _nl_locale_name (category, categoryname);
1161#endif
1162
1163  /* Ignore LANGUAGE if the locale is set to "C" because
1164     1. "C" locale usually uses the ASCII encoding, and most international
1165	messages use non-ASCII characters. These characters get displayed
1166	as question marks (if using glibc's iconv()) or as invalid 8-bit
1167	characters (because other iconv()s refuse to convert most non-ASCII
1168	characters to ASCII). In any case, the output is ugly.
1169     2. The precise output of some programs in the "C" locale is specified
1170	by POSIX and should not depend on environment variables like
1171	"LANGUAGE".  We allow such programs to use gettext().  */
1172  return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1173}
1174
1175/* @@ begin of epilog @@ */
1176
1177/* We don't want libintl.a to depend on any other library.  So we
1178   avoid the non-standard function stpcpy.  In GNU C Library this
1179   function is available, though.  Also allow the symbol HAVE_STPCPY
1180   to be defined.  */
1181#if !_LIBC && !HAVE_STPCPY
1182static char *
1183stpcpy (dest, src)
1184     char *dest;
1185     const char *src;
1186{
1187  while ((*dest++ = *src++) != '\0')
1188    /* Do nothing. */ ;
1189  return dest - 1;
1190}
1191#endif
1192
1193#if !_LIBC && !HAVE_MEMPCPY
1194static void *
1195mempcpy (dest, src, n)
1196     void *dest;
1197     const void *src;
1198     size_t n;
1199{
1200  return (void *) ((char *) memcpy (dest, src, n) + n);
1201}
1202#endif
1203
1204
1205#ifdef _LIBC
1206/* If we want to free all resources we have to do some work at
1207   program's end.  */
1208libc_freeres_fn (free_mem)
1209{
1210  void *old;
1211
1212  while (_nl_domain_bindings != NULL)
1213    {
1214      struct binding *oldp = _nl_domain_bindings;
1215      _nl_domain_bindings = _nl_domain_bindings->next;
1216      if (oldp->dirname != INTUSE(_nl_default_dirname))
1217	/* Yes, this is a pointer comparison.  */
1218	free (oldp->dirname);
1219      free (oldp->codeset);
1220      free (oldp);
1221    }
1222
1223  if (_nl_current_default_domain != _nl_default_default_domain)
1224    /* Yes, again a pointer comparison.  */
1225    free ((char *) _nl_current_default_domain);
1226
1227  /* Remove the search tree with the known translations.  */
1228  __tdestroy (root, free);
1229  root = NULL;
1230
1231  while (transmem_list != NULL)
1232    {
1233      old = transmem_list;
1234      transmem_list = transmem_list->next;
1235      free (old);
1236    }
1237}
1238#endif
1239