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