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