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