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
43 char *alloca ();
44 #   endif
45 #  endif
46 # endif
47 #endif
48 
49 #include <errno.h>
50 #ifndef errno
51 extern 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
143 char *getwd ();
144 #  define getcwd(buf, max) getwd (buf)
145 # else
146 char *getcwd ();
147 # endif
148 # ifndef HAVE_STPCPY
149 static char *stpcpy PARAMS ((char *dest, const char *src));
150 # endif
151 # ifndef HAVE_MEMPCPY
152 static 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.  */
212 struct 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 
239 static 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.  */
246 static int transcmp PARAMS ((const void *p1, const void *p2));
247 static int
transcmp(p1,p2)248 transcmp (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".  */
276 const char _nl_default_default_domain[] attribute_hidden = "messages";
277 
278 /* Value used as the default domain for gettext(3).  */
279 const 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__
284 extern const char _nl_default_dirname[];
285 #else
286 const char _nl_default_dirname[] = LOCALEDIR;
287 #endif
288 
289 /* List with bindings of specific domains created by bindtextdomain()
290    calls.  */
291 struct binding *_nl_domain_bindings;
292 
293 /* Prototypes for local functions.  */
294 static 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;
299 static const char *category_to_name PARAMS ((int category)) internal_function;
300 static 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
313 struct 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.  */
346 typedef struct transmem_list
347 {
348   struct transmem_list *next;
349   char data[ZERO];
350 } transmem_block_t;
351 static struct transmem_list *transmem_list;
352 #else
353 typedef 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
390 static 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.  */
408 char *
409 DCIGETTEXT (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 
691 char *
692 internal_function
_nl_find_msg(domain_file,domainbinding,msgid,lengthp)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.  */
1002 static char *
1003 internal_function
plural_lookup(domain,n,translation,translation_len)1004 plural_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.  */
1043 static const char *
1044 internal_function
category_to_name(category)1045 category_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.  */
1103 static const char *
1104 internal_function
guess_category_value(category,categoryname)1105 guess_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
1147 static char *
stpcpy(dest,src)1148 stpcpy (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
1159 static void *
mempcpy(dest,src,n)1160 mempcpy (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.  */
1173 static void __attribute__ ((unused))
free_mem(void)1174 free_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 
1205 text_set_element (__libc_subfreeres, free_mem);
1206 #endif
1207