1/* Implementation of the internal dcigettext function.
2   Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
3
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Library General Public License as published
6   by the Free Software Foundation; either version 2, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Library General Public License for more details.
13
14   You should have received a copy of the GNU Library General Public
15   License along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17   USA.  */
18
19/* Tell glibc's <string.h> to provide a prototype for mempcpy().
20   This must come before <config.h> because <config.h> may include
21   <features.h>, and once <features.h> has been included, it's too late.  */
22#ifndef _GNU_SOURCE
23# define _GNU_SOURCE	1
24#endif
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <sys/types.h>
31
32#ifdef __GNUC__
33# define alloca __builtin_alloca
34# define HAVE_ALLOCA 1
35#else
36# ifdef _MSC_VER
37#  include <malloc.h>
38#  define alloca _alloca
39# else
40#  if defined HAVE_ALLOCA_H || defined _LIBC
41#   include <alloca.h>
42#  else
43#   ifdef _AIX
44 #pragma alloca
45#   else
46#    ifndef alloca
47char *alloca ();
48#    endif
49#   endif
50#  endif
51# endif
52#endif
53
54#include <errno.h>
55#ifndef errno
56extern int errno;
57#endif
58#ifndef __set_errno
59# define __set_errno(val) errno = (val)
60#endif
61
62#include <stddef.h>
63#include <stdlib.h>
64#include <string.h>
65
66#if defined HAVE_UNISTD_H || defined _LIBC
67# include <unistd.h>
68#endif
69
70#include <locale.h>
71
72#ifdef _LIBC
73  /* Guess whether integer division by zero raises signal SIGFPE.
74     Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
75# if defined __alpha__ || defined __arm__ || defined __i386__ \
76     || defined __m68k__ || defined __s390__
77#  define INTDIV0_RAISES_SIGFPE 1
78# else
79#  define INTDIV0_RAISES_SIGFPE 0
80# endif
81#endif
82#if !INTDIV0_RAISES_SIGFPE
83# include <signal.h>
84#endif
85
86#if defined HAVE_SYS_PARAM_H || defined _LIBC
87# include <sys/param.h>
88#endif
89
90#include "gettextP.h"
91#include "plural-exp.h"
92#ifdef _LIBC
93# include <libintl.h>
94#else
95# include "libgnuintl.h"
96#endif
97#include "hash-string.h"
98
99/* Thread safetyness.  */
100#ifdef _LIBC
101# include <bits/libc-lock.h>
102#else
103/* Provide dummy implementation if this is outside glibc.  */
104# define __libc_lock_define_initialized(CLASS, NAME)
105# define __libc_lock_lock(NAME)
106# define __libc_lock_unlock(NAME)
107# define __libc_rwlock_define_initialized(CLASS, NAME)
108# define __libc_rwlock_rdlock(NAME)
109# define __libc_rwlock_unlock(NAME)
110#endif
111
112/* Alignment of types.  */
113#if defined __GNUC__ && __GNUC__ >= 2
114# define alignof(TYPE) __alignof__ (TYPE)
115#else
116# define alignof(TYPE) \
117    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
118#endif
119
120/* The internal variables in the standalone libintl.a must have different
121   names than the internal variables in GNU libc, otherwise programs
122   using libintl.a cannot be linked statically.  */
123#if !defined _LIBC
124# define _nl_default_default_domain libintl_nl_default_default_domain
125# define _nl_current_default_domain libintl_nl_current_default_domain
126# define _nl_default_dirname libintl_nl_default_dirname
127# define _nl_domain_bindings libintl_nl_domain_bindings
128#endif
129
130/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
131#ifndef offsetof
132# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
133#endif
134
135/* @@ end of prolog @@ */
136
137#ifdef _LIBC
138/* Rename the non ANSI C functions.  This is required by the standard
139   because some ANSI C functions will require linking with this object
140   file and the name space must not be polluted.  */
141# define getcwd __getcwd
142# ifndef stpcpy
143#  define stpcpy __stpcpy
144# endif
145# define tfind __tfind
146#else
147# if !defined HAVE_GETCWD
148char *getwd ();
149#  define getcwd(buf, max) getwd (buf)
150# else
151#  if VMS
152#   define getcwd(buf, max) (getcwd) (buf, max, 0)
153#  else
154char *getcwd ();
155#  endif
156# endif
157# ifndef HAVE_STPCPY
158#define stpcpy(dest, src) my_stpcpy(dest, src)
159static char *stpcpy (char *dest, const char *src);
160# endif
161# ifndef HAVE_MEMPCPY
162static void *mempcpy (void *dest, const void *src, size_t n);
163# endif
164#endif
165
166/* Amount to increase buffer size by in each try.  */
167#define PATH_INCR 32
168
169/* The following is from pathmax.h.  */
170/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
171   PATH_MAX but might cause redefinition warnings when sys/param.h is
172   later included (as on MORE/BSD 4.3).  */
173#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
174# include <limits.h>
175#endif
176
177#ifndef _POSIX_PATH_MAX
178# define _POSIX_PATH_MAX 255
179#endif
180
181#if !defined PATH_MAX && defined _PC_PATH_MAX
182# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
183#endif
184
185/* Don't include sys/param.h if it already has been.  */
186#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
187# include <sys/param.h>
188#endif
189
190#if !defined PATH_MAX && defined MAXPATHLEN
191# define PATH_MAX MAXPATHLEN
192#endif
193
194#ifndef PATH_MAX
195# define PATH_MAX _POSIX_PATH_MAX
196#endif
197
198/* Pathname support.
199   ISSLASH(C)           tests whether C is a directory separator character.
200   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
201                        it may be concatenated to a directory pathname.
202   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
203 */
204#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
205  /* Win32, OS/2, DOS */
206# define ISSLASH(C) ((C) == '/' || (C) == '\\')
207# define HAS_DEVICE(P) \
208    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
209     && (P)[1] == ':')
210# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
211# define IS_PATH_WITH_DIR(P) \
212    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
213#else
214  /* Unix */
215# define ISSLASH(C) ((C) == '/')
216# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
217# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
218#endif
219
220/* This is the type used for the search tree where known translations
221   are stored.  */
222struct known_translation_t
223{
224  /* Domain in which to search.  */
225  char *domainname;
226
227  /* The category.  */
228  int category;
229
230  /* State of the catalog counter at the point the string was found.  */
231  int counter;
232
233  /* Catalog where the string was found.  */
234  struct loaded_l10nfile *domain;
235
236  /* And finally the translation.  */
237  const char *translation;
238  size_t translation_length;
239
240  /* Pointer to the string in question.  */
241  char msgid[ZERO];
242};
243
244/* Root of the search tree with known translations.  We can use this
245   only if the system provides the `tsearch' function family.  */
246#if defined HAVE_TSEARCH || defined _LIBC
247# include <search.h>
248
249static void *root;
250
251# ifdef _LIBC
252#  define tsearch __tsearch
253# endif
254
255/* Function to compare two entries in the table of known translations.  */
256static int
257transcmp (const void *p1, const void *p2)
258{
259  const struct known_translation_t *s1;
260  const struct known_translation_t *s2;
261  int result;
262
263  s1 = (const struct known_translation_t *) p1;
264  s2 = (const struct known_translation_t *) p2;
265
266  result = strcmp (s1->msgid, s2->msgid);
267  if (result == 0)
268    {
269      result = strcmp (s1->domainname, s2->domainname);
270      if (result == 0)
271	/* We compare the category last (though this is the cheapest
272	   operation) since it is hopefully always the same (namely
273	   LC_MESSAGES).  */
274	result = s1->category - s2->category;
275    }
276
277  return result;
278}
279#endif
280
281#ifndef INTVARDEF
282# define INTVARDEF(name)
283#endif
284#ifndef INTUSE
285# define INTUSE(name) name
286#endif
287
288/* Name of the default domain used for gettext(3) prior any call to
289   textdomain(3).  The default value for this is "messages".  */
290const char _nl_default_default_domain[] attribute_hidden = "messages";
291
292/* Value used as the default domain for gettext(3).  */
293const char *_nl_current_default_domain attribute_hidden
294     = _nl_default_default_domain;
295
296/* Contains the default location of the message catalogs.  */
297#if defined __EMX__
298extern const char _nl_default_dirname[];
299#else
300const char _nl_default_dirname[] = LOCALEDIR;
301INTVARDEF (_nl_default_dirname)
302#endif
303
304/* List with bindings of specific domains created by bindtextdomain()
305   calls.  */
306struct binding *_nl_domain_bindings;
307
308/* Prototypes for local functions.  */
309static char *plural_lookup (struct loaded_l10nfile *domain,
310			    unsigned long int n,
311			    const char *translation, size_t translation_len)
312     internal_function;
313static const char *guess_category_value (int category,
314					 const char *categoryname)
315     internal_function;
316#ifdef _LIBC
317# include "../locale/localeinfo.h"
318# define category_to_name(category)	_nl_category_names[category]
319#else
320static const char *category_to_name (int category) internal_function;
321#endif
322
323
324/* For those loosing systems which don't have `alloca' we have to add
325   some additional code emulating it.  */
326#ifdef HAVE_ALLOCA
327/* Nothing has to be done.  */
328# define freea(p) /* nothing */
329# define ADD_BLOCK(list, address) /* nothing */
330# define FREE_BLOCKS(list) /* nothing */
331#else
332struct block_list
333{
334  void *address;
335  struct block_list *next;
336};
337# define ADD_BLOCK(list, addr)						      \
338  do {									      \
339    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
340    /* If we cannot get a free block we cannot add the new element to	      \
341       the list.  */							      \
342    if (newp != NULL) {							      \
343      newp->address = (addr);						      \
344      newp->next = (list);						      \
345      (list) = newp;							      \
346    }									      \
347  } while (0)
348# define FREE_BLOCKS(list)						      \
349  do {									      \
350    while (list != NULL) {						      \
351      struct block_list *old = list;					      \
352      list = list->next;						      \
353      free (old->address);						      \
354      free (old);							      \
355    }									      \
356  } while (0)
357# undef alloca
358# define alloca(size) (malloc (size))
359# define freea(p) free (p)
360#endif	/* have alloca */
361
362
363#ifdef _LIBC
364/* List of blocks allocated for translations.  */
365typedef struct transmem_list
366{
367  struct transmem_list *next;
368  char data[ZERO];
369} transmem_block_t;
370static struct transmem_list *transmem_list;
371#else
372typedef unsigned char transmem_block_t;
373#endif
374
375
376/* Names for the libintl functions are a problem.  They must not clash
377   with existing names and they should follow ANSI C.  But this source
378   code is also used in GNU C Library where the names have a __
379   prefix.  So we have to make a difference here.  */
380#ifdef _LIBC
381# define DCIGETTEXT __dcigettext
382#else
383# define DCIGETTEXT libintl_dcigettext
384#endif
385
386/* Lock variable to protect the global data in the gettext implementation.  */
387#ifdef _LIBC
388__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
389#endif
390
391/* Checking whether the binaries runs SUID must be done and glibc provides
392   easier methods therefore we make a difference here.  */
393#ifdef _LIBC
394# define ENABLE_SECURE __libc_enable_secure
395# define DETERMINE_SECURE
396#else
397# ifndef HAVE_GETUID
398#  define getuid() 0
399# endif
400# ifndef HAVE_GETGID
401#  define getgid() 0
402# endif
403# ifndef HAVE_GETEUID
404#  define geteuid() getuid()
405# endif
406# ifndef HAVE_GETEGID
407#  define getegid() getgid()
408# endif
409static int enable_secure;
410# define ENABLE_SECURE (enable_secure == 1)
411# define DETERMINE_SECURE \
412  if (enable_secure == 0)						      \
413    {									      \
414      if (getuid () != geteuid () || getgid () != getegid ())		      \
415	enable_secure = 1;						      \
416      else								      \
417	enable_secure = -1;						      \
418    }
419#endif
420
421/* Get the function to evaluate the plural expression.  */
422#include "eval-plural.h"
423
424/* Look up MSGID in the DOMAINNAME message catalog for the current
425   CATEGORY locale and, if PLURAL is nonzero, search over string
426   depending on the plural form determined by N.  */
427char *
428DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
429	    int plural, unsigned long int n, int category)
430{
431#ifndef HAVE_ALLOCA
432  struct block_list *block_list = NULL;
433#endif
434  struct loaded_l10nfile *domain;
435  struct binding *binding;
436  const char *categoryname;
437  const char *categoryvalue;
438  char *dirname, *xdomainname;
439  char *single_locale;
440  char *retval;
441  size_t retlen;
442  int saved_errno;
443#if defined HAVE_TSEARCH || defined _LIBC
444  struct known_translation_t *search;
445  struct known_translation_t **foundp = NULL;
446  size_t msgid_len;
447#endif
448  size_t domainname_len;
449
450  /* If no real MSGID is given return NULL.  */
451  if (msgid1 == NULL)
452    return NULL;
453
454#ifdef _LIBC
455  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
456    /* Bogus.  */
457    return (plural == 0
458	    ? (char *) msgid1
459	    /* Use the Germanic plural rule.  */
460	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
461#endif
462
463  __libc_rwlock_rdlock (_nl_state_lock);
464
465  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
466     CATEGORY is not LC_MESSAGES this might not make much sense but the
467     definition left this undefined.  */
468  if (domainname == NULL)
469    domainname = _nl_current_default_domain;
470
471  /* OS/2 specific: backward compatibility with older libintl versions  */
472#ifdef LC_MESSAGES_COMPAT
473  if (category == LC_MESSAGES_COMPAT)
474    category = LC_MESSAGES;
475#endif
476
477#if defined HAVE_TSEARCH || defined _LIBC
478  msgid_len = strlen (msgid1) + 1;
479
480  /* Try to find the translation among those which we found at
481     some time.  */
482  search = (struct known_translation_t *)
483	   alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
484  memcpy (search->msgid, msgid1, msgid_len);
485  search->domainname = (char *) domainname;
486  search->category = category;
487
488  foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
489  freea (search);
490  if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
491    {
492      /* Now deal with plural.  */
493      if (plural)
494	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
495				(*foundp)->translation_length);
496      else
497	retval = (char *) (*foundp)->translation;
498
499      __libc_rwlock_unlock (_nl_state_lock);
500      return retval;
501    }
502#endif
503
504  /* Preserve the `errno' value.  */
505  saved_errno = errno;
506
507  /* See whether this is a SUID binary or not.  */
508  DETERMINE_SECURE;
509
510  /* First find matching binding.  */
511  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
512    {
513      int compare = strcmp (domainname, binding->domainname);
514      if (compare == 0)
515	/* We found it!  */
516	break;
517      if (compare < 0)
518	{
519	  /* It is not in the list.  */
520	  binding = NULL;
521	  break;
522	}
523    }
524
525  if (binding == NULL)
526    dirname = (char *) INTUSE(_nl_default_dirname);
527  else if (IS_ABSOLUTE_PATH (binding->dirname))
528    dirname = binding->dirname;
529  else
530    {
531      /* We have a relative path.  Make it absolute now.  */
532      size_t dirname_len = strlen (binding->dirname) + 1;
533      size_t path_max;
534      char *ret;
535
536      path_max = (unsigned int) PATH_MAX;
537      path_max += 2;		/* The getcwd docs say to do this.  */
538
539      for (;;)
540	{
541	  dirname = (char *) alloca (path_max + dirname_len);
542	  ADD_BLOCK (block_list, dirname);
543
544	  __set_errno (0);
545	  ret = getcwd (dirname, path_max);
546	  if (ret != NULL || errno != ERANGE)
547	    break;
548
549	  path_max += path_max / 2;
550	  path_max += PATH_INCR;
551	}
552
553      if (ret == NULL)
554	/* We cannot get the current working directory.  Don't signal an
555	   error but simply return the default string.  */
556	goto return_untranslated;
557
558      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
559    }
560
561  /* Now determine the symbolic name of CATEGORY and its value.  */
562  categoryname = category_to_name (category);
563  categoryvalue = guess_category_value (category, categoryname);
564
565  domainname_len = strlen (domainname);
566  xdomainname = (char *) alloca (strlen (categoryname)
567				 + domainname_len + 5);
568  ADD_BLOCK (block_list, xdomainname);
569
570  stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
571		  domainname, domainname_len),
572	  ".mo");
573
574  /* Creating working area.  */
575  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
576  ADD_BLOCK (block_list, single_locale);
577
578
579  /* Search for the given string.  This is a loop because we perhaps
580     got an ordered list of languages to consider for the translation.  */
581  while (1)
582    {
583      /* Make CATEGORYVALUE point to the next element of the list.  */
584      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
585	++categoryvalue;
586      if (categoryvalue[0] == '\0')
587	{
588	  /* The whole contents of CATEGORYVALUE has been searched but
589	     no valid entry has been found.  We solve this situation
590	     by implicitly appending a "C" entry, i.e. no translation
591	     will take place.  */
592	  single_locale[0] = 'C';
593	  single_locale[1] = '\0';
594	}
595      else
596	{
597	  char *cp = single_locale;
598	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
599	    *cp++ = *categoryvalue++;
600	  *cp = '\0';
601
602	  /* When this is a SUID binary we must not allow accessing files
603	     outside the dedicated directories.  */
604	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
605	    /* Ingore this entry.  */
606	    continue;
607	}
608
609      /* If the current locale value is C (or POSIX) we don't load a
610	 domain.  Return the MSGID.  */
611      if (strcmp (single_locale, "C") == 0
612	  || strcmp (single_locale, "POSIX") == 0)
613	break;
614
615      /* Find structure describing the message catalog matching the
616	 DOMAINNAME and CATEGORY.  */
617      domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
618
619      if (domain != NULL)
620	{
621	  retval = _nl_find_msg (domain, binding, msgid1, &retlen);
622
623	  if (retval == NULL)
624	    {
625	      int cnt;
626
627	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
628		{
629		  retval = _nl_find_msg (domain->successor[cnt], binding,
630					 msgid1, &retlen);
631
632		  if (retval != NULL)
633		    {
634		      domain = domain->successor[cnt];
635		      break;
636		    }
637		}
638	    }
639
640	  if (retval != NULL)
641	    {
642	      /* Found the translation of MSGID1 in domain DOMAIN:
643		 starting at RETVAL, RETLEN bytes.  */
644	      FREE_BLOCKS (block_list);
645#if defined HAVE_TSEARCH || defined _LIBC
646	      if (foundp == NULL)
647		{
648		  /* Create a new entry and add it to the search tree.  */
649		  struct known_translation_t *newp;
650
651		  newp = (struct known_translation_t *)
652		    malloc (offsetof (struct known_translation_t, msgid)
653			    + msgid_len + domainname_len + 1);
654		  if (newp != NULL)
655		    {
656		      newp->domainname =
657			mempcpy (newp->msgid, msgid1, msgid_len);
658		      memcpy (newp->domainname, domainname, domainname_len + 1);
659		      newp->category = category;
660		      newp->counter = _nl_msg_cat_cntr;
661		      newp->domain = domain;
662		      newp->translation = retval;
663		      newp->translation_length = retlen;
664
665		      /* Insert the entry in the search tree.  */
666		      foundp = (struct known_translation_t **)
667			tsearch (newp, &root, transcmp);
668		      if (foundp == NULL
669			  || __builtin_expect (*foundp != newp, 0))
670			/* The insert failed.  */
671			free (newp);
672		    }
673		}
674	      else
675		{
676		  /* We can update the existing entry.  */
677		  (*foundp)->counter = _nl_msg_cat_cntr;
678		  (*foundp)->domain = domain;
679		  (*foundp)->translation = retval;
680		  (*foundp)->translation_length = retlen;
681		}
682#endif
683	      __set_errno (saved_errno);
684
685	      /* Now deal with plural.  */
686	      if (plural)
687		retval = plural_lookup (domain, n, retval, retlen);
688
689	      __libc_rwlock_unlock (_nl_state_lock);
690	      return retval;
691	    }
692	}
693    }
694
695 return_untranslated:
696  /* Return the untranslated MSGID.  */
697  FREE_BLOCKS (block_list);
698  __libc_rwlock_unlock (_nl_state_lock);
699#if 0				/* Doesn't work with diet libc -- TYT */
700#ifndef _LIBC
701  if (!ENABLE_SECURE)
702    {
703      extern void _nl_log_untranslated (const char *logfilename,
704					const char *domainname,
705					const char *msgid1, const char *msgid2,
706					int plural);
707      const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
708
709      if (logfilename != NULL && logfilename[0] != '\0')
710	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
711    }
712#endif
713#endif
714  __set_errno (saved_errno);
715  return (plural == 0
716	  ? (char *) msgid1
717	  /* Use the Germanic plural rule.  */
718	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
719}
720
721
722char *
723internal_function
724_nl_find_msg (struct loaded_l10nfile *domain_file,
725	      struct binding *domainbinding, const char *msgid,
726	      size_t *lengthp)
727{
728  struct loaded_domain *domain;
729  nls_uint32 nstrings;
730  size_t act;
731  char *result;
732  size_t resultlen;
733
734  if (domain_file->decided == 0)
735    _nl_load_domain (domain_file, domainbinding);
736
737  if (domain_file->data == NULL)
738    return NULL;
739
740  domain = (struct loaded_domain *) domain_file->data;
741
742  nstrings = domain->nstrings;
743
744  /* Locate the MSGID and its translation.  */
745  if (domain->hash_tab != NULL)
746    {
747      /* Use the hashing table.  */
748      nls_uint32 len = strlen (msgid);
749      nls_uint32 hash_val = hash_string (msgid);
750      nls_uint32 idx = hash_val % domain->hash_size;
751      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
752
753      while (1)
754	{
755	  nls_uint32 nstr =
756	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
757
758	  if (nstr == 0)
759	    /* Hash table entry is empty.  */
760	    return NULL;
761
762	  nstr--;
763
764	  /* Compare msgid with the original string at index nstr.
765	     We compare the lengths with >=, not ==, because plural entries
766	     are represented by strings with an embedded NUL.  */
767	  if (nstr < nstrings
768	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
769		&& (strcmp (msgid,
770			    domain->data + W (domain->must_swap,
771					      domain->orig_tab[nstr].offset))
772		    == 0)
773	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
774		&& (strcmp (msgid,
775			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
776		    == 0))
777	    {
778	      act = nstr;
779	      goto found;
780	    }
781
782	  if (idx >= domain->hash_size - incr)
783	    idx -= domain->hash_size - incr;
784	  else
785	    idx += incr;
786	}
787      /* NOTREACHED */
788    }
789  else
790    {
791      /* Try the default method:  binary search in the sorted array of
792	 messages.  */
793      size_t top, bottom;
794
795      bottom = 0;
796      top = nstrings;
797      while (bottom < top)
798	{
799	  int cmp_val;
800
801	  act = (bottom + top) / 2;
802	  cmp_val = strcmp (msgid, (domain->data
803				    + W (domain->must_swap,
804					 domain->orig_tab[act].offset)));
805	  if (cmp_val < 0)
806	    top = act;
807	  else if (cmp_val > 0)
808	    bottom = act + 1;
809	  else
810	    goto found;
811	}
812      /* No translation was found.  */
813      return NULL;
814    }
815
816 found:
817  /* The translation was found at index ACT.  If we have to convert the
818     string to use a different character set, this is the time.  */
819  if (act < nstrings)
820    {
821      result = (char *)
822	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
823      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
824    }
825  else
826    {
827      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
828      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
829    }
830
831#if defined _LIBC || HAVE_ICONV
832  if (domain->codeset_cntr
833      != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
834    {
835      /* The domain's codeset has changed through bind_textdomain_codeset()
836	 since the message catalog was initialized or last accessed.  We
837	 have to reinitialize the converter.  */
838      _nl_free_domain_conv (domain);
839      _nl_init_domain_conv (domain_file, domain, domainbinding);
840    }
841
842  if (
843# ifdef _LIBC
844      domain->conv != (__gconv_t) -1
845# else
846#  if HAVE_ICONV
847      domain->conv != (iconv_t) -1
848#  endif
849# endif
850      )
851    {
852      /* We are supposed to do a conversion.  First allocate an
853	 appropriate table with the same structure as the table
854	 of translations in the file, where we can put the pointers
855	 to the converted strings in.
856	 There is a slight complication with plural entries.  They
857	 are represented by consecutive NUL terminated strings.  We
858	 handle this case by converting RESULTLEN bytes, including
859	 NULs.  */
860
861      if (domain->conv_tab == NULL
862	  && ((domain->conv_tab =
863		 (char **) calloc (nstrings + domain->n_sysdep_strings,
864				   sizeof (char *)))
865	      == NULL))
866	/* Mark that we didn't succeed allocating a table.  */
867	domain->conv_tab = (char **) -1;
868
869      if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
870	/* Nothing we can do, no more memory.  */
871	goto converted;
872
873      if (domain->conv_tab[act] == NULL)
874	{
875	  /* We haven't used this string so far, so it is not
876	     translated yet.  Do this now.  */
877	  /* We use a bit more efficient memory handling.
878	     We allocate always larger blocks which get used over
879	     time.  This is faster than many small allocations.   */
880	  __libc_lock_define_initialized (static, lock)
881# define INITIAL_BLOCK_SIZE	4080
882	  static unsigned char *freemem;
883	  static size_t freemem_size;
884
885	  const unsigned char *inbuf;
886	  unsigned char *outbuf;
887	  int malloc_count;
888# ifndef _LIBC
889	  transmem_block_t *transmem_list = NULL;
890# endif
891
892	  __libc_lock_lock (lock);
893
894	  inbuf = (const unsigned char *) result;
895	  outbuf = freemem + sizeof (size_t);
896
897	  malloc_count = 0;
898	  while (1)
899	    {
900	      transmem_block_t *newmem;
901# ifdef _LIBC
902	      size_t non_reversible;
903	      int res;
904
905	      if (freemem_size < sizeof (size_t))
906		goto resize_freemem;
907
908	      res = __gconv (domain->conv,
909			     &inbuf, inbuf + resultlen,
910			     &outbuf,
911			     outbuf + freemem_size - sizeof (size_t),
912			     &non_reversible);
913
914	      if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
915		break;
916
917	      if (res != __GCONV_FULL_OUTPUT)
918		{
919		  __libc_lock_unlock (lock);
920		  goto converted;
921		}
922
923	      inbuf = result;
924# else
925#  if HAVE_ICONV
926	      const char *inptr = (const char *) inbuf;
927	      size_t inleft = resultlen;
928	      char *outptr = (char *) outbuf;
929	      size_t outleft;
930
931	      if (freemem_size < sizeof (size_t))
932		goto resize_freemem;
933
934	      outleft = freemem_size - sizeof (size_t);
935	      if (iconv (domain->conv,
936			 (ICONV_CONST char **) &inptr, &inleft,
937			 &outptr, &outleft)
938		  != (size_t) (-1))
939		{
940		  outbuf = (unsigned char *) outptr;
941		  break;
942		}
943	      if (errno != E2BIG)
944		{
945		  __libc_lock_unlock (lock);
946		  goto converted;
947		}
948#  endif
949# endif
950
951	    resize_freemem:
952	      /* We must allocate a new buffer or resize the old one.  */
953	      if (malloc_count > 0)
954		{
955		  ++malloc_count;
956		  freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
957		  newmem = (transmem_block_t *) realloc (transmem_list,
958							 freemem_size);
959# ifdef _LIBC
960		  if (newmem != NULL)
961		    transmem_list = transmem_list->next;
962		  else
963		    {
964		      struct transmem_list *old = transmem_list;
965
966		      transmem_list = transmem_list->next;
967		      free (old);
968		    }
969# endif
970		}
971	      else
972		{
973		  malloc_count = 1;
974		  freemem_size = INITIAL_BLOCK_SIZE;
975		  newmem = (transmem_block_t *) malloc (freemem_size);
976		}
977	      if (__builtin_expect (newmem == NULL, 0))
978		{
979		  freemem = NULL;
980		  freemem_size = 0;
981		  __libc_lock_unlock (lock);
982		  goto converted;
983		}
984
985# ifdef _LIBC
986	      /* Add the block to the list of blocks we have to free
987                 at some point.  */
988	      newmem->next = transmem_list;
989	      transmem_list = newmem;
990
991	      freemem = newmem->data;
992	      freemem_size -= offsetof (struct transmem_list, data);
993# else
994	      transmem_list = newmem;
995	      freemem = newmem;
996# endif
997
998	      outbuf = freemem + sizeof (size_t);
999	    }
1000
1001	  /* We have now in our buffer a converted string.  Put this
1002	     into the table of conversions.  */
1003	  *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1004	  domain->conv_tab[act] = (char *) freemem;
1005	  /* Shrink freemem, but keep it aligned.  */
1006	  freemem_size -= outbuf - freemem;
1007	  freemem = outbuf;
1008	  freemem += freemem_size & (alignof (size_t) - 1);
1009	  freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1010
1011	  __libc_lock_unlock (lock);
1012	}
1013
1014      /* Now domain->conv_tab[act] contains the translation of all
1015	 the plural variants.  */
1016      result = domain->conv_tab[act] + sizeof (size_t);
1017      resultlen = *(size_t *) domain->conv_tab[act];
1018    }
1019
1020 converted:
1021  /* The result string is converted.  */
1022
1023#endif /* _LIBC || HAVE_ICONV */
1024
1025  *lengthp = resultlen;
1026  return result;
1027}
1028
1029
1030/* Look up a plural variant.  */
1031static char *
1032internal_function
1033plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
1034	       const char *translation, size_t translation_len)
1035{
1036  struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1037  unsigned long int index;
1038  const char *p;
1039
1040  index = plural_eval (domaindata->plural, n);
1041  if (index >= domaindata->nplurals)
1042    /* This should never happen.  It means the plural expression and the
1043       given maximum value do not match.  */
1044    index = 0;
1045
1046  /* Skip INDEX strings at TRANSLATION.  */
1047  p = translation;
1048  while (index-- > 0)
1049    {
1050#ifdef _LIBC
1051      p = __rawmemchr (p, '\0');
1052#else
1053      p = strchr (p, '\0');
1054#endif
1055      /* And skip over the NUL byte.  */
1056      p++;
1057
1058      if (p >= translation + translation_len)
1059	/* This should never happen.  It means the plural expression
1060	   evaluated to a value larger than the number of variants
1061	   available for MSGID1.  */
1062	return (char *) translation;
1063    }
1064  return (char *) p;
1065}
1066
1067#ifndef _LIBC
1068/* Return string representation of locale CATEGORY.  */
1069static const char *
1070internal_function
1071category_to_name (int category)
1072{
1073  const char *retval;
1074
1075  switch (category)
1076  {
1077#ifdef LC_COLLATE
1078  case LC_COLLATE:
1079    retval = "LC_COLLATE";
1080    break;
1081#endif
1082#ifdef LC_CTYPE
1083  case LC_CTYPE:
1084    retval = "LC_CTYPE";
1085    break;
1086#endif
1087#ifdef LC_MONETARY
1088  case LC_MONETARY:
1089    retval = "LC_MONETARY";
1090    break;
1091#endif
1092#ifdef LC_NUMERIC
1093  case LC_NUMERIC:
1094    retval = "LC_NUMERIC";
1095    break;
1096#endif
1097#ifdef LC_TIME
1098  case LC_TIME:
1099    retval = "LC_TIME";
1100    break;
1101#endif
1102#ifdef LC_MESSAGES
1103  case LC_MESSAGES:
1104    retval = "LC_MESSAGES";
1105    break;
1106#endif
1107#ifdef LC_RESPONSE
1108  case LC_RESPONSE:
1109    retval = "LC_RESPONSE";
1110    break;
1111#endif
1112#ifdef LC_ALL
1113  case LC_ALL:
1114    /* This might not make sense but is perhaps better than any other
1115       value.  */
1116    retval = "LC_ALL";
1117    break;
1118#endif
1119  default:
1120    /* If you have a better idea for a default value let me know.  */
1121    retval = "LC_XXX";
1122  }
1123
1124  return retval;
1125}
1126#endif
1127
1128/* Guess value of current locale from value of the environment variables.  */
1129static const char *
1130internal_function
1131guess_category_value (int category, const char *categoryname)
1132{
1133  const char *language;
1134  const char *retval;
1135
1136  /* The highest priority value is the `LANGUAGE' environment
1137     variable.  But we don't use the value if the currently selected
1138     locale is the C locale.  This is a GNU extension.  */
1139  language = getenv ("LANGUAGE");
1140  if (language != NULL && language[0] == '\0')
1141    language = NULL;
1142
1143  /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1144     `LC_xxx', and `LANG'.  On some systems this can be done by the
1145     `setlocale' function itself.  */
1146#ifdef _LIBC
1147  retval = __current_locale_name (category);
1148#else
1149  retval = _nl_locale_name (category, categoryname);
1150#endif
1151
1152  /* Ignore LANGUAGE if the locale is set to "C" because
1153     1. "C" locale usually uses the ASCII encoding, and most international
1154	messages use non-ASCII characters. These characters get displayed
1155	as question marks (if using glibc's iconv()) or as invalid 8-bit
1156	characters (because other iconv()s refuse to convert most non-ASCII
1157	characters to ASCII). In any case, the output is ugly.
1158     2. The precise output of some programs in the "C" locale is specified
1159	by POSIX and should not depend on environment variables like
1160	"LANGUAGE".  We allow such programs to use gettext().  */
1161  return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1162}
1163
1164/* @@ begin of epilog @@ */
1165
1166/* We don't want libintl.a to depend on any other library.  So we
1167   avoid the non-standard function stpcpy.  In GNU C Library this
1168   function is available, though.  Also allow the symbol HAVE_STPCPY
1169   to be defined.  */
1170#if !_LIBC && !HAVE_STPCPY
1171static char *
1172stpcpy (char *dest, const char *src)
1173{
1174  while ((*dest++ = *src++) != '\0')
1175    /* Do nothing. */ ;
1176  return dest - 1;
1177}
1178#endif
1179
1180#if !_LIBC && !HAVE_MEMPCPY
1181static void *
1182mempcpy (void *dest, const void *src, size_t n)
1183{
1184  return (void *) ((char *) memcpy (dest, src, n) + n);
1185}
1186#endif
1187
1188
1189#ifdef _LIBC
1190/* If we want to free all resources we have to do some work at
1191   program's end.  */
1192libc_freeres_fn (free_mem)
1193{
1194  void *old;
1195
1196  while (_nl_domain_bindings != NULL)
1197    {
1198      struct binding *oldp = _nl_domain_bindings;
1199      _nl_domain_bindings = _nl_domain_bindings->next;
1200      if (oldp->dirname != INTUSE(_nl_default_dirname))
1201	/* Yes, this is a pointer comparison.  */
1202	free (oldp->dirname);
1203      free (oldp->codeset);
1204      free (oldp);
1205    }
1206
1207  if (_nl_current_default_domain != _nl_default_default_domain)
1208    /* Yes, again a pointer comparison.  */
1209    free ((char *) _nl_current_default_domain);
1210
1211  /* Remove the search tree with the known translations.  */
1212  __tdestroy (root, free);
1213  root = NULL;
1214
1215  while (transmem_list != NULL)
1216    {
1217      old = transmem_list;
1218      transmem_list = transmem_list->next;
1219      free (old);
1220    }
1221}
1222#endif
1223