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