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