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