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