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