• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Implementation of the internal dcigettext function.
2    Copyright (C) 1995-2020 Free Software Foundation, Inc.
3 
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 2.1 of the License, or
7    (at your option) 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
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
18    This must come before <config.h> because <config.h> may include
19    <features.h>, and once <features.h> has been included, it's too late.  */
20 #ifndef _GNU_SOURCE
21 # define _GNU_SOURCE	1
22 #endif
23 
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27 
28 #include <sys/types.h>
29 
30 #ifdef __GNUC__
31 # define alloca __builtin_alloca
32 # define HAVE_ALLOCA 1
33 #else
34 # ifdef _MSC_VER
35 #  include <malloc.h>
36 #  define alloca _alloca
37 # else
38 #  if defined HAVE_ALLOCA_H || defined _LIBC
39 #   include <alloca.h>
40 #  else
41 #   ifdef _AIX
42  #pragma alloca
43 #   else
44 #    ifndef alloca
45 char *alloca ();
46 #    endif
47 #   endif
48 #  endif
49 # endif
50 #endif
51 
52 #include <errno.h>
53 #ifndef errno
54 extern int errno;
55 #endif
56 #ifndef __set_errno
57 # define __set_errno(val) errno = (val)
58 #endif
59 
60 #include <stddef.h>
61 #include <stdlib.h>
62 #include <string.h>
63 
64 #if defined HAVE_UNISTD_H || defined _LIBC
65 # include <unistd.h>
66 #endif
67 
68 #include <locale.h>
69 
70 #ifdef _LIBC
71   /* Guess whether integer division by zero raises signal SIGFPE.
72      Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
73 # if defined __alpha__ || defined __arm__ || defined __i386__ \
74      || defined __m68k__ || defined __s390__
75 #  define INTDIV0_RAISES_SIGFPE 1
76 # else
77 #  define INTDIV0_RAISES_SIGFPE 0
78 # endif
79 #endif
80 #if !INTDIV0_RAISES_SIGFPE
81 # include <signal.h>
82 #endif
83 
84 #if defined HAVE_SYS_PARAM_H || defined _LIBC
85 # include <sys/param.h>
86 #endif
87 
88 #if !defined _LIBC
89 # include "localcharset.h"
90 #endif
91 
92 #include "gettextP.h"
93 #include "plural-exp.h"
94 #ifdef _LIBC
95 # include <libintl.h>
96 #else
97 # ifdef IN_LIBGLOCALE
98 #  include <libintl.h>
99 # endif
100 # include "libgnuintl.h"
101 #endif
102 #include "hash-string.h"
103 
104 /* Handle multi-threaded applications.  */
105 #ifdef _LIBC
106 # include <bits/libc-lock.h>
107 # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
108 # define gl_rwlock_rdlock __libc_rwlock_rdlock
109 # define gl_rwlock_wrlock __libc_rwlock_wrlock
110 # define gl_rwlock_unlock __libc_rwlock_unlock
111 #else
112 # include "lock.h"
113 #endif
114 
115 /* Alignment of types.  */
116 #if defined __GNUC__ && __GNUC__ >= 2
117 # define alignof(TYPE) __alignof__ (TYPE)
118 #else
119 # define alignof(TYPE) \
120     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
121 #endif
122 
123 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
124 #ifndef offsetof
125 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
126 #endif
127 
128 /* @@ end of prolog @@ */
129 
130 #ifdef _LIBC
131 /* Rename the non ANSI C functions.  This is required by the standard
132    because some ANSI C functions will require linking with this object
133    file and the name space must not be polluted.  */
134 # define getcwd __getcwd
135 # ifndef stpcpy
136 #  define stpcpy __stpcpy
137 # endif
138 # define tfind __tfind
139 #else
140 #ifdef OHOS_OPT_COMPAT
141 # if !defined HAVE_GETCWD
142 char *getwd ();
143 #  define getcwd(buf, max) getwd (buf)
144 # else
145 #  if VMS
146 #   define getcwd(buf, max) (getcwd) (buf, max, 0)
147 #  else
148 char *getcwd ();
149 #  endif
150 # endif
151 #endif
152 # ifndef HAVE_STPCPY
153 static char *stpcpy (char *dest, const char *src);
154 # endif
155 # ifndef HAVE_MEMPCPY
156 static void *mempcpy (void *dest, const void *src, size_t n);
157 # endif
158 #endif
159 
160 /* Use a replacement if the system does not provide the `tsearch' function
161    family.  */
162 #if defined HAVE_TSEARCH || defined _LIBC
163 # include <search.h>
164 #else
165 # define tsearch libintl_tsearch
166 # define tfind libintl_tfind
167 # define tdelete libintl_tdelete
168 # define twalk libintl_twalk
169 # include "tsearch.h"
170 #endif
171 
172 #ifdef _LIBC
173 # define tsearch __tsearch
174 #endif
175 
176 /* Amount to increase buffer size by in each try.  */
177 #define PATH_INCR 32
178 
179 /* The following is from pathmax.h.  */
180 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
181    PATH_MAX but might cause redefinition warnings when sys/param.h is
182    later included (as on MORE/BSD 4.3).  */
183 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
184 # include <limits.h>
185 #endif
186 
187 #ifndef _POSIX_PATH_MAX
188 # define _POSIX_PATH_MAX 255
189 #endif
190 
191 #if !defined PATH_MAX && defined _PC_PATH_MAX
192 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
193 #endif
194 
195 /* Don't include sys/param.h if it already has been.  */
196 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
197 # include <sys/param.h>
198 #endif
199 
200 #if !defined PATH_MAX && defined MAXPATHLEN
201 # define PATH_MAX MAXPATHLEN
202 #endif
203 
204 #ifndef PATH_MAX
205 # define PATH_MAX _POSIX_PATH_MAX
206 #endif
207 
208 #ifdef _LIBC
209 # define IS_ABSOLUTE_FILE_NAME(P) ((P)[0] == '/')
210 # define IS_RELATIVE_FILE_NAME(P) (! IS_ABSOLUTE_FILE_NAME (P))
211 # define IS_FILE_NAME_WITH_DIR(P) (strchr ((P), '/') != NULL)
212 #else
213 # include "filename.h"
214 #endif
215 
216 /* Whether to support different locales in different threads.  */
217 #if defined _LIBC || HAVE_USELOCALE || defined IN_LIBGLOCALE
218 # define HAVE_PER_THREAD_LOCALE
219 #endif
220 
221 /* This is the type used for the search tree where known translations
222    are stored.  */
223 struct known_translation_t
224 {
225   /* Domain in which to search.  */
226   const char *domainname;
227 
228   /* The category.  */
229   int category;
230 
231 #ifdef HAVE_PER_THREAD_LOCALE
232   /* Name of the relevant locale category, or "" for the global locale.  */
233   const char *localename;
234 #endif
235 
236 #ifdef IN_LIBGLOCALE
237   /* The character encoding.  */
238   const char *encoding;
239 #endif
240 
241   /* State of the catalog counter at the point the string was found.  */
242   int counter;
243 
244   /* Catalog where the string was found.  */
245   struct loaded_l10nfile *domain;
246 
247   /* And finally the translation.  */
248   const char *translation;
249   size_t translation_length;
250 
251   /* Pointer to the string in question.  */
252   union
253     {
254       char appended[ZERO];  /* used if domain != NULL */
255       const char *ptr;      /* used if domain == NULL */
256     }
257   msgid;
258 };
259 
260 gl_rwlock_define_initialized (static, tree_lock)
261 
262 /* Root of the search tree with known translations.  */
263 static void *root;
264 
265 /* Function to compare two entries in the table of known translations.  */
266 static int
transcmp(const void * p1,const void * p2)267 transcmp (const void *p1, const void *p2)
268 {
269   const struct known_translation_t *s1;
270   const struct known_translation_t *s2;
271   int result;
272 
273   s1 = (const struct known_translation_t *) p1;
274   s2 = (const struct known_translation_t *) p2;
275 
276   result = strcmp (s1->domain != NULL ? s1->msgid.appended : s1->msgid.ptr,
277 		   s2->domain != NULL ? s2->msgid.appended : s2->msgid.ptr);
278   if (result == 0)
279     {
280       result = strcmp (s1->domainname, s2->domainname);
281       if (result == 0)
282 	{
283 #ifdef HAVE_PER_THREAD_LOCALE
284 	  result = strcmp (s1->localename, s2->localename);
285 	  if (result == 0)
286 #endif
287 	    {
288 #ifdef IN_LIBGLOCALE
289 	      result = strcmp (s1->encoding, s2->encoding);
290 	      if (result == 0)
291 #endif
292 		/* We compare the category last (though this is the cheapest
293 		   operation) since it is hopefully always the same (namely
294 		   LC_MESSAGES).  */
295 		result = s1->category - s2->category;
296 	    }
297 	}
298     }
299 
300   return result;
301 }
302 
303 /* Name of the default domain used for gettext(3) prior any call to
304    textdomain(3).  The default value for this is "messages".  */
305 const char _nl_default_default_domain[] attribute_hidden = "messages";
306 
307 #ifndef IN_LIBGLOCALE
308 /* Value used as the default domain for gettext(3).  */
309 const char *_nl_current_default_domain attribute_hidden
310      = _nl_default_default_domain;
311 #endif
312 
313 /* Contains the default location of the message catalogs.  */
314 #if defined __EMX__ && !defined __KLIBC__
315 extern const char _nl_default_dirname[];
316 #else
317 # ifdef _LIBC
318 extern const char _nl_default_dirname[];
319 libc_hidden_proto (_nl_default_dirname)
320 # endif
321 const char _nl_default_dirname[] = LOCALEDIR;
322 # ifdef _LIBC
323 libc_hidden_data_def (_nl_default_dirname)
324 # endif
325 #endif
326 
327 #ifndef IN_LIBGLOCALE
328 /* List with bindings of specific domains created by bindtextdomain()
329    calls.  */
330 struct binding *_nl_domain_bindings;
331 #endif
332 
333 /* Prototypes for local functions.  */
334 static char *plural_lookup (struct loaded_l10nfile *domain,
335 			    unsigned long int n,
336 			    const char *translation, size_t translation_len)
337      internal_function;
338 
339 #ifdef IN_LIBGLOCALE
340 static const char *guess_category_value (int category,
341 					 const char *categoryname,
342 					 const char *localename)
343      internal_function;
344 #else
345 static const char *guess_category_value (int category,
346 					 const char *categoryname)
347      internal_function;
348 #endif
349 
350 #ifdef _LIBC
351 # include "../locale/localeinfo.h"
352 # define category_to_name(category) \
353   _nl_category_names.str + _nl_category_name_idxs[category]
354 #else
355 static const char *category_to_name (int category) internal_function;
356 #endif
357 #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
358 static const char *get_output_charset (struct binding *domainbinding)
359      internal_function;
360 #endif
361 
362 
363 /* For those losing systems which don't have `alloca' we have to add
364    some additional code emulating it.  */
365 #ifdef HAVE_ALLOCA
366 /* Nothing has to be done.  */
367 # define freea(p) /* nothing */
368 # define ADD_BLOCK(list, address) /* nothing */
369 # define FREE_BLOCKS(list) /* nothing */
370 #else
371 struct block_list
372 {
373   void *address;
374   struct block_list *next;
375 };
376 # define ADD_BLOCK(list, addr)						      \
377   do {									      \
378     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
379     /* If we cannot get a free block we cannot add the new element to	      \
380        the list.  */							      \
381     if (newp != NULL) {							      \
382       newp->address = (addr);						      \
383       newp->next = (list);						      \
384       (list) = newp;							      \
385     }									      \
386   } while (0)
387 # define FREE_BLOCKS(list)						      \
388   do {									      \
389     while (list != NULL) {						      \
390       struct block_list *old = list;					      \
391       list = list->next;						      \
392       free (old->address);						      \
393       free (old);							      \
394     }									      \
395   } while (0)
396 # undef alloca
397 # define alloca(size) (malloc (size))
398 # define freea(p) free (p)
399 #endif	/* have alloca */
400 
401 
402 #ifdef _LIBC
403 /* List of blocks allocated for translations.  */
404 typedef struct transmem_list
405 {
406   struct transmem_list *next;
407   char data[ZERO];
408 } transmem_block_t;
409 static struct transmem_list *transmem_list;
410 #else
411 typedef unsigned char transmem_block_t;
412 #endif
413 
414 
415 /* Names for the libintl functions are a problem.  They must not clash
416    with existing names and they should follow ANSI C.  But this source
417    code is also used in GNU C Library where the names have a __
418    prefix.  So we have to make a difference here.  */
419 #ifdef _LIBC
420 # define DCIGETTEXT __dcigettext
421 #else
422 # define DCIGETTEXT libintl_dcigettext
423 #endif
424 
425 /* Lock variable to protect the global data in the gettext implementation.  */
426 gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
427 
428 /* Checking whether the binaries runs SUID must be done and glibc provides
429    easier methods therefore we make a difference here.  */
430 #ifdef _LIBC
431 # define ENABLE_SECURE __libc_enable_secure
432 # define DETERMINE_SECURE
433 #else
434 # ifndef HAVE_GETUID
435 #  define getuid() 0
436 # endif
437 # ifndef HAVE_GETGID
438 #  define getgid() 0
439 # endif
440 # ifndef HAVE_GETEUID
441 #  define geteuid() getuid()
442 # endif
443 # ifndef HAVE_GETEGID
444 #  define getegid() getgid()
445 # endif
446 static int enable_secure;
447 # define ENABLE_SECURE (enable_secure == 1)
448 # define DETERMINE_SECURE \
449   if (enable_secure == 0)						      \
450     {									      \
451       if (getuid () != geteuid () || getgid () != getegid ())		      \
452 	enable_secure = 1;						      \
453       else								      \
454 	enable_secure = -1;						      \
455     }
456 #endif
457 
458 /* Get the function to evaluate the plural expression.  */
459 #include "eval-plural.h"
460 
461 /* Look up MSGID in the DOMAINNAME message catalog for the current
462    CATEGORY locale and, if PLURAL is nonzero, search over string
463    depending on the plural form determined by N.  */
464 #ifdef IN_LIBGLOCALE
465 char *
gl_dcigettext(const char * domainname,const char * msgid1,const char * msgid2,int plural,unsigned long int n,int category,const char * localename,const char * encoding)466 gl_dcigettext (const char *domainname,
467 	       const char *msgid1, const char *msgid2,
468 	       int plural, unsigned long int n,
469 	       int category,
470 	       const char *localename, const char *encoding)
471 #else
472 char *
473 DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
474 	    int plural, unsigned long int n, int category)
475 #endif
476 {
477 #ifndef HAVE_ALLOCA
478   struct block_list *block_list = NULL;
479 #endif
480   struct loaded_l10nfile *domain;
481   struct binding *binding;
482   const char *categoryname;
483   const char *categoryvalue;
484   const char *dirname;
485 #if defined _WIN32 && !defined __CYGWIN__
486   const wchar_t *wdirname;
487 #endif
488   char *xdomainname;
489   char *single_locale;
490   char *retval;
491   size_t retlen;
492   int saved_errno;
493   struct known_translation_t search;
494   struct known_translation_t **foundp = NULL;
495 #if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
496   const char *localename;
497 #endif
498   size_t domainname_len;
499 
500   /* If no real MSGID is given return NULL.  */
501   if (msgid1 == NULL)
502     return NULL;
503 
504 #ifdef _LIBC
505   if (category < 0 || category >= __LC_LAST || category == LC_ALL)
506     /* Bogus.  */
507     return (plural == 0
508 	    ? (char *) msgid1
509 	    /* Use the Germanic plural rule.  */
510 	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
511 #endif
512 
513   /* Preserve the `errno' value.  */
514   saved_errno = errno;
515 
516 #ifdef _LIBC
517   __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
518   __libc_rwlock_rdlock (__libc_setlocale_lock);
519 #endif
520 
521   gl_rwlock_rdlock (_nl_state_lock);
522 
523   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
524      CATEGORY is not LC_MESSAGES this might not make much sense but the
525      definition left this undefined.  */
526   if (domainname == NULL)
527     domainname = _nl_current_default_domain;
528 
529   /* OS/2 specific: backward compatibility with older libintl versions  */
530 #ifdef LC_MESSAGES_COMPAT
531   if (category == LC_MESSAGES_COMPAT)
532     category = LC_MESSAGES;
533 #endif
534 
535   /* Try to find the translation among those which we found at
536      some time.  */
537   search.domain = NULL;
538   search.msgid.ptr = msgid1;
539   search.domainname = domainname;
540   search.category = category;
541 #ifdef HAVE_PER_THREAD_LOCALE
542 # ifndef IN_LIBGLOCALE
543 #  ifdef _LIBC
544   localename = strdupa (__current_locale_name (category));
545 #  else
546   categoryname = category_to_name (category);
547 #   define CATEGORYNAME_INITIALIZED
548   localename = _nl_locale_name_thread_unsafe (category, categoryname);
549   if (localename == NULL)
550     localename = "";
551 #  endif
552 # endif
553   search.localename = localename;
554 #endif
555 #ifdef IN_LIBGLOCALE
556   search.encoding = encoding;
557 #endif
558 
559   /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
560      tsearch calls can be fatal.  */
561   gl_rwlock_rdlock (tree_lock);
562 
563   foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
564 
565   gl_rwlock_unlock (tree_lock);
566 
567   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
568     {
569       /* Now deal with plural.  */
570       if (plural)
571 	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
572 				(*foundp)->translation_length);
573       else
574 	retval = (char *) (*foundp)->translation;
575 
576       gl_rwlock_unlock (_nl_state_lock);
577 # ifdef _LIBC
578       __libc_rwlock_unlock (__libc_setlocale_lock);
579 # endif
580       __set_errno (saved_errno);
581       return retval;
582     }
583 
584   /* See whether this is a SUID binary or not.  */
585   DETERMINE_SECURE;
586 
587   /* First find matching binding.  */
588 #ifdef IN_LIBGLOCALE
589   /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
590      and _nl_load_domain and _nl_find_domain just pass it through.  */
591   binding = NULL;
592   dirname = bindtextdomain (domainname, NULL);
593 # if defined _WIN32 && !defined __CYGWIN__
594   wdirname = wbindtextdomain (domainname, NULL);
595 # endif
596 #else
597   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
598     {
599       int compare = strcmp (domainname, binding->domainname);
600       if (compare == 0)
601 	/* We found it!  */
602 	break;
603       if (compare < 0)
604 	{
605 	  /* It is not in the list.  */
606 	  binding = NULL;
607 	  break;
608 	}
609     }
610 
611   if (binding == NULL)
612     {
613       dirname = _nl_default_dirname;
614 # if defined _WIN32 && !defined __CYGWIN__
615       wdirname = NULL;
616 # endif
617     }
618   else
619     {
620       dirname = binding->dirname;
621 # if defined _WIN32 && !defined __CYGWIN__
622       wdirname = binding->wdirname;
623 # endif
624 #endif
625 #if defined _WIN32 && !defined __CYGWIN__
626       if (wdirname != NULL
627 	  ? IS_RELATIVE_FILE_NAME (wdirname)
628 	  : IS_RELATIVE_FILE_NAME (dirname))
629 	{
630 	  /* We have a relative path.  Make it absolute now.  */
631 	  size_t wdirname_len;
632 	  size_t path_max;
633 	  wchar_t *resolved_wdirname;
634 	  wchar_t *ret;
635 	  wchar_t *p;
636 
637 	  if (wdirname != NULL)
638 	    wdirname_len = wcslen (wdirname);
639 	  else
640 	    {
641 	      wdirname_len = mbstowcs (NULL, dirname, 0);
642 
643 	      if (wdirname_len == (size_t)(-1))
644 		/* dirname contains invalid multibyte characters.  Don't signal
645 		   an error but simply return the default string.  */
646 		goto return_untranslated;
647 	    }
648 	  wdirname_len++;
649 
650 	  path_max = (unsigned int) PATH_MAX;
651 	  path_max += 2;		/* The getcwd docs say to do this.  */
652 
653 	  for (;;)
654 	    {
655 	      resolved_wdirname =
656 		(wchar_t *)
657 		alloca ((path_max + wdirname_len) * sizeof (wchar_t));
658 	      ADD_BLOCK (block_list, resolved_wdirname);
659 
660 	      __set_errno (0);
661 	      ret = _wgetcwd (resolved_wdirname, path_max);
662 	      if (ret != NULL || errno != ERANGE)
663 		break;
664 
665 	      path_max += path_max / 2;
666 	      path_max += PATH_INCR;
667 	    }
668 
669 	  if (ret == NULL)
670 	    /* We cannot get the current working directory.  Don't signal an
671 	       error but simply return the default string.  */
672 	    goto return_untranslated;
673 
674 	  p = wcschr (resolved_wdirname, L'\0');
675 	  *p++ = L'/';
676 	  if (wdirname != NULL)
677 	    wcscpy (p, wdirname);
678 	  else
679 	    mbstowcs (p, dirname, wdirname_len);
680 
681 	  wdirname = resolved_wdirname;
682 	  dirname = NULL;
683 	}
684 #else
685       if (IS_RELATIVE_FILE_NAME (dirname))
686 	{
687 	  /* We have a relative path.  Make it absolute now.  */
688 	  size_t dirname_len = strlen (dirname) + 1;
689 	  size_t path_max;
690 	  char *resolved_dirname;
691 	  char *ret;
692 
693 	  path_max = (unsigned int) PATH_MAX;
694 	  path_max += 2;		/* The getcwd docs say to do this.  */
695 
696 	  for (;;)
697 	    {
698 	      resolved_dirname = (char *) alloca (path_max + dirname_len);
699 	      ADD_BLOCK (block_list, resolved_dirname);
700 
701 	      __set_errno (0);
702 	      ret = getcwd (resolved_dirname, path_max);
703 	      if (ret != NULL || errno != ERANGE)
704 		break;
705 
706 	      path_max += path_max / 2;
707 	      path_max += PATH_INCR;
708 	    }
709 
710 	  if (ret == NULL)
711 	    /* We cannot get the current working directory.  Don't signal an
712 	       error but simply return the default string.  */
713 	    goto return_untranslated;
714 
715 	  stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
716 	  dirname = resolved_dirname;
717 	}
718 #endif
719 #ifndef IN_LIBGLOCALE
720     }
721 #endif
722 
723   /* Now determine the symbolic name of CATEGORY and its value.  */
724 #ifndef CATEGORYNAME_INITIALIZED
725   categoryname = category_to_name (category);
726 #endif
727 #ifdef IN_LIBGLOCALE
728   categoryvalue = guess_category_value (category, categoryname, localename);
729 #else
730   categoryvalue = guess_category_value (category, categoryname);
731 #endif
732 
733   domainname_len = strlen (domainname);
734   xdomainname = (char *) alloca (strlen (categoryname)
735 				 + domainname_len + 5);
736   ADD_BLOCK (block_list, xdomainname);
737 
738   stpcpy ((char *) mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
739 			    domainname, domainname_len),
740 	  ".mo");
741 
742   /* Creating working area.  */
743   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
744   ADD_BLOCK (block_list, single_locale);
745 
746 
747   /* Search for the given string.  This is a loop because we perhaps
748      got an ordered list of languages to consider for the translation.  */
749   while (1)
750     {
751       /* Make CATEGORYVALUE point to the next element of the list.  */
752       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
753 	++categoryvalue;
754       if (categoryvalue[0] == '\0')
755 	{
756 	  /* The whole contents of CATEGORYVALUE has been searched but
757 	     no valid entry has been found.  We solve this situation
758 	     by implicitly appending a "C" entry, i.e. no translation
759 	     will take place.  */
760 	  single_locale[0] = 'C';
761 	  single_locale[1] = '\0';
762 	}
763       else
764 	{
765 	  char *cp = single_locale;
766 	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
767 	    *cp++ = *categoryvalue++;
768 	  *cp = '\0';
769 
770 	  /* When this is a SUID binary we must not allow accessing files
771 	     outside the dedicated directories.  */
772 	  if (ENABLE_SECURE && IS_FILE_NAME_WITH_DIR (single_locale))
773 	    /* Ingore this entry.  */
774 	    continue;
775 	}
776 
777       /* If the current locale value is C (or POSIX) we don't load a
778 	 domain.  Return the MSGID.  */
779       if (strcmp (single_locale, "C") == 0
780 	  || strcmp (single_locale, "POSIX") == 0)
781 	break;
782 
783       /* Find structure describing the message catalog matching the
784 	 DOMAINNAME and CATEGORY.  */
785       domain = _nl_find_domain (dirname,
786 #if defined _WIN32 && !defined __CYGWIN__
787 				wdirname,
788 #endif
789 				single_locale, xdomainname, binding);
790 
791       if (domain != NULL)
792 	{
793 #if defined IN_LIBGLOCALE
794 	  retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
795 #else
796 	  retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
797 #endif
798 
799 	  if (retval == NULL)
800 	    {
801 	      int cnt;
802 
803 	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
804 		{
805 #if defined IN_LIBGLOCALE
806 		  retval = _nl_find_msg (domain->successor[cnt], binding,
807 					 encoding, msgid1, &retlen);
808 #else
809 		  retval = _nl_find_msg (domain->successor[cnt], binding,
810 					 msgid1, 1, &retlen);
811 #endif
812 
813 		  /* Resource problems are not fatal, instead we return no
814 		     translation.  */
815 		  if (__builtin_expect (retval == (char *) -1, 0))
816 		    goto return_untranslated;
817 
818 		  if (retval != NULL)
819 		    {
820 		      domain = domain->successor[cnt];
821 		      break;
822 		    }
823 		}
824 	    }
825 
826 	  /* Returning -1 means that some resource problem exists
827 	     (likely memory) and that the strings could not be
828 	     converted.  Return the original strings.  */
829 	  if (__builtin_expect (retval == (char *) -1, 0))
830 	    break;
831 
832 	  if (retval != NULL)
833 	    {
834 	      /* Found the translation of MSGID1 in domain DOMAIN:
835 		 starting at RETVAL, RETLEN bytes.  */
836 	      FREE_BLOCKS (block_list);
837 	      if (foundp == NULL)
838 		{
839 		  /* Create a new entry and add it to the search tree.  */
840 		  size_t msgid_len;
841 		  size_t size;
842 		  struct known_translation_t *newp;
843 
844 		  msgid_len = strlen (msgid1) + 1;
845 		  size = offsetof (struct known_translation_t, msgid)
846 			 + msgid_len + domainname_len + 1;
847 #ifdef HAVE_PER_THREAD_LOCALE
848 		  size += strlen (localename) + 1;
849 #endif
850 		  newp = (struct known_translation_t *) malloc (size);
851 		  if (newp != NULL)
852 		    {
853 		      char *new_domainname;
854 #ifdef HAVE_PER_THREAD_LOCALE
855 		      char *new_localename;
856 #endif
857 
858 		      new_domainname =
859 			(char *) mempcpy (newp->msgid.appended, msgid1,
860 					  msgid_len);
861 		      memcpy (new_domainname, domainname, domainname_len + 1);
862 #ifdef HAVE_PER_THREAD_LOCALE
863 		      new_localename = new_domainname + domainname_len + 1;
864 		      strcpy (new_localename, localename);
865 #endif
866 		      newp->domainname = new_domainname;
867 		      newp->category = category;
868 #ifdef HAVE_PER_THREAD_LOCALE
869 		      newp->localename = new_localename;
870 #endif
871 #ifdef IN_LIBGLOCALE
872 		      newp->encoding = encoding;
873 #endif
874 		      newp->counter = _nl_msg_cat_cntr;
875 		      newp->domain = domain;
876 		      newp->translation = retval;
877 		      newp->translation_length = retlen;
878 
879 		      gl_rwlock_wrlock (tree_lock);
880 
881 		      /* Insert the entry in the search tree.  */
882 		      foundp = (struct known_translation_t **)
883 			tsearch (newp, &root, transcmp);
884 
885 		      gl_rwlock_unlock (tree_lock);
886 
887 		      if (foundp == NULL
888 			  || __builtin_expect (*foundp != newp, 0))
889 			/* The insert failed.  */
890 			free (newp);
891 		    }
892 		}
893 	      else
894 		{
895 		  /* We can update the existing entry.  */
896 		  (*foundp)->counter = _nl_msg_cat_cntr;
897 		  (*foundp)->domain = domain;
898 		  (*foundp)->translation = retval;
899 		  (*foundp)->translation_length = retlen;
900 		}
901 
902 	      __set_errno (saved_errno);
903 
904 	      /* Now deal with plural.  */
905 	      if (plural)
906 		retval = plural_lookup (domain, n, retval, retlen);
907 
908 	      gl_rwlock_unlock (_nl_state_lock);
909 #ifdef _LIBC
910 	      __libc_rwlock_unlock (__libc_setlocale_lock);
911 #endif
912 	      return retval;
913 	    }
914 	}
915     }
916 
917  return_untranslated:
918   /* Return the untranslated MSGID.  */
919   FREE_BLOCKS (block_list);
920   gl_rwlock_unlock (_nl_state_lock);
921 #ifdef _LIBC
922   __libc_rwlock_unlock (__libc_setlocale_lock);
923 #endif
924 #ifndef _LIBC
925   if (!ENABLE_SECURE)
926     {
927       extern void _nl_log_untranslated (const char *logfilename,
928 					const char *domainname,
929 					const char *msgid1, const char *msgid2,
930 					int plural);
931       const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
932 
933       if (logfilename != NULL && logfilename[0] != '\0')
934 	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
935     }
936 #endif
937   __set_errno (saved_errno);
938   return (plural == 0
939 	  ? (char *) msgid1
940 	  /* Use the Germanic plural rule.  */
941 	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
942 }
943 
944 
945 /* This lock primarily protects the memory management variables freemem,
946    freemem_size.  It also protects write accesses to convd->conv_tab.
947    It's not worth using a separate lock (such as domain->conversions_lock)
948    for this purpose, because when modifying convd->conv_tab, we also need
949    to lock freemem, freemem_size for most of the time.  */
__libc_lock_define_initialized(static,lock)950 __libc_lock_define_initialized (static, lock)
951 
952 /* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
953    Return it if found.  Return NULL if not found or in case of a conversion
954    failure (problem in the particular message catalog).  Return (char *) -1
955    in case of a memory allocation failure during conversion (only if
956    ENCODING != NULL resp. CONVERT == true).  */
957 char *
958 internal_function
959 #ifdef IN_LIBGLOCALE
960 _nl_find_msg (struct loaded_l10nfile *domain_file,
961 	      struct binding *domainbinding, const char *encoding,
962 	      const char *msgid,
963 	      size_t *lengthp)
964 #else
965 _nl_find_msg (struct loaded_l10nfile *domain_file,
966 	      struct binding *domainbinding,
967 	      const char *msgid, int convert,
968 	      size_t *lengthp)
969 #endif
970 {
971   struct loaded_domain *domain;
972   nls_uint32 nstrings;
973   size_t act;
974   char *result;
975   size_t resultlen;
976 
977   if (domain_file->decided <= 0)
978     _nl_load_domain (domain_file, domainbinding);
979 
980   if (domain_file->data == NULL)
981     return NULL;
982 
983   domain = (struct loaded_domain *) domain_file->data;
984 
985   nstrings = domain->nstrings;
986 
987   /* Locate the MSGID and its translation.  */
988   if (domain->hash_tab != NULL)
989     {
990       /* Use the hashing table.  */
991       nls_uint32 len = strlen (msgid);
992       nls_uint32 hash_val = __hash_string (msgid);
993       nls_uint32 idx = hash_val % domain->hash_size;
994       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
995 
996       while (1)
997 	{
998 	  nls_uint32 nstr =
999 	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
1000 
1001 	  if (nstr == 0)
1002 	    /* Hash table entry is empty.  */
1003 	    return NULL;
1004 
1005 	  nstr--;
1006 
1007 	  /* Compare msgid with the original string at index nstr.
1008 	     We compare the lengths with >=, not ==, because plural entries
1009 	     are represented by strings with an embedded NUL.  */
1010 	  if (nstr < nstrings
1011 	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
1012 		&& (strcmp (msgid,
1013 			    domain->data + W (domain->must_swap,
1014 					      domain->orig_tab[nstr].offset))
1015 		    == 0)
1016 	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
1017 		&& (strcmp (msgid,
1018 			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
1019 		    == 0))
1020 	    {
1021 	      act = nstr;
1022 	      goto found;
1023 	    }
1024 
1025 	  if (idx >= domain->hash_size - incr)
1026 	    idx -= domain->hash_size - incr;
1027 	  else
1028 	    idx += incr;
1029 	}
1030       /* NOTREACHED */
1031     }
1032   else
1033     {
1034       /* Try the default method:  binary search in the sorted array of
1035 	 messages.  */
1036       size_t top, bottom;
1037 
1038       bottom = 0;
1039       top = nstrings;
1040       while (bottom < top)
1041 	{
1042 	  int cmp_val;
1043 
1044 	  act = (bottom + top) / 2;
1045 	  cmp_val = strcmp (msgid, (domain->data
1046 				    + W (domain->must_swap,
1047 					 domain->orig_tab[act].offset)));
1048 	  if (cmp_val < 0)
1049 	    top = act;
1050 	  else if (cmp_val > 0)
1051 	    bottom = act + 1;
1052 	  else
1053 	    goto found;
1054 	}
1055       /* No translation was found.  */
1056       return NULL;
1057     }
1058 
1059  found:
1060   /* The translation was found at index ACT.  If we have to convert the
1061      string to use a different character set, this is the time.  */
1062   if (act < nstrings)
1063     {
1064       result = (char *)
1065 	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
1066       resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
1067     }
1068   else
1069     {
1070       result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
1071       resultlen = domain->trans_sysdep_tab[act - nstrings].length;
1072     }
1073 
1074 #if defined _LIBC || HAVE_ICONV
1075 # ifdef IN_LIBGLOCALE
1076   if (encoding != NULL)
1077 # else
1078   if (convert)
1079 # endif
1080     {
1081       /* We are supposed to do a conversion.  */
1082 # ifndef IN_LIBGLOCALE
1083       const char *encoding = get_output_charset (domainbinding);
1084 # endif
1085       size_t nconversions;
1086       struct converted_domain *convd;
1087       size_t i;
1088 
1089       /* Protect against reallocation of the table.  */
1090       gl_rwlock_rdlock (domain->conversions_lock);
1091 
1092       /* Search whether a table with converted translations for this
1093 	 encoding has already been allocated.  */
1094       nconversions = domain->nconversions;
1095       convd = NULL;
1096 
1097       for (i = nconversions; i > 0; )
1098 	{
1099 	  i--;
1100 	  if (strcmp (domain->conversions[i].encoding, encoding) == 0)
1101 	    {
1102 	      convd = &domain->conversions[i];
1103 	      break;
1104 	    }
1105 	}
1106 
1107       gl_rwlock_unlock (domain->conversions_lock);
1108 
1109       if (convd == NULL)
1110 	{
1111 	  /* We have to allocate a new conversions table.  */
1112 	  gl_rwlock_wrlock (domain->conversions_lock);
1113 	  nconversions = domain->nconversions;
1114 
1115 	  /* Maybe in the meantime somebody added the translation.
1116 	     Recheck.  */
1117 	  for (i = nconversions; i > 0; )
1118 	    {
1119 	      i--;
1120 	      if (strcmp (domain->conversions[i].encoding, encoding) == 0)
1121 		{
1122 		  convd = &domain->conversions[i];
1123 		  goto found_convd;
1124 		}
1125 	    }
1126 
1127 	  {
1128 	    /* Allocate a table for the converted translations for this
1129 	       encoding.  */
1130 	    struct converted_domain *new_conversions =
1131 	      (struct converted_domain *)
1132 	      (domain->conversions != NULL
1133 	       ? realloc (domain->conversions,
1134 			  (nconversions + 1) * sizeof (struct converted_domain))
1135 	       : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
1136 
1137 	    if (__builtin_expect (new_conversions == NULL, 0))
1138 	      {
1139 		/* Nothing we can do, no more memory.  We cannot use the
1140 		   translation because it might be encoded incorrectly.  */
1141 	      unlock_fail:
1142 		gl_rwlock_unlock (domain->conversions_lock);
1143 		return (char *) -1;
1144 	      }
1145 
1146 	    domain->conversions = new_conversions;
1147 
1148 	    /* Copy the 'encoding' string to permanent storage.  */
1149 	    encoding = strdup (encoding);
1150 	    if (__builtin_expect (encoding == NULL, 0))
1151 	      /* Nothing we can do, no more memory.  We cannot use the
1152 		 translation because it might be encoded incorrectly.  */
1153 	      goto unlock_fail;
1154 
1155 	    convd = &new_conversions[nconversions];
1156 	    convd->encoding = encoding;
1157 
1158 	    /* Find out about the character set the file is encoded with.
1159 	       This can be found (in textual form) in the entry "".  If this
1160 	       entry does not exist or if this does not contain the 'charset='
1161 	       information, we will assume the charset matches the one the
1162 	       current locale and we don't have to perform any conversion.  */
1163 # ifdef _LIBC
1164 	    convd->conv = (__gconv_t) -1;
1165 # else
1166 #  if HAVE_ICONV
1167 	    convd->conv = (iconv_t) -1;
1168 #  endif
1169 # endif
1170 	    {
1171 	      char *nullentry;
1172 	      size_t nullentrylen;
1173 
1174 	      /* Get the header entry.  This is a recursion, but it doesn't
1175 		 reallocate domain->conversions because we pass
1176 		 encoding = NULL or convert = 0, respectively.  */
1177 	      nullentry =
1178 # ifdef IN_LIBGLOCALE
1179 		_nl_find_msg (domain_file, domainbinding, NULL, "",
1180 			      &nullentrylen);
1181 # else
1182 		_nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
1183 # endif
1184 
1185 	      /* Resource problems are fatal.  If we continue onwards we will
1186 	         only attempt to calloc a new conv_tab and fail later.  */
1187 	      if (__builtin_expect (nullentry == (char *) -1, 0))
1188 		{
1189 # ifndef IN_LIBGLOCALE
1190 		  free ((char *) encoding);
1191 # endif
1192 		  goto unlock_fail;
1193 		}
1194 
1195 	      if (nullentry != NULL)
1196 		{
1197 		  const char *charsetstr;
1198 
1199 		  charsetstr = strstr (nullentry, "charset=");
1200 		  if (charsetstr != NULL)
1201 		    {
1202 		      size_t len;
1203 		      char *charset;
1204 		      const char *outcharset;
1205 
1206 		      charsetstr += strlen ("charset=");
1207 		      len = strcspn (charsetstr, " \t\n");
1208 
1209 		      charset = (char *) alloca (len + 1);
1210 # if defined _LIBC || HAVE_MEMPCPY
1211 		      *((char *) mempcpy (charset, charsetstr, len)) = '\0';
1212 # else
1213 		      memcpy (charset, charsetstr, len);
1214 		      charset[len] = '\0';
1215 # endif
1216 
1217 		      outcharset = encoding;
1218 
1219 # ifdef _LIBC
1220 		      /* We always want to use transliteration.  */
1221 		      outcharset = norm_add_slashes (outcharset, "TRANSLIT");
1222 		      charset = norm_add_slashes (charset, "");
1223 		      int r = __gconv_open (outcharset, charset, &convd->conv,
1224 					    GCONV_AVOID_NOCONV);
1225 		      if (__builtin_expect (r != __GCONV_OK, 0))
1226 			{
1227 			  /* If the output encoding is the same there is
1228 			     nothing to do.  Otherwise do not use the
1229 			     translation at all.  */
1230 			  if (__builtin_expect (r != __GCONV_NULCONV, 1))
1231 			    {
1232 			      gl_rwlock_unlock (domain->conversions_lock);
1233 			      free ((char *) encoding);
1234 			      return NULL;
1235 			    }
1236 
1237 			  convd->conv = (__gconv_t) -1;
1238 			}
1239 # else
1240 #  if HAVE_ICONV
1241 		      /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
1242 			 we want to use transliteration.  */
1243 #   if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \
1244 	&& !defined __UCLIBC__) \
1245        || _LIBICONV_VERSION >= 0x0105
1246 		      if (strchr (outcharset, '/') == NULL)
1247 			{
1248 			  char *tmp;
1249 
1250 			  len = strlen (outcharset);
1251 			  tmp = (char *) alloca (len + 10 + 1);
1252 			  memcpy (tmp, outcharset, len);
1253 			  memcpy (tmp + len, "//TRANSLIT", 10 + 1);
1254 			  outcharset = tmp;
1255 
1256 			  convd->conv = iconv_open (outcharset, charset);
1257 
1258 			  freea (outcharset);
1259 			}
1260 		      else
1261 #   endif
1262 			convd->conv = iconv_open (outcharset, charset);
1263 #  endif
1264 # endif
1265 
1266 		      freea (charset);
1267 		    }
1268 		}
1269 	    }
1270 	    convd->conv_tab = NULL;
1271 	    /* Here domain->conversions is still == new_conversions.  */
1272 	    domain->nconversions++;
1273 	  }
1274 
1275 	found_convd:
1276 	  gl_rwlock_unlock (domain->conversions_lock);
1277 	}
1278 
1279       if (
1280 # ifdef _LIBC
1281 	  convd->conv != (__gconv_t) -1
1282 # else
1283 #  if HAVE_ICONV
1284 	  convd->conv != (iconv_t) -1
1285 #  endif
1286 # endif
1287 	  )
1288 	{
1289 	  /* We are supposed to do a conversion.  First allocate an
1290 	     appropriate table with the same structure as the table
1291 	     of translations in the file, where we can put the pointers
1292 	     to the converted strings in.
1293 	     There is a slight complication with plural entries.  They
1294 	     are represented by consecutive NUL terminated strings.  We
1295 	     handle this case by converting RESULTLEN bytes, including
1296 	     NULs.  */
1297 
1298 	  if (__builtin_expect (convd->conv_tab == NULL, 0))
1299 	    {
1300 	      __libc_lock_lock (lock);
1301 	      if (convd->conv_tab == NULL)
1302 		{
1303 		  convd->conv_tab =
1304 		    (char **) calloc (nstrings + domain->n_sysdep_strings,
1305 				      sizeof (char *));
1306 		  if (convd->conv_tab != NULL)
1307 		    goto not_translated_yet;
1308 		  /* Mark that we didn't succeed allocating a table.  */
1309 		  convd->conv_tab = (char **) -1;
1310 		}
1311 	      __libc_lock_unlock (lock);
1312 	    }
1313 
1314 	  if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
1315 	    /* Nothing we can do, no more memory.  We cannot use the
1316 	       translation because it might be encoded incorrectly.  */
1317 	    return (char *) -1;
1318 
1319 	  if (convd->conv_tab[act] == NULL)
1320 	    {
1321 	      /* We haven't used this string so far, so it is not
1322 		 translated yet.  Do this now.  */
1323 	      /* We use a bit more efficient memory handling.
1324 		 We allocate always larger blocks which get used over
1325 		 time.  This is faster than many small allocations.   */
1326 # define INITIAL_BLOCK_SIZE	4080
1327 	      static unsigned char *freemem;
1328 	      static size_t freemem_size;
1329 
1330 	      const unsigned char *inbuf;
1331 	      unsigned char *outbuf;
1332 	      int malloc_count;
1333 # ifndef _LIBC
1334 	      transmem_block_t *transmem_list;
1335 # endif
1336 
1337 	      __libc_lock_lock (lock);
1338 	    not_translated_yet:
1339 
1340 	      inbuf = (const unsigned char *) result;
1341 	      outbuf = freemem + sizeof (size_t);
1342 # ifndef _LIBC
1343 	      transmem_list = NULL;
1344 # endif
1345 
1346 	      malloc_count = 0;
1347 	      while (1)
1348 		{
1349 		  transmem_block_t *newmem;
1350 # ifdef _LIBC
1351 		  size_t non_reversible;
1352 		  int res;
1353 
1354 		  if (freemem_size < sizeof (size_t))
1355 		    goto resize_freemem;
1356 
1357 		  res = __gconv (convd->conv,
1358 				 &inbuf, inbuf + resultlen,
1359 				 &outbuf,
1360 				 outbuf + freemem_size - sizeof (size_t),
1361 				 &non_reversible);
1362 
1363 		  if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
1364 		    break;
1365 
1366 		  if (res != __GCONV_FULL_OUTPUT)
1367 		    {
1368 		      /* We should not use the translation at all, it
1369 			 is incorrectly encoded.  */
1370 		      __libc_lock_unlock (lock);
1371 		      return NULL;
1372 		    }
1373 
1374 		  inbuf = (const unsigned char *) result;
1375 # else
1376 #  if HAVE_ICONV
1377 		  const char *inptr = (const char *) inbuf;
1378 		  size_t inleft = resultlen;
1379 		  char *outptr = (char *) outbuf;
1380 		  size_t outleft;
1381 
1382 		  if (freemem_size < sizeof (size_t))
1383 		    goto resize_freemem;
1384 
1385 		  outleft = freemem_size - sizeof (size_t);
1386 		  if (iconv (convd->conv,
1387 			     (ICONV_CONST char **) &inptr, &inleft,
1388 			     &outptr, &outleft)
1389 		      != (size_t) (-1))
1390 		    {
1391 		      outbuf = (unsigned char *) outptr;
1392 		      break;
1393 		    }
1394 		  if (errno != E2BIG)
1395 		    {
1396 		      __libc_lock_unlock (lock);
1397 		      return NULL;
1398 		    }
1399 #  endif
1400 # endif
1401 
1402 		resize_freemem:
1403 		  /* We must allocate a new buffer or resize the old one.  */
1404 		  if (malloc_count > 0)
1405 		    {
1406 		      ++malloc_count;
1407 		      freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
1408 		      newmem = (transmem_block_t *) realloc (transmem_list,
1409 							     freemem_size);
1410 # ifdef _LIBC
1411 		      if (newmem != NULL)
1412 			transmem_list = newmem;
1413 		      else
1414 			{
1415 			  struct transmem_list *old = transmem_list;
1416 
1417 			  transmem_list = transmem_list->next;
1418 			  free (old);
1419 			}
1420 # endif
1421 		    }
1422 		  else
1423 		    {
1424 		      malloc_count = 1;
1425 		      freemem_size = INITIAL_BLOCK_SIZE;
1426 		      newmem = (transmem_block_t *) malloc (freemem_size);
1427 # ifdef _LIBC
1428 		      if (newmem != NULL)
1429 			{
1430 			  /* Add the block to the list of blocks we have to free
1431 			     at some point.  */
1432 			  newmem->next = transmem_list;
1433 			  transmem_list = newmem;
1434 			}
1435 		      /* Fall through and return -1.  */
1436 # endif
1437 		    }
1438 		  if (__builtin_expect (newmem == NULL, 0))
1439 		    {
1440 		      freemem = NULL;
1441 		      freemem_size = 0;
1442 		      __libc_lock_unlock (lock);
1443 		      return (char *) -1;
1444 		    }
1445 
1446 # ifdef _LIBC
1447 		  freemem = (unsigned char *) newmem->data;
1448 		  freemem_size -= offsetof (struct transmem_list, data);
1449 # else
1450 		  transmem_list = newmem;
1451 		  freemem = newmem;
1452 # endif
1453 
1454 		  outbuf = freemem + sizeof (size_t);
1455 		}
1456 
1457 	      /* We have now in our buffer a converted string.  Put this
1458 		 into the table of conversions.  */
1459 	      *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1460 	      convd->conv_tab[act] = (char *) freemem;
1461 	      /* Shrink freemem, but keep it aligned.  */
1462 	      freemem_size -= outbuf - freemem;
1463 	      freemem = outbuf;
1464 	      freemem += freemem_size & (alignof (size_t) - 1);
1465 	      freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1466 
1467 	      __libc_lock_unlock (lock);
1468 	    }
1469 
1470 	  /* Now convd->conv_tab[act] contains the translation of all
1471 	     the plural variants.  */
1472 	  result = convd->conv_tab[act] + sizeof (size_t);
1473 	  resultlen = *(size_t *) convd->conv_tab[act];
1474 	}
1475     }
1476 
1477   /* The result string is converted.  */
1478 
1479 #endif /* _LIBC || HAVE_ICONV */
1480 
1481   *lengthp = resultlen;
1482   return result;
1483 }
1484 
1485 
1486 /* Look up a plural variant.  */
1487 static char *
1488 internal_function
plural_lookup(struct loaded_l10nfile * domain,unsigned long int n,const char * translation,size_t translation_len)1489 plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
1490 	       const char *translation, size_t translation_len)
1491 {
1492   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1493   unsigned long int index;
1494   const char *p;
1495 
1496   index = plural_eval (domaindata->plural, n);
1497   if (index >= domaindata->nplurals)
1498     /* This should never happen.  It means the plural expression and the
1499        given maximum value do not match.  */
1500     index = 0;
1501 
1502   /* Skip INDEX strings at TRANSLATION.  */
1503   p = translation;
1504   while (index-- > 0)
1505     {
1506 #ifdef _LIBC
1507       p = __rawmemchr (p, '\0');
1508 #else
1509       p = strchr (p, '\0');
1510 #endif
1511       /* And skip over the NUL byte.  */
1512       p++;
1513 
1514       if (p >= translation + translation_len)
1515 	/* This should never happen.  It means the plural expression
1516 	   evaluated to a value larger than the number of variants
1517 	   available for MSGID1.  */
1518 	return (char *) translation;
1519     }
1520   return (char *) p;
1521 }
1522 
1523 #ifndef _LIBC
1524 /* Return string representation of locale CATEGORY.  */
1525 static const char *
1526 internal_function
category_to_name(int category)1527 category_to_name (int category)
1528 {
1529   const char *retval;
1530 
1531   switch (category)
1532   {
1533 #ifdef LC_COLLATE
1534   case LC_COLLATE:
1535     retval = "LC_COLLATE";
1536     break;
1537 #endif
1538 #ifdef LC_CTYPE
1539   case LC_CTYPE:
1540     retval = "LC_CTYPE";
1541     break;
1542 #endif
1543 #ifdef LC_MONETARY
1544   case LC_MONETARY:
1545     retval = "LC_MONETARY";
1546     break;
1547 #endif
1548 #ifdef LC_NUMERIC
1549   case LC_NUMERIC:
1550     retval = "LC_NUMERIC";
1551     break;
1552 #endif
1553 #ifdef LC_TIME
1554   case LC_TIME:
1555     retval = "LC_TIME";
1556     break;
1557 #endif
1558 #ifdef LC_MESSAGES
1559   case LC_MESSAGES:
1560     retval = "LC_MESSAGES";
1561     break;
1562 #endif
1563 #ifdef LC_RESPONSE
1564   case LC_RESPONSE:
1565     retval = "LC_RESPONSE";
1566     break;
1567 #endif
1568 #ifdef LC_ALL
1569   case LC_ALL:
1570     /* This might not make sense but is perhaps better than any other
1571        value.  */
1572     retval = "LC_ALL";
1573     break;
1574 #endif
1575   default:
1576     /* If you have a better idea for a default value let me know.  */
1577     retval = "LC_XXX";
1578   }
1579 
1580   return retval;
1581 }
1582 #endif
1583 
1584 /* Lookup or infer the value of specified category in the current locale.
1585    This uses values of the environment variables LC_ALL, LC_*, LANG, LANGUAGE,
1586    and/or system-dependent defaults.  */
1587 static const char *
1588 internal_function
1589 #ifdef IN_LIBGLOCALE
guess_category_value(int category,const char * categoryname,const char * locale)1590 guess_category_value (int category, const char *categoryname,
1591 		      const char *locale)
1592 
1593 #else
1594 guess_category_value (int category, const char *categoryname)
1595 #endif
1596 {
1597   const char *language;
1598 #ifndef IN_LIBGLOCALE
1599   const char *locale;
1600 # ifndef _LIBC
1601   const char *language_default;
1602   int locale_defaulted;
1603 # endif
1604 #endif
1605 
1606   /* We use the settings in the following order:
1607      1. The value of the environment variable 'LANGUAGE'.  This is a GNU
1608         extension.  Its value can be a colon-separated list of locale names.
1609      2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
1610         More precisely, the first among these that is set to a non-empty value.
1611         This is how POSIX specifies it.  The value is a single locale name.
1612      3. A system-dependent preference list of languages.  Its value can be a
1613         colon-separated list of locale names.
1614      4. A system-dependent default locale name.
1615      This way:
1616        - System-dependent settings can be overridden by environment variables.
1617        - If the system provides both a list of languages and a default locale,
1618          the former is used.  */
1619 
1620 #ifndef IN_LIBGLOCALE
1621   /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
1622      `LC_xxx', and `LANG'.  On some systems this can be done by the
1623      `setlocale' function itself.  */
1624 # ifdef _LIBC
1625   locale = __current_locale_name (category);
1626 # else
1627   locale_defaulted = 0;
1628 #  if HAVE_USELOCALE
1629   locale = _nl_locale_name_thread_unsafe (category, categoryname);
1630   if (locale == NULL)
1631 #  endif
1632     {
1633       locale = _nl_locale_name_posix (category, categoryname);
1634       if (locale == NULL)
1635 	{
1636 	  locale = _nl_locale_name_default ();
1637 	  locale_defaulted = 1;
1638 	}
1639     }
1640 # endif
1641 #endif
1642 
1643   /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
1644      to "C" because
1645      1. "C" locale usually uses the ASCII encoding, and most international
1646 	messages use non-ASCII characters. These characters get displayed
1647 	as question marks (if using glibc's iconv()) or as invalid 8-bit
1648 	characters (because other iconv()s refuse to convert most non-ASCII
1649 	characters to ASCII). In any case, the output is ugly.
1650      2. The precise output of some programs in the "C" locale is specified
1651 	by POSIX and should not depend on environment variables like
1652 	"LANGUAGE" or system-dependent information.  We allow such programs
1653         to use gettext().  */
1654   if (strcmp (locale, "C") == 0)
1655     return locale;
1656 
1657   /* The highest priority value is the value of the 'LANGUAGE' environment
1658      variable.  */
1659   language = getenv ("LANGUAGE");
1660   if (language != NULL && language[0] != '\0')
1661     return language;
1662 #if !defined IN_LIBGLOCALE && !defined _LIBC
1663   /* The next priority value is the locale name, if not defaulted.  */
1664   if (locale_defaulted)
1665     {
1666       /* The next priority value is the default language preferences list. */
1667       language_default = _nl_language_preferences_default ();
1668       if (language_default != NULL)
1669         return language_default;
1670     }
1671   /* The least priority value is the locale name, if defaulted.  */
1672 #endif
1673   return locale;
1674 }
1675 
1676 #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
1677 /* Returns the output charset.  */
1678 static const char *
1679 internal_function
get_output_charset(struct binding * domainbinding)1680 get_output_charset (struct binding *domainbinding)
1681 {
1682   /* The output charset should normally be determined by the locale.  But
1683      sometimes the locale is not used or not correctly set up, so we provide
1684      a possibility for the user to override this: the OUTPUT_CHARSET
1685      environment variable.  Moreover, the value specified through
1686      bind_textdomain_codeset overrides both.  */
1687   if (domainbinding != NULL && domainbinding->codeset != NULL)
1688     return domainbinding->codeset;
1689   else
1690     {
1691       /* For speed reasons, we look at the value of OUTPUT_CHARSET only
1692 	 once.  This is a user variable that is not supposed to change
1693 	 during a program run.  */
1694       static char *output_charset_cache;
1695       static int output_charset_cached;
1696 
1697       if (!output_charset_cached)
1698 	{
1699 	  const char *value = getenv ("OUTPUT_CHARSET");
1700 
1701 	  if (value != NULL && value[0] != '\0')
1702 	    {
1703 	      size_t len = strlen (value) + 1;
1704 	      char *value_copy = (char *) malloc (len);
1705 
1706 	      if (value_copy != NULL)
1707 		memcpy (value_copy, value, len);
1708 	      output_charset_cache = value_copy;
1709 	    }
1710 	  output_charset_cached = 1;
1711 	}
1712 
1713       if (output_charset_cache != NULL)
1714 	return output_charset_cache;
1715       else
1716 	{
1717 # ifdef _LIBC
1718 	  return _NL_CURRENT (LC_CTYPE, CODESET);
1719 # else
1720 #  if HAVE_ICONV
1721 	  return locale_charset ();
1722 #  endif
1723 # endif
1724 	}
1725     }
1726 }
1727 #endif
1728 
1729 /* @@ begin of epilog @@ */
1730 
1731 /* We don't want libintl.a to depend on any other library.  So we
1732    avoid the non-standard function stpcpy.  In GNU C Library this
1733    function is available, though.  Also allow the symbol HAVE_STPCPY
1734    to be defined.  */
1735 #if !_LIBC && !HAVE_STPCPY
1736 static char *
stpcpy(char * dest,const char * src)1737 stpcpy (char *dest, const char *src)
1738 {
1739   while ((*dest++ = *src++) != '\0')
1740     /* Do nothing. */ ;
1741   return dest - 1;
1742 }
1743 #endif
1744 
1745 #if !_LIBC && !HAVE_MEMPCPY
1746 static void *
mempcpy(void * dest,const void * src,size_t n)1747 mempcpy (void *dest, const void *src, size_t n)
1748 {
1749   return (void *) ((char *) memcpy (dest, src, n) + n);
1750 }
1751 #endif
1752 
1753 #if !_LIBC && !HAVE_TSEARCH
1754 # include "tsearch.c"
1755 #endif
1756 
1757 
1758 #ifdef _LIBC
1759 /* If we want to free all resources we have to do some work at
1760    program's end.  */
libc_freeres_fn(free_mem)1761 libc_freeres_fn (free_mem)
1762 {
1763   void *old;
1764 
1765   while (_nl_domain_bindings != NULL)
1766     {
1767       struct binding *oldp = _nl_domain_bindings;
1768       _nl_domain_bindings = _nl_domain_bindings->next;
1769       if (oldp->dirname != _nl_default_dirname)
1770 	/* Yes, this is a pointer comparison.  */
1771 	free (oldp->dirname);
1772       free (oldp->codeset);
1773       free (oldp);
1774     }
1775 
1776   if (_nl_current_default_domain != _nl_default_default_domain)
1777     /* Yes, again a pointer comparison.  */
1778     free ((char *) _nl_current_default_domain);
1779 
1780   /* Remove the search tree with the known translations.  */
1781   __tdestroy (root, free);
1782   root = NULL;
1783 
1784   while (transmem_list != NULL)
1785     {
1786       old = transmem_list;
1787       transmem_list = transmem_list->next;
1788       free (old);
1789     }
1790 }
1791 #endif
1792