Updated to fedora-glibc-20050912T0656
[glibc/history.git] / intl / dcigettext.c
blobf294dedf2fa0a0f01b4be7852bbea8253480e421
1 /* Implementation of the internal dcigettext function.
2 Copyright (C) 1995-2002,2003,2004,2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
21 This must come before <config.h> because <config.h> may include
22 <features.h>, and once <features.h> has been included, it's too late. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
31 #include <sys/types.h>
33 #ifdef __GNUC__
34 # define alloca __builtin_alloca
35 # define HAVE_ALLOCA 1
36 #else
37 # if defined HAVE_ALLOCA_H || defined _LIBC
38 # include <alloca.h>
39 # else
40 # ifdef _AIX
41 #pragma alloca
42 # else
43 # ifndef alloca
44 char *alloca ();
45 # endif
46 # endif
47 # endif
48 #endif
50 #include <errno.h>
51 #ifndef errno
52 extern int errno;
53 #endif
54 #ifndef __set_errno
55 # define __set_errno(val) errno = (val)
56 #endif
58 #include <stddef.h>
59 #include <stdlib.h>
60 #include <string.h>
62 #if defined HAVE_UNISTD_H || defined _LIBC
63 # include <unistd.h>
64 #endif
66 #include <locale.h>
68 #if defined HAVE_SYS_PARAM_H || defined _LIBC
69 # include <sys/param.h>
70 #endif
72 #include "gettextP.h"
73 #include "plural-exp.h"
74 #ifdef _LIBC
75 # include <libintl.h>
76 #else
77 # include "libgnuintl.h"
78 #endif
79 #include "hash-string.h"
81 /* Thread safetyness. */
82 #ifdef _LIBC
83 # include <bits/libc-lock.h>
84 #else
85 /* Provide dummy implementation if this is outside glibc. */
86 # define __libc_lock_define_initialized(CLASS, NAME)
87 # define __libc_lock_lock(NAME)
88 # define __libc_lock_unlock(NAME)
89 # define __libc_rwlock_define_initialized(CLASS, NAME)
90 # define __libc_rwlock_rdlock(NAME)
91 # define __libc_rwlock_unlock(NAME)
92 #endif
94 /* Alignment of types. */
95 #if defined __GNUC__ && __GNUC__ >= 2
96 # define alignof(TYPE) __alignof__ (TYPE)
97 #else
98 # define alignof(TYPE) \
99 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
100 #endif
102 /* The internal variables in the standalone libintl.a must have different
103 names than the internal variables in GNU libc, otherwise programs
104 using libintl.a cannot be linked statically. */
105 #if !defined _LIBC
106 # define _nl_default_default_domain libintl_nl_default_default_domain
107 # define _nl_current_default_domain libintl_nl_current_default_domain
108 # define _nl_default_dirname libintl_nl_default_dirname
109 # define _nl_domain_bindings libintl_nl_domain_bindings
110 #endif
112 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
113 #ifndef offsetof
114 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
115 #endif
117 /* @@ end of prolog @@ */
119 #ifdef _LIBC
120 /* Rename the non ANSI C functions. This is required by the standard
121 because some ANSI C functions will require linking with this object
122 file and the name space must not be polluted. */
123 # define getcwd __getcwd
124 # ifndef stpcpy
125 # define stpcpy __stpcpy
126 # endif
127 # define tfind __tfind
128 #else
129 # if !defined HAVE_GETCWD
130 char *getwd ();
131 # define getcwd(buf, max) getwd (buf)
132 # else
133 char *getcwd ();
134 # endif
135 # ifndef HAVE_STPCPY
136 static char *stpcpy PARAMS ((char *dest, const char *src));
137 # endif
138 # ifndef HAVE_MEMPCPY
139 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
140 # endif
141 #endif
143 /* Amount to increase buffer size by in each try. */
144 #define PATH_INCR 32
146 /* The following is from pathmax.h. */
147 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
148 PATH_MAX but might cause redefinition warnings when sys/param.h is
149 later included (as on MORE/BSD 4.3). */
150 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
151 # include <limits.h>
152 #endif
154 #ifndef _POSIX_PATH_MAX
155 # define _POSIX_PATH_MAX 255
156 #endif
158 #if !defined PATH_MAX && defined _PC_PATH_MAX
159 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
160 #endif
162 /* Don't include sys/param.h if it already has been. */
163 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
164 # include <sys/param.h>
165 #endif
167 #if !defined PATH_MAX && defined MAXPATHLEN
168 # define PATH_MAX MAXPATHLEN
169 #endif
171 #ifndef PATH_MAX
172 # define PATH_MAX _POSIX_PATH_MAX
173 #endif
175 /* Whether to support different locales in different threads. */
176 #if defined _LIBC || HAVE_NL_LOCALE_NAME
177 # define HAVE_PER_THREAD_LOCALE
178 #endif
180 /* This is the type used for the search tree where known translations
181 are stored. */
182 struct known_translation_t
184 /* Domain in which to search. */
185 const char *domainname;
187 /* The category. */
188 int category;
190 #ifdef HAVE_PER_THREAD_LOCALE
191 /* Name of the relevant locale category, or "" for the global locale. */
192 const char *localename;
193 #endif
195 /* State of the catalog counter at the point the string was found. */
196 int counter;
198 /* Catalog where the string was found. */
199 struct loaded_l10nfile *domain;
201 /* And finally the translation. */
202 const char *translation;
203 size_t translation_length;
205 /* Pointer to the string in question. */
206 char msgid[ZERO];
209 /* Root of the search tree with known translations. We can use this
210 only if the system provides the `tsearch' function family. */
211 #if defined HAVE_TSEARCH || defined _LIBC
212 # include <search.h>
214 static void *root;
216 # ifdef _LIBC
217 # define tsearch __tsearch
218 # endif
220 /* Function to compare two entries in the table of known translations. */
221 static int transcmp PARAMS ((const void *p1, const void *p2));
222 static int
223 transcmp (p1, p2)
224 const void *p1;
225 const void *p2;
227 const struct known_translation_t *s1;
228 const struct known_translation_t *s2;
229 int result;
231 s1 = (const struct known_translation_t *) p1;
232 s2 = (const struct known_translation_t *) p2;
234 result = strcmp (s1->msgid, s2->msgid);
235 if (result == 0)
237 result = strcmp (s1->domainname, s2->domainname);
238 if (result == 0)
240 #ifdef HAVE_PER_THREAD_LOCALE
241 result = strcmp (s1->localename, s2->localename);
242 if (result == 0)
243 #endif
244 /* We compare the category last (though this is the cheapest
245 operation) since it is hopefully always the same (namely
246 LC_MESSAGES). */
247 result = s1->category - s2->category;
251 return result;
253 #endif
255 /* Name of the default domain used for gettext(3) prior any call to
256 textdomain(3). The default value for this is "messages". */
257 const char _nl_default_default_domain[] attribute_hidden = "messages";
259 /* Value used as the default domain for gettext(3). */
260 const char *_nl_current_default_domain attribute_hidden
261 = _nl_default_default_domain;
263 /* Contains the default location of the message catalogs. */
265 #ifdef _LIBC
266 extern const char _nl_default_dirname[];
267 libc_hidden_proto (_nl_default_dirname)
268 #endif
269 const char _nl_default_dirname[] = LOCALEDIR;
270 #ifdef _LIBC
271 libc_hidden_data_def (_nl_default_dirname)
272 #endif
274 /* List with bindings of specific domains created by bindtextdomain()
275 calls. */
276 struct binding *_nl_domain_bindings;
278 /* Prototypes for local functions. */
279 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
280 unsigned long int n,
281 const char *translation,
282 size_t translation_len))
283 internal_function;
284 static const char *guess_category_value PARAMS ((int category,
285 const char *categoryname))
286 internal_function;
287 #ifdef _LIBC
288 # include "../locale/localeinfo.h"
289 # define category_to_name(category) _nl_category_names[category]
290 #else
291 static const char *category_to_name PARAMS ((int category)) internal_function;
292 #endif
295 /* For those loosing systems which don't have `alloca' we have to add
296 some additional code emulating it. */
297 #ifdef HAVE_ALLOCA
298 /* Nothing has to be done. */
299 # define freea(p) /* nothing */
300 # define ADD_BLOCK(list, address) /* nothing */
301 # define FREE_BLOCKS(list) /* nothing */
302 #else
303 struct block_list
305 void *address;
306 struct block_list *next;
308 # define ADD_BLOCK(list, addr) \
309 do { \
310 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
311 /* If we cannot get a free block we cannot add the new element to \
312 the list. */ \
313 if (newp != NULL) { \
314 newp->address = (addr); \
315 newp->next = (list); \
316 (list) = newp; \
318 } while (0)
319 # define FREE_BLOCKS(list) \
320 do { \
321 while (list != NULL) { \
322 struct block_list *old = list; \
323 list = list->next; \
324 free (old->address); \
325 free (old); \
327 } while (0)
328 # undef alloca
329 # define alloca(size) (malloc (size))
330 # define freea(p) free (p)
331 #endif /* have alloca */
334 #ifdef _LIBC
335 /* List of blocks allocated for translations. */
336 typedef struct transmem_list
338 struct transmem_list *next;
339 char data[ZERO];
340 } transmem_block_t;
341 static struct transmem_list *transmem_list;
342 #else
343 typedef unsigned char transmem_block_t;
344 #endif
345 #if defined _LIBC || HAVE_ICONV
346 static const char *get_output_charset PARAMS ((struct binding *domainbinding))
347 internal_function;
348 #endif
351 /* Names for the libintl functions are a problem. They must not clash
352 with existing names and they should follow ANSI C. But this source
353 code is also used in GNU C Library where the names have a __
354 prefix. So we have to make a difference here. */
355 #ifdef _LIBC
356 # define DCIGETTEXT __dcigettext
357 #else
358 # define DCIGETTEXT libintl_dcigettext
359 #endif
361 /* Lock variable to protect the global data in the gettext implementation. */
362 #ifdef _LIBC
363 __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
364 #endif
366 /* Checking whether the binaries runs SUID must be done and glibc provides
367 easier methods therefore we make a difference here. */
368 #ifdef _LIBC
369 # define ENABLE_SECURE __libc_enable_secure
370 # define DETERMINE_SECURE
371 #else
372 # ifndef HAVE_GETUID
373 # define getuid() 0
374 # endif
375 # ifndef HAVE_GETGID
376 # define getgid() 0
377 # endif
378 # ifndef HAVE_GETEUID
379 # define geteuid() getuid()
380 # endif
381 # ifndef HAVE_GETEGID
382 # define getegid() getgid()
383 # endif
384 static int enable_secure;
385 # define ENABLE_SECURE (enable_secure == 1)
386 # define DETERMINE_SECURE \
387 if (enable_secure == 0) \
389 if (getuid () != geteuid () || getgid () != getegid ()) \
390 enable_secure = 1; \
391 else \
392 enable_secure = -1; \
394 #endif
396 /* Get the function to evaluate the plural expression. */
397 #include "plural-eval.c"
399 /* Look up MSGID in the DOMAINNAME message catalog for the current
400 CATEGORY locale and, if PLURAL is nonzero, search over string
401 depending on the plural form determined by N. */
402 char *
403 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
404 const char *domainname;
405 const char *msgid1;
406 const char *msgid2;
407 int plural;
408 unsigned long int n;
409 int category;
411 #ifndef HAVE_ALLOCA
412 struct block_list *block_list = NULL;
413 #endif
414 struct loaded_l10nfile *domain;
415 struct binding *binding;
416 const char *categoryname;
417 const char *categoryvalue;
418 char *dirname, *xdomainname;
419 char *single_locale;
420 char *retval;
421 size_t retlen;
422 int saved_errno;
423 #if defined HAVE_TSEARCH || defined _LIBC
424 struct known_translation_t *search;
425 struct known_translation_t **foundp = NULL;
426 size_t msgid_len;
427 # ifdef HAVE_PER_THREAD_LOCALE
428 const char *localename;
429 # endif
430 #endif
431 size_t domainname_len;
433 /* If no real MSGID is given return NULL. */
434 if (msgid1 == NULL)
435 return NULL;
437 #ifdef _LIBC
438 if (category < 0 || category >= __LC_LAST || category == LC_ALL)
439 /* Bogus. */
440 return (plural == 0
441 ? (char *) msgid1
442 /* Use the Germanic plural rule. */
443 : n == 1 ? (char *) msgid1 : (char *) msgid2);
444 #endif
446 __libc_rwlock_rdlock (_nl_state_lock);
448 /* If DOMAINNAME is NULL, we are interested in the default domain. If
449 CATEGORY is not LC_MESSAGES this might not make much sense but the
450 definition left this undefined. */
451 if (domainname == NULL)
452 domainname = _nl_current_default_domain;
454 #if defined HAVE_TSEARCH || defined _LIBC
455 msgid_len = strlen (msgid1) + 1;
457 /* Try to find the translation among those which we found at
458 some time. */
459 search = (struct known_translation_t *)
460 alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
461 memcpy (search->msgid, msgid1, msgid_len);
462 search->domainname = domainname;
463 search->category = category;
464 # ifdef HAVE_PER_THREAD_LOCALE
465 # ifdef _LIBC
466 localename = __current_locale_name (category);
467 # endif
468 search->localename = localename;
469 # endif
471 /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
472 tsearch calls can be fatal. */
473 __libc_rwlock_define_initialized (static, tree_lock);
474 __libc_rwlock_rdlock (tree_lock);
476 foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
478 __libc_rwlock_unlock (tree_lock);
480 freea (search);
481 if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
483 /* Now deal with plural. */
484 if (plural)
485 retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
486 (*foundp)->translation_length);
487 else
488 retval = (char *) (*foundp)->translation;
490 __libc_rwlock_unlock (_nl_state_lock);
491 return retval;
493 #endif
495 /* Preserve the `errno' value. */
496 saved_errno = errno;
498 /* See whether this is a SUID binary or not. */
499 DETERMINE_SECURE;
501 /* First find matching binding. */
502 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
504 int compare = strcmp (domainname, binding->domainname);
505 if (compare == 0)
506 /* We found it! */
507 break;
508 if (compare < 0)
510 /* It is not in the list. */
511 binding = NULL;
512 break;
516 if (binding == NULL)
517 dirname = (char *) _nl_default_dirname;
518 else if (binding->dirname[0] == '/')
519 dirname = binding->dirname;
520 else
522 /* We have a relative path. Make it absolute now. */
523 size_t dirname_len = strlen (binding->dirname) + 1;
524 size_t path_max;
525 char *ret;
527 path_max = (unsigned int) PATH_MAX;
528 path_max += 2; /* The getcwd docs say to do this. */
530 for (;;)
532 dirname = (char *) alloca (path_max + dirname_len);
533 ADD_BLOCK (block_list, dirname);
535 __set_errno (0);
536 ret = getcwd (dirname, path_max);
537 if (ret != NULL || errno != ERANGE)
538 break;
540 path_max += path_max / 2;
541 path_max += PATH_INCR;
544 if (ret == NULL)
546 /* We cannot get the current working directory. Don't signal an
547 error but simply return the default string. */
548 FREE_BLOCKS (block_list);
549 __libc_rwlock_unlock (_nl_state_lock);
550 __set_errno (saved_errno);
551 return (plural == 0
552 ? (char *) msgid1
553 /* Use the Germanic plural rule. */
554 : n == 1 ? (char *) msgid1 : (char *) msgid2);
557 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
560 /* Now determine the symbolic name of CATEGORY and its value. */
561 categoryname = category_to_name (category);
562 categoryvalue = guess_category_value (category, categoryname);
564 domainname_len = strlen (domainname);
565 xdomainname = (char *) alloca (strlen (categoryname)
566 + domainname_len + 5);
567 ADD_BLOCK (block_list, xdomainname);
569 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
570 domainname, domainname_len),
571 ".mo");
573 /* Creating working area. */
574 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
575 ADD_BLOCK (block_list, single_locale);
578 /* Search for the given string. This is a loop because we perhaps
579 got an ordered list of languages to consider for the translation. */
580 while (1)
582 /* Make CATEGORYVALUE point to the next element of the list. */
583 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
584 ++categoryvalue;
585 if (categoryvalue[0] == '\0')
587 /* The whole contents of CATEGORYVALUE has been searched but
588 no valid entry has been found. We solve this situation
589 by implicitly appending a "C" entry, i.e. no translation
590 will take place. */
591 single_locale[0] = 'C';
592 single_locale[1] = '\0';
594 else
596 char *cp = single_locale;
597 while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
598 *cp++ = *categoryvalue++;
599 *cp = '\0';
601 /* When this is a SUID binary we must not allow accessing files
602 outside the dedicated directories. */
603 if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
604 /* Ingore this entry. */
605 continue;
608 /* If the current locale value is C (or POSIX) we don't load a
609 domain. Return the MSGID. */
610 if (strcmp (single_locale, "C") == 0
611 || strcmp (single_locale, "POSIX") == 0)
613 FREE_BLOCKS (block_list);
614 __libc_rwlock_unlock (_nl_state_lock);
615 __set_errno (saved_errno);
616 return (plural == 0
617 ? (char *) msgid1
618 /* Use the Germanic plural rule. */
619 : n == 1 ? (char *) msgid1 : (char *) msgid2);
623 /* Find structure describing the message catalog matching the
624 DOMAINNAME and CATEGORY. */
625 domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
627 if (domain != NULL)
629 retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
631 if (retval == NULL)
633 int cnt;
635 for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
637 retval = _nl_find_msg (domain->successor[cnt], binding,
638 msgid1, 1, &retlen);
640 if (retval != NULL)
642 domain = domain->successor[cnt];
643 break;
648 if (retval != NULL)
650 /* Found the translation of MSGID1 in domain DOMAIN:
651 starting at RETVAL, RETLEN bytes. */
652 FREE_BLOCKS (block_list);
653 #if defined HAVE_TSEARCH || defined _LIBC
654 if (foundp == NULL)
656 /* Create a new entry and add it to the search tree. */
657 size_t size;
658 struct known_translation_t *newp;
660 size = offsetof (struct known_translation_t, msgid)
661 + msgid_len + domainname_len + 1;
662 # ifdef HAVE_PER_THREAD_LOCALE
663 size += strlen (localename) + 1;
664 # endif
665 newp = (struct known_translation_t *) malloc (size);
666 if (newp != NULL)
668 char *new_domainname;
669 # ifdef HAVE_PER_THREAD_LOCALE
670 char *new_localename;
671 # endif
673 new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
674 memcpy (new_domainname, domainname, domainname_len + 1);
675 # ifdef HAVE_PER_THREAD_LOCALE
676 new_localename = new_domainname + domainname_len + 1;
677 strcpy (new_localename, localename);
678 # endif
679 newp->domainname = new_domainname;
680 newp->category = category;
681 # ifdef HAVE_PER_THREAD_LOCALE
682 newp->localename = new_localename;
683 # endif
684 newp->counter = _nl_msg_cat_cntr;
685 newp->domain = domain;
686 newp->translation = retval;
687 newp->translation_length = retlen;
689 __libc_rwlock_wrlock (tree_lock);
691 /* Insert the entry in the search tree. */
692 foundp = (struct known_translation_t **)
693 tsearch (newp, &root, transcmp);
695 __libc_rwlock_unlock (tree_lock);
697 if (foundp == NULL
698 || __builtin_expect (*foundp != newp, 0))
699 /* The insert failed. */
700 free (newp);
703 else
705 /* We can update the existing entry. */
706 (*foundp)->counter = _nl_msg_cat_cntr;
707 (*foundp)->domain = domain;
708 (*foundp)->translation = retval;
709 (*foundp)->translation_length = retlen;
711 #endif
712 __set_errno (saved_errno);
714 /* Now deal with plural. */
715 if (plural)
716 retval = plural_lookup (domain, n, retval, retlen);
718 __libc_rwlock_unlock (_nl_state_lock);
719 return retval;
723 /* NOTREACHED */
727 char *
728 internal_function
729 _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
730 struct loaded_l10nfile *domain_file;
731 struct binding *domainbinding;
732 const char *msgid;
733 int convert;
734 size_t *lengthp;
736 struct loaded_domain *domain;
737 nls_uint32 nstrings;
738 size_t act;
739 char *result;
740 size_t resultlen;
742 if (domain_file->decided <= 0)
743 _nl_load_domain (domain_file, domainbinding);
745 if (domain_file->data == NULL)
746 return NULL;
748 domain = (struct loaded_domain *) domain_file->data;
750 nstrings = domain->nstrings;
752 /* Locate the MSGID and its translation. */
753 if (domain->hash_tab != NULL)
755 /* Use the hashing table. */
756 nls_uint32 len = strlen (msgid);
757 nls_uint32 hash_val = __hash_string (msgid);
758 nls_uint32 idx = hash_val % domain->hash_size;
759 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
761 while (1)
763 nls_uint32 nstr =
764 W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
766 if (nstr == 0)
767 /* Hash table entry is empty. */
768 return NULL;
770 nstr--;
772 /* Compare msgid with the original string at index nstr.
773 We compare the lengths with >=, not ==, because plural entries
774 are represented by strings with an embedded NUL. */
775 if (nstr < nstrings
776 ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
777 && (strcmp (msgid,
778 domain->data + W (domain->must_swap,
779 domain->orig_tab[nstr].offset))
780 == 0)
781 : domain->orig_sysdep_tab[nstr - nstrings].length > len
782 && (strcmp (msgid,
783 domain->orig_sysdep_tab[nstr - nstrings].pointer)
784 == 0))
786 act = nstr;
787 goto found;
790 if (idx >= domain->hash_size - incr)
791 idx -= domain->hash_size - incr;
792 else
793 idx += incr;
795 /* NOTREACHED */
797 else
799 /* Try the default method: binary search in the sorted array of
800 messages. */
801 size_t top, bottom;
803 bottom = 0;
804 top = nstrings;
805 while (bottom < top)
807 int cmp_val;
809 act = (bottom + top) / 2;
810 cmp_val = strcmp (msgid, (domain->data
811 + W (domain->must_swap,
812 domain->orig_tab[act].offset)));
813 if (cmp_val < 0)
814 top = act;
815 else if (cmp_val > 0)
816 bottom = act + 1;
817 else
818 goto found;
820 /* No translation was found. */
821 return NULL;
824 found:
825 /* The translation was found at index ACT. If we have to convert the
826 string to use a different character set, this is the time. */
827 if (act < nstrings)
829 result = (char *)
830 (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
831 resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
833 else
835 result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
836 resultlen = domain->trans_sysdep_tab[act - nstrings].length;
839 #if defined _LIBC || HAVE_ICONV
840 if (convert)
842 /* We are supposed to do a conversion. */
843 const char *encoding = get_output_charset (domainbinding);
845 /* Search whether a table with converted translations for this
846 encoding has already been allocated. */
847 size_t nconversions = domain->nconversions;
848 struct converted_domain *convd = NULL;
849 size_t i;
851 for (i = nconversions; i > 0; )
853 i--;
854 if (strcmp (domain->conversions[i].encoding, encoding) == 0)
856 convd = &domain->conversions[i];
857 break;
861 if (convd == NULL)
863 /* Allocate a table for the converted translations for this
864 encoding. */
865 struct converted_domain *new_conversions =
866 (struct converted_domain *)
867 (domain->conversions != NULL
868 ? realloc (domain->conversions,
869 (nconversions + 1) * sizeof (struct converted_domain))
870 : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
872 if (__builtin_expect (new_conversions == NULL, 0))
873 /* Nothing we can do, no more memory. */
874 goto converted;
875 domain->conversions = new_conversions;
877 /* Copy the 'encoding' string to permanent storage. */
878 encoding = strdup (encoding);
879 if (__builtin_expect (encoding == NULL, 0))
880 /* Nothing we can do, no more memory. */
881 goto converted;
883 convd = &new_conversions[nconversions];
884 convd->encoding = encoding;
886 /* Find out about the character set the file is encoded with.
887 This can be found (in textual form) in the entry "". If this
888 entry does not exist or if this does not contain the 'charset='
889 information, we will assume the charset matches the one the
890 current locale and we don't have to perform any conversion. */
891 # ifdef _LIBC
892 convd->conv = (__gconv_t) -1;
893 # else
894 # if HAVE_ICONV
895 convd->conv = (iconv_t) -1;
896 # endif
897 # endif
899 char *nullentry;
900 size_t nullentrylen;
902 /* Get the header entry. This is a recursion, but it doesn't
903 reallocate domain->conversions because we pass convert = 0. */
904 nullentry =
905 _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
907 if (nullentry != NULL)
909 const char *charsetstr;
911 charsetstr = strstr (nullentry, "charset=");
912 if (charsetstr != NULL)
914 size_t len;
915 char *charset;
916 const char *outcharset;
918 charsetstr += strlen ("charset=");
919 len = strcspn (charsetstr, " \t\n");
921 charset = (char *) alloca (len + 1);
922 # if defined _LIBC || HAVE_MEMPCPY
923 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
924 # else
925 memcpy (charset, charsetstr, len);
926 charset[len] = '\0';
927 # endif
929 outcharset = encoding;
931 # ifdef _LIBC
932 /* We always want to use transliteration. */
933 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
934 charset = norm_add_slashes (charset, "");
935 if (__gconv_open (outcharset, charset, &convd->conv,
936 GCONV_AVOID_NOCONV)
937 != __GCONV_OK)
938 convd->conv = (__gconv_t) -1;
939 # else
940 # if HAVE_ICONV
941 /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
942 we want to use transliteration. */
943 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
944 || _LIBICONV_VERSION >= 0x0105
945 if (strchr (outcharset, '/') == NULL)
947 char *tmp;
949 len = strlen (outcharset);
950 tmp = (char *) alloca (len + 10 + 1);
951 memcpy (tmp, outcharset, len);
952 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
953 outcharset = tmp;
955 convd->conv = iconv_open (outcharset, charset);
957 freea (outcharset);
959 else
960 # endif
961 convd->conv = iconv_open (outcharset, charset);
962 # endif
963 # endif
965 freea (charset);
969 convd->conv_tab = NULL;
970 /* Here domain->conversions is still == new_conversions. */
971 domain->nconversions++;
974 if (
975 # ifdef _LIBC
976 convd->conv != (__gconv_t) -1
977 # else
978 # if HAVE_ICONV
979 convd->conv != (iconv_t) -1
980 # endif
981 # endif
984 /* We are supposed to do a conversion. First allocate an
985 appropriate table with the same structure as the table
986 of translations in the file, where we can put the pointers
987 to the converted strings in.
988 There is a slight complication with plural entries. They
989 are represented by consecutive NUL terminated strings. We
990 handle this case by converting RESULTLEN bytes, including
991 NULs. */
993 if (convd->conv_tab == NULL
994 && ((convd->conv_tab =
995 (char **) calloc (nstrings + domain->n_sysdep_strings,
996 sizeof (char *)))
997 == NULL))
998 /* Mark that we didn't succeed allocating a table. */
999 convd->conv_tab = (char **) -1;
1001 if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
1002 /* Nothing we can do, no more memory. */
1003 goto converted;
1005 if (convd->conv_tab[act] == NULL)
1007 /* We haven't used this string so far, so it is not
1008 translated yet. Do this now. */
1009 /* We use a bit more efficient memory handling.
1010 We allocate always larger blocks which get used over
1011 time. This is faster than many small allocations. */
1012 __libc_lock_define_initialized (static, lock)
1013 # define INITIAL_BLOCK_SIZE 4080
1014 static unsigned char *freemem;
1015 static size_t freemem_size;
1017 const unsigned char *inbuf;
1018 unsigned char *outbuf;
1019 int malloc_count;
1020 # ifndef _LIBC
1021 transmem_block_t *transmem_list = NULL;
1022 # endif
1024 __libc_lock_lock (lock);
1026 inbuf = (const unsigned char *) result;
1027 outbuf = freemem + sizeof (size_t);
1029 malloc_count = 0;
1030 while (1)
1032 transmem_block_t *newmem;
1033 # ifdef _LIBC
1034 size_t non_reversible;
1035 int res;
1037 if (freemem_size < sizeof (size_t))
1038 goto resize_freemem;
1040 res = __gconv (convd->conv,
1041 &inbuf, inbuf + resultlen,
1042 &outbuf,
1043 outbuf + freemem_size - sizeof (size_t),
1044 &non_reversible);
1046 if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
1047 break;
1049 if (res != __GCONV_FULL_OUTPUT)
1051 __libc_lock_unlock (lock);
1052 goto converted;
1055 inbuf = (const unsigned char *) result;
1056 # else
1057 # if HAVE_ICONV
1058 const char *inptr = (const char *) inbuf;
1059 size_t inleft = resultlen;
1060 char *outptr = (char *) outbuf;
1061 size_t outleft;
1063 if (freemem_size < sizeof (size_t))
1064 goto resize_freemem;
1066 outleft = freemem_size - sizeof (size_t);
1067 if (iconv (convd->conv,
1068 (ICONV_CONST char **) &inptr, &inleft,
1069 &outptr, &outleft)
1070 != (size_t) (-1))
1072 outbuf = (unsigned char *) outptr;
1073 break;
1075 if (errno != E2BIG)
1077 __libc_lock_unlock (lock);
1078 goto converted;
1080 # endif
1081 # endif
1083 resize_freemem:
1084 /* We must allocate a new buffer or resize the old one. */
1085 if (malloc_count > 0)
1087 ++malloc_count;
1088 freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
1089 newmem = (transmem_block_t *) realloc (transmem_list,
1090 freemem_size);
1091 # ifdef _LIBC
1092 if (newmem != NULL)
1093 transmem_list = transmem_list->next;
1094 else
1096 struct transmem_list *old = transmem_list;
1098 transmem_list = transmem_list->next;
1099 free (old);
1101 # endif
1103 else
1105 malloc_count = 1;
1106 freemem_size = INITIAL_BLOCK_SIZE;
1107 newmem = (transmem_block_t *) malloc (freemem_size);
1109 if (__builtin_expect (newmem == NULL, 0))
1111 freemem = NULL;
1112 freemem_size = 0;
1113 __libc_lock_unlock (lock);
1114 goto converted;
1117 # ifdef _LIBC
1118 /* Add the block to the list of blocks we have to free
1119 at some point. */
1120 newmem->next = transmem_list;
1121 transmem_list = newmem;
1123 freemem = (unsigned char *) newmem->data;
1124 freemem_size -= offsetof (struct transmem_list, data);
1125 # else
1126 transmem_list = newmem;
1127 freemem = newmem;
1128 # endif
1130 outbuf = freemem + sizeof (size_t);
1133 /* We have now in our buffer a converted string. Put this
1134 into the table of conversions. */
1135 *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1136 convd->conv_tab[act] = (char *) freemem;
1137 /* Shrink freemem, but keep it aligned. */
1138 freemem_size -= outbuf - freemem;
1139 freemem = outbuf;
1140 freemem += freemem_size & (alignof (size_t) - 1);
1141 freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1143 __libc_lock_unlock (lock);
1146 /* Now convd->conv_tab[act] contains the translation of all
1147 the plural variants. */
1148 result = convd->conv_tab[act] + sizeof (size_t);
1149 resultlen = *(size_t *) convd->conv_tab[act];
1153 converted:
1154 /* The result string is converted. */
1156 #endif /* _LIBC || HAVE_ICONV */
1158 *lengthp = resultlen;
1159 return result;
1163 /* Look up a plural variant. */
1164 static char *
1165 internal_function
1166 plural_lookup (domain, n, translation, translation_len)
1167 struct loaded_l10nfile *domain;
1168 unsigned long int n;
1169 const char *translation;
1170 size_t translation_len;
1172 struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1173 unsigned long int index;
1174 const char *p;
1176 index = plural_eval (domaindata->plural, n);
1177 if (index >= domaindata->nplurals)
1178 /* This should never happen. It means the plural expression and the
1179 given maximum value do not match. */
1180 index = 0;
1182 /* Skip INDEX strings at TRANSLATION. */
1183 p = translation;
1184 while (index-- > 0)
1186 #ifdef _LIBC
1187 p = __rawmemchr (p, '\0');
1188 #else
1189 p = strchr (p, '\0');
1190 #endif
1191 /* And skip over the NUL byte. */
1192 p++;
1194 if (p >= translation + translation_len)
1195 /* This should never happen. It means the plural expression
1196 evaluated to a value larger than the number of variants
1197 available for MSGID1. */
1198 return (char *) translation;
1200 return (char *) p;
1203 #ifndef _LIBC
1204 /* Return string representation of locale CATEGORY. */
1205 static const char *
1206 internal_function
1207 category_to_name (category)
1208 int category;
1210 const char *retval;
1212 switch (category)
1214 #ifdef LC_COLLATE
1215 case LC_COLLATE:
1216 retval = "LC_COLLATE";
1217 break;
1218 #endif
1219 #ifdef LC_CTYPE
1220 case LC_CTYPE:
1221 retval = "LC_CTYPE";
1222 break;
1223 #endif
1224 #ifdef LC_MONETARY
1225 case LC_MONETARY:
1226 retval = "LC_MONETARY";
1227 break;
1228 #endif
1229 #ifdef LC_NUMERIC
1230 case LC_NUMERIC:
1231 retval = "LC_NUMERIC";
1232 break;
1233 #endif
1234 #ifdef LC_TIME
1235 case LC_TIME:
1236 retval = "LC_TIME";
1237 break;
1238 #endif
1239 #ifdef LC_MESSAGES
1240 case LC_MESSAGES:
1241 retval = "LC_MESSAGES";
1242 break;
1243 #endif
1244 #ifdef LC_RESPONSE
1245 case LC_RESPONSE:
1246 retval = "LC_RESPONSE";
1247 break;
1248 #endif
1249 #ifdef LC_ALL
1250 case LC_ALL:
1251 /* This might not make sense but is perhaps better than any other
1252 value. */
1253 retval = "LC_ALL";
1254 break;
1255 #endif
1256 default:
1257 /* If you have a better idea for a default value let me know. */
1258 retval = "LC_XXX";
1261 return retval;
1263 #endif
1265 /* Guess value of current locale from value of the environment variables. */
1266 static const char *
1267 internal_function
1268 guess_category_value (category, categoryname)
1269 int category;
1270 const char *categoryname;
1272 const char *language;
1273 const char *retval;
1275 /* The highest priority value is the `LANGUAGE' environment
1276 variable. But we don't use the value if the currently selected
1277 locale is the C locale. This is a GNU extension. */
1278 language = getenv ("LANGUAGE");
1279 if (language != NULL && language[0] == '\0')
1280 language = NULL;
1282 /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1283 `LC_xxx', and `LANG'. On some systems this can be done by the
1284 `setlocale' function itself. */
1285 #ifdef _LIBC
1286 retval = __current_locale_name (category);
1287 #else
1288 retval = _nl_locale_name (category, categoryname);
1289 #endif
1291 return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1294 #if defined _LIBC || HAVE_ICONV
1295 /* Returns the output charset. */
1296 static const char *
1297 internal_function
1298 get_output_charset (domainbinding)
1299 struct binding *domainbinding;
1301 /* The output charset should normally be determined by the locale. But
1302 sometimes the locale is not used or not correctly set up, so we provide
1303 a possibility for the user to override this: the OUTPUT_CHARSET
1304 environment variable. Moreover, the value specified through
1305 bind_textdomain_codeset overrides both. */
1306 if (domainbinding != NULL && domainbinding->codeset != NULL)
1307 return domainbinding->codeset;
1308 else
1310 /* For speed reasons, we look at the value of OUTPUT_CHARSET only
1311 once. This is a user variable that is not supposed to change
1312 during a program run. */
1313 static char *output_charset_cache;
1314 static int output_charset_cached;
1316 if (!output_charset_cached)
1318 const char *value = getenv ("OUTPUT_CHARSET");
1320 if (value != NULL && value[0] != '\0')
1322 size_t len = strlen (value) + 1;
1323 char *value_copy = (char *) malloc (len);
1325 if (value_copy != NULL)
1326 memcpy (value_copy, value, len);
1327 output_charset_cache = value_copy;
1329 output_charset_cached = 1;
1332 if (output_charset_cache != NULL)
1333 return output_charset_cache;
1334 else
1336 # ifdef _LIBC
1337 return _NL_CURRENT (LC_CTYPE, CODESET);
1338 # else
1339 # if HAVE_ICONV
1340 extern const char *locale_charset PARAMS ((void);
1341 return locale_charset ();
1342 # endif
1343 # endif
1347 #endif
1349 /* @@ begin of epilog @@ */
1351 /* We don't want libintl.a to depend on any other library. So we
1352 avoid the non-standard function stpcpy. In GNU C Library this
1353 function is available, though. Also allow the symbol HAVE_STPCPY
1354 to be defined. */
1355 #if !_LIBC && !HAVE_STPCPY
1356 static char *
1357 stpcpy (dest, src)
1358 char *dest;
1359 const char *src;
1361 while ((*dest++ = *src++) != '\0')
1362 /* Do nothing. */ ;
1363 return dest - 1;
1365 #endif
1367 #if !_LIBC && !HAVE_MEMPCPY
1368 static void *
1369 mempcpy (dest, src, n)
1370 void *dest;
1371 const void *src;
1372 size_t n;
1374 return (void *) ((char *) memcpy (dest, src, n) + n);
1376 #endif
1379 #ifdef _LIBC
1380 /* If we want to free all resources we have to do some work at
1381 program's end. */
1382 libc_freeres_fn (free_mem)
1384 void *old;
1386 while (_nl_domain_bindings != NULL)
1388 struct binding *oldp = _nl_domain_bindings;
1389 _nl_domain_bindings = _nl_domain_bindings->next;
1390 if (oldp->dirname != _nl_default_dirname)
1391 /* Yes, this is a pointer comparison. */
1392 free (oldp->dirname);
1393 free (oldp->codeset);
1394 free (oldp);
1397 if (_nl_current_default_domain != _nl_default_default_domain)
1398 /* Yes, again a pointer comparison. */
1399 free ((char *) _nl_current_default_domain);
1401 /* Remove the search tree with the known translations. */
1402 __tdestroy (root, free);
1403 root = NULL;
1405 while (transmem_list != NULL)
1407 old = transmem_list;
1408 transmem_list = transmem_list->next;
1409 free (old);
1412 #endif