* config/arm/elf.h (ASM_OUTPUT_ALIGNED_COMMON): Remove definition.
[official-gcc.git] / gcc / intl / dcigettext.c
blobf829bd3e4d93833629cb55905e18d62951e0cfe1
1 /* Implementation of the internal dcigettext function.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
7 any later version.
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 GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA. */
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
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <sys/types.h>
32 #ifdef __GNUC__
33 # define alloca __builtin_alloca
34 # define HAVE_ALLOCA 1
35 #else
36 # if defined HAVE_ALLOCA_H || defined _LIBC
37 # include <alloca.h>
38 # else
39 # ifdef _AIX
40 #pragma alloca
41 # else
42 # ifndef alloca
43 char *alloca ();
44 # endif
45 # endif
46 # endif
47 #endif
49 #include <errno.h>
50 #ifndef errno
51 extern int errno;
52 #endif
53 #ifndef __set_errno
54 # define __set_errno(val) errno = (val)
55 #endif
57 #include <stddef.h>
58 #include <stdlib.h>
60 #include <string.h>
61 #if !HAVE_STRCHR && !defined _LIBC
62 # ifndef strchr
63 # define strchr index
64 # endif
65 #endif
67 #if defined HAVE_UNISTD_H || defined _LIBC
68 # include <unistd.h>
69 #endif
71 #include <locale.h>
73 #if defined HAVE_SYS_PARAM_H || defined _LIBC
74 # include <sys/param.h>
75 #endif
77 #include "gettextP.h"
78 #ifdef _LIBC
79 # include <libintl.h>
80 #else
81 # include "libgnuintl.h"
82 #endif
83 #include "hash-string.h"
85 /* Thread safetyness. */
86 #ifdef _LIBC
87 # include <bits/libc-lock.h>
88 #else
89 /* Provide dummy implementation if this is outside glibc. */
90 # define __libc_lock_define_initialized(CLASS, NAME)
91 # define __libc_lock_lock(NAME)
92 # define __libc_lock_unlock(NAME)
93 # define __libc_rwlock_define_initialized(CLASS, NAME)
94 # define __libc_rwlock_rdlock(NAME)
95 # define __libc_rwlock_unlock(NAME)
96 #endif
98 /* Alignment of types. */
99 #if defined __GNUC__ && __GNUC__ >= 2
100 # define alignof(TYPE) __alignof__ (TYPE)
101 #else
102 # define alignof(TYPE) \
103 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
104 #endif
106 /* The internal variables in the standalone libintl.a must have different
107 names than the internal variables in GNU libc, otherwise programs
108 using libintl.a cannot be linked statically. */
109 #if !defined _LIBC
110 # define _nl_default_default_domain _nl_default_default_domain__
111 # define _nl_current_default_domain _nl_current_default_domain__
112 # define _nl_default_dirname _nl_default_dirname__
113 # define _nl_domain_bindings _nl_domain_bindings__
114 #endif
116 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
117 #ifndef offsetof
118 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
119 #endif
121 /* @@ end of prolog @@ */
123 #ifdef _LIBC
124 /* Rename the non ANSI C functions. This is required by the standard
125 because some ANSI C functions will require linking with this object
126 file and the name space must not be polluted.
127 GCC LOCAL: Don't use #elif. */
128 # define getcwd __getcwd
129 # ifndef stpcpy
130 # define stpcpy __stpcpy
131 # endif
132 # define tfind __tfind
133 #else
134 # if !defined HAVE_GETCWD
135 char *getwd ();
136 # define getcwd(buf, max) getwd (buf)
137 # else
138 # if !defined HAVE_DECL_GETCWD
139 char *getcwd ();
140 # endif
141 # endif
142 # ifndef HAVE_STPCPY
143 static char *stpcpy PARAMS ((char *dest, const char *src));
144 # endif
145 # ifndef HAVE_MEMPCPY
146 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
147 # endif
148 #endif
150 /* Amount to increase buffer size by in each try. */
151 #define PATH_INCR 32
153 /* The following is from pathmax.h. */
154 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
155 PATH_MAX but might cause redefinition warnings when sys/param.h is
156 later included (as on MORE/BSD 4.3). */
157 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
158 # include <limits.h>
159 #endif
161 #ifndef _POSIX_PATH_MAX
162 # define _POSIX_PATH_MAX 255
163 #endif
165 #if !defined PATH_MAX && defined _PC_PATH_MAX
166 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
167 #endif
169 /* Don't include sys/param.h if it already has been. */
170 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
171 # include <sys/param.h>
172 #endif
174 #if !defined PATH_MAX && defined MAXPATHLEN
175 # define PATH_MAX MAXPATHLEN
176 #endif
178 #ifndef PATH_MAX
179 # define PATH_MAX _POSIX_PATH_MAX
180 #endif
182 /* Pathname support.
183 ISSLASH(C) tests whether C is a directory separator character.
184 IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
185 it may be concatenated to a directory pathname.
186 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
188 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
189 /* Win32, OS/2, DOS */
190 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
191 # define HAS_DEVICE(P) \
192 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
193 && (P)[1] == ':')
194 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
195 # define IS_PATH_WITH_DIR(P) \
196 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
197 #else
198 /* Unix */
199 # define ISSLASH(C) ((C) == '/')
200 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
201 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
202 #endif
204 /* XPG3 defines the result of `setlocale (category, NULL)' as:
205 ``Directs `setlocale()' to query `category' and return the current
206 setting of `local'.''
207 However it does not specify the exact format. Neither do SUSV2 and
208 ISO C 99. So we can use this feature only on selected systems (e.g.
209 those using GNU C Library). */
210 #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
211 # define HAVE_LOCALE_NULL
212 #endif
214 /* This is the type used for the search tree where known translations
215 are stored. */
216 struct known_translation_t
218 /* Domain in which to search. */
219 char *domainname;
221 /* The category. */
222 int category;
224 /* State of the catalog counter at the point the string was found. */
225 int counter;
227 /* Catalog where the string was found. */
228 struct loaded_l10nfile *domain;
230 /* And finally the translation. */
231 const char *translation;
232 size_t translation_length;
234 /* Pointer to the string in question. */
235 char msgid[ZERO];
238 /* Root of the search tree with known translations. We can use this
239 only if the system provides the `tsearch' function family. */
240 #if defined HAVE_TSEARCH || defined _LIBC
241 # include <search.h>
243 static void *root;
245 # ifdef _LIBC
246 # define tsearch __tsearch
247 # endif
249 /* Function to compare two entries in the table of known translations. */
250 static int transcmp PARAMS ((const void *p1, const void *p2));
251 static int
252 transcmp (p1, p2)
253 const void *p1;
254 const void *p2;
256 const struct known_translation_t *s1;
257 const struct known_translation_t *s2;
258 int result;
260 s1 = (const struct known_translation_t *) p1;
261 s2 = (const struct known_translation_t *) p2;
263 result = strcmp (s1->msgid, s2->msgid);
264 if (result == 0)
266 result = strcmp (s1->domainname, s2->domainname);
267 if (result == 0)
268 /* We compare the category last (though this is the cheapest
269 operation) since it is hopefully always the same (namely
270 LC_MESSAGES). */
271 result = s1->category - s2->category;
274 return result;
276 #endif
278 /* Name of the default domain used for gettext(3) prior any call to
279 textdomain(3). The default value for this is "messages". */
280 const char _nl_default_default_domain[] = "messages";
282 /* Value used as the default domain for gettext(3). */
283 const char *_nl_current_default_domain = _nl_default_default_domain;
285 /* Contains the default location of the message catalogs. */
286 const char _nl_default_dirname[] = LOCALEDIR;
288 /* List with bindings of specific domains created by bindtextdomain()
289 calls. */
290 struct binding *_nl_domain_bindings;
292 /* Prototypes for local functions. */
293 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
294 unsigned long int n,
295 const char *translation,
296 size_t translation_len))
297 internal_function;
298 static unsigned long int plural_eval PARAMS ((struct expression *pexp,
299 unsigned long int n))
300 internal_function;
301 static const char *category_to_name PARAMS ((int category)) internal_function;
302 static const char *guess_category_value PARAMS ((int category,
303 const char *categoryname))
304 internal_function;
307 /* For those loosing systems which don't have `alloca' we have to add
308 some additional code emulating it. */
309 #ifdef HAVE_ALLOCA
310 /* Nothing has to be done. */
311 # define ADD_BLOCK(list, address) /* nothing */
312 # define FREE_BLOCKS(list) /* nothing */
313 #else
314 struct block_list
316 void *address;
317 struct block_list *next;
319 # define ADD_BLOCK(list, addr) \
320 do { \
321 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
322 /* If we cannot get a free block we cannot add the new element to \
323 the list. */ \
324 if (newp != NULL) { \
325 newp->address = (addr); \
326 newp->next = (list); \
327 (list) = newp; \
329 } while (0)
330 # define FREE_BLOCKS(list) \
331 do { \
332 while (list != NULL) { \
333 struct block_list *old = list; \
334 list = list->next; \
335 free (old); \
337 } while (0)
338 # undef alloca
339 # define alloca(size) (malloc (size))
340 #endif /* have alloca */
343 #ifdef _LIBC
344 /* List of blocks allocated for translations. */
345 typedef struct transmem_list
347 struct transmem_list *next;
348 char data[ZERO];
349 } transmem_block_t;
350 static struct transmem_list *transmem_list;
351 #else
352 typedef unsigned char transmem_block_t;
353 #endif
356 /* Names for the libintl functions are a problem. They must not clash
357 with existing names and they should follow ANSI C. But this source
358 code is also used in GNU C Library where the names have a __
359 prefix. So we have to make a difference here. */
360 #ifdef _LIBC
361 # define DCIGETTEXT __dcigettext
362 #else
363 # define DCIGETTEXT dcigettext__
364 #endif
366 /* Lock variable to protect the global data in the gettext implementation. */
367 #ifdef _LIBC
368 __libc_rwlock_define_initialized (, _nl_state_lock)
369 #endif
371 /* Checking whether the binaries runs SUID must be done and glibc provides
372 easier methods therefore we make a difference here. */
373 #ifdef _LIBC
374 # define ENABLE_SECURE __libc_enable_secure
375 # define DETERMINE_SECURE
376 #else
377 # ifndef HAVE_GETUID
378 # define getuid() 0
379 # endif
380 # ifndef HAVE_GETGID
381 # define getgid() 0
382 # endif
383 # ifndef HAVE_GETEUID
384 # define geteuid() getuid()
385 # endif
386 # ifndef HAVE_GETEGID
387 # define getegid() getgid()
388 # endif
389 static int enable_secure;
390 # define ENABLE_SECURE (enable_secure == 1)
391 # define DETERMINE_SECURE \
392 if (enable_secure == 0) \
394 if (getuid () != geteuid () || getgid () != getegid ()) \
395 enable_secure = 1; \
396 else \
397 enable_secure = -1; \
399 #endif
401 /* Look up MSGID in the DOMAINNAME message catalog for the current
402 CATEGORY locale and, if PLURAL is nonzero, search over string
403 depending on the plural form determined by N. */
404 char *
405 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
406 const char *domainname;
407 const char *msgid1;
408 const char *msgid2;
409 int plural;
410 unsigned long int n;
411 int category;
413 #ifndef HAVE_ALLOCA
414 struct block_list *block_list = NULL;
415 #endif
416 struct loaded_l10nfile *domain;
417 struct binding *binding;
418 const char *categoryname;
419 const char *categoryvalue;
420 char *dirname, *xdomainname;
421 char *single_locale;
422 char *retval;
423 size_t retlen;
424 int saved_errno;
425 #if defined HAVE_TSEARCH || defined _LIBC
426 struct known_translation_t *search;
427 struct known_translation_t **foundp = NULL;
428 size_t msgid_len;
429 #endif
430 size_t domainname_len;
432 /* If no real MSGID is given return NULL. */
433 if (msgid1 == NULL)
434 return NULL;
436 __libc_rwlock_rdlock (_nl_state_lock);
438 /* If DOMAINNAME is NULL, we are interested in the default domain. If
439 CATEGORY is not LC_MESSAGES this might not make much sense but the
440 definition left this undefined. */
441 if (domainname == NULL)
442 domainname = _nl_current_default_domain;
444 #if defined HAVE_TSEARCH || defined _LIBC
445 msgid_len = strlen (msgid1) + 1;
447 /* Try to find the translation among those which we found at
448 some time. */
449 search = (struct known_translation_t *)
450 alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
451 memcpy (search->msgid, msgid1, msgid_len);
452 search->domainname = (char *) domainname;
453 search->category = category;
455 foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
456 if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
458 /* Now deal with plural. */
459 if (plural)
460 retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
461 (*foundp)->translation_length);
462 else
463 retval = (char *) (*foundp)->translation;
465 __libc_rwlock_unlock (_nl_state_lock);
466 return retval;
468 #endif
470 /* Preserve the `errno' value. */
471 saved_errno = errno;
473 /* See whether this is a SUID binary or not. */
474 DETERMINE_SECURE;
476 /* First find matching binding. */
477 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
479 int compare = strcmp (domainname, binding->domainname);
480 if (compare == 0)
481 /* We found it! */
482 break;
483 if (compare < 0)
485 /* It is not in the list. */
486 binding = NULL;
487 break;
491 if (binding == NULL)
492 dirname = (char *) _nl_default_dirname;
493 else if (IS_ABSOLUTE_PATH (binding->dirname))
494 dirname = binding->dirname;
495 else
497 /* We have a relative path. Make it absolute now. */
498 size_t dirname_len = strlen (binding->dirname) + 1;
499 size_t path_max;
500 char *ret;
502 path_max = (unsigned int) PATH_MAX;
503 path_max += 2; /* The getcwd docs say to do this. */
505 for (;;)
507 dirname = (char *) alloca (path_max + dirname_len);
508 ADD_BLOCK (block_list, dirname);
510 __set_errno (0);
511 ret = getcwd (dirname, path_max);
512 if (ret != NULL || errno != ERANGE)
513 break;
515 path_max += path_max / 2;
516 path_max += PATH_INCR;
519 if (ret == NULL)
521 /* We cannot get the current working directory. Don't signal an
522 error but simply return the default string. */
523 FREE_BLOCKS (block_list);
524 __libc_rwlock_unlock (_nl_state_lock);
525 __set_errno (saved_errno);
526 return (plural == 0
527 ? (char *) msgid1
528 /* Use the Germanic plural rule. */
529 : n == 1 ? (char *) msgid1 : (char *) msgid2);
532 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
535 /* Now determine the symbolic name of CATEGORY and its value. */
536 categoryname = category_to_name (category);
537 categoryvalue = guess_category_value (category, categoryname);
539 domainname_len = strlen (domainname);
540 xdomainname = (char *) alloca (strlen (categoryname)
541 + domainname_len + 5);
542 ADD_BLOCK (block_list, xdomainname);
544 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
545 domainname, domainname_len),
546 ".mo");
548 /* Creating working area. */
549 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
550 ADD_BLOCK (block_list, single_locale);
553 /* Search for the given string. This is a loop because we perhaps
554 got an ordered list of languages to consider for the translation. */
555 while (1)
557 /* Make CATEGORYVALUE point to the next element of the list. */
558 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
559 ++categoryvalue;
560 if (categoryvalue[0] == '\0')
562 /* The whole contents of CATEGORYVALUE has been searched but
563 no valid entry has been found. We solve this situation
564 by implicitly appending a "C" entry, i.e. no translation
565 will take place. */
566 single_locale[0] = 'C';
567 single_locale[1] = '\0';
569 else
571 char *cp = single_locale;
572 while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
573 *cp++ = *categoryvalue++;
574 *cp = '\0';
576 /* When this is a SUID binary we must not allow accessing files
577 outside the dedicated directories. */
578 if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
579 /* Ingore this entry. */
580 continue;
583 /* If the current locale value is C (or POSIX) we don't load a
584 domain. Return the MSGID. */
585 if (strcmp (single_locale, "C") == 0
586 || strcmp (single_locale, "POSIX") == 0)
588 FREE_BLOCKS (block_list);
589 __libc_rwlock_unlock (_nl_state_lock);
590 __set_errno (saved_errno);
591 return (plural == 0
592 ? (char *) msgid1
593 /* Use the Germanic plural rule. */
594 : n == 1 ? (char *) msgid1 : (char *) msgid2);
598 /* Find structure describing the message catalog matching the
599 DOMAINNAME and CATEGORY. */
600 domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
602 if (domain != NULL)
604 retval = _nl_find_msg (domain, binding, msgid1, &retlen);
606 if (retval == NULL)
608 int cnt;
610 for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
612 retval = _nl_find_msg (domain->successor[cnt], binding,
613 msgid1, &retlen);
615 if (retval != NULL)
617 domain = domain->successor[cnt];
618 break;
623 if (retval != NULL)
625 /* Found the translation of MSGID1 in domain DOMAIN:
626 starting at RETVAL, RETLEN bytes. */
627 FREE_BLOCKS (block_list);
628 __set_errno (saved_errno);
629 #if defined HAVE_TSEARCH || defined _LIBC
630 if (foundp == NULL)
632 /* Create a new entry and add it to the search tree. */
633 struct known_translation_t *newp;
635 newp = (struct known_translation_t *)
636 malloc (offsetof (struct known_translation_t, msgid)
637 + msgid_len + domainname_len + 1);
638 if (newp != NULL)
640 newp->domainname =
641 mempcpy (newp->msgid, msgid1, msgid_len);
642 memcpy (newp->domainname, domainname, domainname_len + 1);
643 newp->category = category;
644 newp->counter = _nl_msg_cat_cntr;
645 newp->domain = domain;
646 newp->translation = retval;
647 newp->translation_length = retlen;
649 /* Insert the entry in the search tree. */
650 foundp = (struct known_translation_t **)
651 tsearch (newp, &root, transcmp);
652 if (foundp == NULL
653 || __builtin_expect (*foundp != newp, 0))
654 /* The insert failed. */
655 free (newp);
658 else
660 /* We can update the existing entry. */
661 (*foundp)->counter = _nl_msg_cat_cntr;
662 (*foundp)->domain = domain;
663 (*foundp)->translation = retval;
664 (*foundp)->translation_length = retlen;
666 #endif
667 /* Now deal with plural. */
668 if (plural)
669 retval = plural_lookup (domain, n, retval, retlen);
671 __libc_rwlock_unlock (_nl_state_lock);
672 return retval;
676 /* NOTREACHED */
680 char *
681 internal_function
682 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
683 struct loaded_l10nfile *domain_file;
684 struct binding *domainbinding;
685 const char *msgid;
686 size_t *lengthp;
688 struct loaded_domain *domain;
689 size_t act;
690 char *result;
691 size_t resultlen;
693 if (domain_file->decided == 0)
694 _nl_load_domain (domain_file, domainbinding);
696 if (domain_file->data == NULL)
697 return NULL;
699 domain = (struct loaded_domain *) domain_file->data;
701 /* Locate the MSGID and its translation. */
702 if (domain->hash_size > 2 && domain->hash_tab != NULL)
704 /* Use the hashing table. */
705 nls_uint32 len = strlen (msgid);
706 nls_uint32 hash_val = hash_string (msgid);
707 nls_uint32 idx = hash_val % domain->hash_size;
708 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
710 while (1)
712 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
714 if (nstr == 0)
715 /* Hash table entry is empty. */
716 return NULL;
718 /* Compare msgid with the original string at index nstr-1.
719 We compare the lengths with >=, not ==, because plural entries
720 are represented by strings with an embedded NUL. */
721 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
722 && (strcmp (msgid,
723 domain->data + W (domain->must_swap,
724 domain->orig_tab[nstr - 1].offset))
725 == 0))
727 act = nstr - 1;
728 goto found;
731 if (idx >= domain->hash_size - incr)
732 idx -= domain->hash_size - incr;
733 else
734 idx += incr;
736 /* NOTREACHED */
738 else
740 /* Try the default method: binary search in the sorted array of
741 messages. */
742 size_t top, bottom;
744 bottom = 0;
745 act = 0;
746 top = domain->nstrings;
747 while (bottom < top)
749 int cmp_val;
751 act = (bottom + top) / 2;
752 cmp_val = strcmp (msgid, (domain->data
753 + W (domain->must_swap,
754 domain->orig_tab[act].offset)));
755 if (cmp_val < 0)
756 top = act;
757 else if (cmp_val > 0)
758 bottom = act + 1;
759 else
760 goto found;
762 /* No translation was found. */
763 return NULL;
766 found:
767 /* The translation was found at index ACT. If we have to convert the
768 string to use a different character set, this is the time. */
769 result = ((char *) domain->data
770 + W (domain->must_swap, domain->trans_tab[act].offset));
771 resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
773 #if defined _LIBC || HAVE_ICONV
774 if (domain->codeset_cntr
775 != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
777 /* The domain's codeset has changed through bind_textdomain_codeset()
778 since the message catalog was initialized or last accessed. We
779 have to reinitialize the converter. */
780 _nl_free_domain_conv (domain);
781 _nl_init_domain_conv (domain_file, domain, domainbinding);
784 if (
785 # ifdef _LIBC
786 domain->conv != (__gconv_t) -1
787 # else
788 # if HAVE_ICONV
789 domain->conv != (iconv_t) -1
790 # endif
791 # endif
794 /* We are supposed to do a conversion. First allocate an
795 appropriate table with the same structure as the table
796 of translations in the file, where we can put the pointers
797 to the converted strings in.
798 There is a slight complication with plural entries. They
799 are represented by consecutive NUL terminated strings. We
800 handle this case by converting RESULTLEN bytes, including
801 NULs. */
803 if (domain->conv_tab == NULL
804 && ((domain->conv_tab = (char **) calloc (domain->nstrings,
805 sizeof (char *)))
806 == NULL))
807 /* Mark that we didn't succeed allocating a table. */
808 domain->conv_tab = (char **) -1;
810 if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
811 /* Nothing we can do, no more memory. */
812 goto converted;
814 if (domain->conv_tab[act] == NULL)
816 /* We haven't used this string so far, so it is not
817 translated yet. Do this now. */
818 /* We use a bit more efficient memory handling.
819 We allocate always larger blocks which get used over
820 time. This is faster than many small allocations. */
821 __libc_lock_define_initialized (static, lock)
822 # define INITIAL_BLOCK_SIZE 4080
823 static unsigned char *freemem;
824 static size_t freemem_size;
826 const unsigned char *inbuf;
827 unsigned char *outbuf;
828 int malloc_count;
829 # ifndef _LIBC
830 transmem_block_t *transmem_list = NULL;
831 # endif
833 __libc_lock_lock (lock);
835 inbuf = (const unsigned char *) result;
836 outbuf = freemem + sizeof (size_t);
838 malloc_count = 0;
839 while (1)
841 transmem_block_t *newmem;
842 # ifdef _LIBC
843 size_t non_reversible;
844 int res;
846 if (freemem_size < sizeof (size_t))
847 goto resize_freemem;
849 res = __gconv (domain->conv,
850 &inbuf, inbuf + resultlen,
851 &outbuf,
852 outbuf + freemem_size - sizeof (size_t),
853 &non_reversible);
855 if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
856 break;
858 if (res != __GCONV_FULL_OUTPUT)
860 __libc_lock_unlock (lock);
861 goto converted;
864 inbuf = result;
865 # else
866 # if HAVE_ICONV
867 const char *inptr = (const char *) inbuf;
868 size_t inleft = resultlen;
869 char *outptr = (char *) outbuf;
870 size_t outleft;
872 if (freemem_size < sizeof (size_t))
873 goto resize_freemem;
875 outleft = freemem_size - sizeof (size_t);
876 if (iconv (domain->conv,
877 (ICONV_CONST char **) &inptr, &inleft,
878 &outptr, &outleft)
879 != (size_t) (-1))
881 outbuf = (unsigned char *) outptr;
882 break;
884 if (errno != E2BIG)
886 __libc_lock_unlock (lock);
887 goto converted;
889 # endif
890 # endif
892 resize_freemem:
893 /* We must allocate a new buffer or resize the old one. */
894 if (malloc_count > 0)
896 ++malloc_count;
897 freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
898 newmem = (transmem_block_t *) realloc (transmem_list,
899 freemem_size);
900 # ifdef _LIBC
901 if (newmem != NULL)
902 transmem_list = transmem_list->next;
903 else
905 struct transmem_list *old = transmem_list;
907 transmem_list = transmem_list->next;
908 free (old);
910 # endif
912 else
914 malloc_count = 1;
915 freemem_size = INITIAL_BLOCK_SIZE;
916 newmem = (transmem_block_t *) malloc (freemem_size);
918 if (__builtin_expect (newmem == NULL, 0))
920 freemem = NULL;
921 freemem_size = 0;
922 __libc_lock_unlock (lock);
923 goto converted;
926 # ifdef _LIBC
927 /* Add the block to the list of blocks we have to free
928 at some point. */
929 newmem->next = transmem_list;
930 transmem_list = newmem;
932 freemem = newmem->data;
933 freemem_size -= offsetof (struct transmem_list, data);
934 # else
935 transmem_list = newmem;
936 freemem = newmem;
937 # endif
939 outbuf = freemem + sizeof (size_t);
942 /* We have now in our buffer a converted string. Put this
943 into the table of conversions. */
944 *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
945 domain->conv_tab[act] = (char *) freemem;
946 /* Shrink freemem, but keep it aligned. */
947 freemem_size -= outbuf - freemem;
948 freemem = outbuf;
949 freemem += freemem_size & (alignof (size_t) - 1);
950 freemem_size = freemem_size & ~ (alignof (size_t) - 1);
952 __libc_lock_unlock (lock);
955 /* Now domain->conv_tab[act] contains the translation of all
956 the plural variants. */
957 result = domain->conv_tab[act] + sizeof (size_t);
958 resultlen = *(size_t *) domain->conv_tab[act];
961 converted:
962 /* The result string is converted. */
964 #endif /* _LIBC || HAVE_ICONV */
966 *lengthp = resultlen;
967 return result;
971 /* Look up a plural variant. */
972 static char *
973 internal_function
974 plural_lookup (domain, n, translation, translation_len)
975 struct loaded_l10nfile *domain;
976 unsigned long int n;
977 const char *translation;
978 size_t translation_len;
980 struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
981 unsigned long int index;
982 const char *p;
984 index = plural_eval (domaindata->plural, n);
985 if (index >= domaindata->nplurals)
986 /* This should never happen. It means the plural expression and the
987 given maximum value do not match. */
988 index = 0;
990 /* Skip INDEX strings at TRANSLATION. */
991 p = translation;
992 while (index-- > 0)
994 #ifdef _LIBC
995 p = __rawmemchr (p, '\0');
996 #else
997 p = strchr (p, '\0');
998 #endif
999 /* And skip over the NUL byte. */
1000 p++;
1002 if (p >= translation + translation_len)
1003 /* This should never happen. It means the plural expression
1004 evaluated to a value larger than the number of variants
1005 available for MSGID1. */
1006 return (char *) translation;
1008 return (char *) p;
1012 /* Function to evaluate the plural expression and return an index value. */
1013 static unsigned long int
1014 internal_function
1015 plural_eval (pexp, n)
1016 struct expression *pexp;
1017 unsigned long int n;
1019 switch (pexp->nargs)
1021 case 0:
1022 switch (pexp->operation)
1024 case var:
1025 return n;
1026 case num:
1027 return pexp->val.num;
1028 default:
1029 break;
1031 /* NOTREACHED */
1032 break;
1033 case 1:
1035 /* pexp->operation must be lnot. */
1036 unsigned long int arg = plural_eval (pexp->val.args[0], n);
1037 return ! arg;
1039 case 2:
1041 unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
1042 if (pexp->operation == lor)
1043 return leftarg || plural_eval (pexp->val.args[1], n);
1044 else if (pexp->operation == land)
1045 return leftarg && plural_eval (pexp->val.args[1], n);
1046 else
1048 unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
1050 switch (pexp->operation)
1052 case mult:
1053 return leftarg * rightarg;
1054 case divide:
1055 return leftarg / rightarg;
1056 case module:
1057 return leftarg % rightarg;
1058 case plus:
1059 return leftarg + rightarg;
1060 case minus:
1061 return leftarg - rightarg;
1062 case less_than:
1063 return leftarg < rightarg;
1064 case greater_than:
1065 return leftarg > rightarg;
1066 case less_or_equal:
1067 return leftarg <= rightarg;
1068 case greater_or_equal:
1069 return leftarg >= rightarg;
1070 case equal:
1071 return leftarg == rightarg;
1072 case not_equal:
1073 return leftarg != rightarg;
1074 default:
1075 break;
1078 /* NOTREACHED */
1079 break;
1081 case 3:
1083 /* pexp->operation must be qmop. */
1084 unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
1085 return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
1088 /* NOTREACHED */
1089 return 0;
1093 /* Return string representation of locale CATEGORY. */
1094 static const char *
1095 internal_function
1096 category_to_name (category)
1097 int category;
1099 const char *retval;
1101 switch (category)
1103 #ifdef LC_COLLATE
1104 case LC_COLLATE:
1105 retval = "LC_COLLATE";
1106 break;
1107 #endif
1108 #ifdef LC_CTYPE
1109 case LC_CTYPE:
1110 retval = "LC_CTYPE";
1111 break;
1112 #endif
1113 #ifdef LC_MONETARY
1114 case LC_MONETARY:
1115 retval = "LC_MONETARY";
1116 break;
1117 #endif
1118 #ifdef LC_NUMERIC
1119 case LC_NUMERIC:
1120 retval = "LC_NUMERIC";
1121 break;
1122 #endif
1123 #ifdef LC_TIME
1124 case LC_TIME:
1125 retval = "LC_TIME";
1126 break;
1127 #endif
1128 #ifdef LC_MESSAGES
1129 case LC_MESSAGES:
1130 retval = "LC_MESSAGES";
1131 break;
1132 #endif
1133 #ifdef LC_RESPONSE
1134 case LC_RESPONSE:
1135 retval = "LC_RESPONSE";
1136 break;
1137 #endif
1138 #ifdef LC_ALL
1139 case LC_ALL:
1140 /* This might not make sense but is perhaps better than any other
1141 value. */
1142 retval = "LC_ALL";
1143 break;
1144 #endif
1145 default:
1146 /* If you have a better idea for a default value let me know. */
1147 retval = "LC_XXX";
1150 return retval;
1153 /* Guess value of current locale from value of the environment variables. */
1154 static const char *
1155 internal_function
1156 guess_category_value (category, categoryname)
1157 int category;
1158 const char *categoryname;
1160 const char *language;
1161 const char *retval;
1162 (void) category; /* shut up compiler */
1163 (void) categoryname; /* ditto */
1165 /* The highest priority value is the `LANGUAGE' environment
1166 variable. But we don't use the value if the currently selected
1167 locale is the C locale. This is a GNU extension. */
1168 language = getenv ("LANGUAGE");
1169 if (language != NULL && language[0] == '\0')
1170 language = NULL;
1172 /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1173 `LC_xxx', and `LANG'. On some systems this can be done by the
1174 `setlocale' function itself. */
1175 #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
1176 retval = setlocale (category, NULL);
1177 #else
1178 /* Setting of LC_ALL overwrites all other. */
1179 retval = getenv ("LC_ALL");
1180 if (retval == NULL || retval[0] == '\0')
1182 /* Next comes the name of the desired category. */
1183 retval = getenv (categoryname);
1184 if (retval == NULL || retval[0] == '\0')
1186 /* Last possibility is the LANG environment variable. */
1187 retval = getenv ("LANG");
1188 if (retval == NULL || retval[0] == '\0')
1189 /* We use C as the default domain. POSIX says this is
1190 implementation defined. */
1191 return "C";
1194 #endif
1196 return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1199 /* @@ begin of epilog @@ */
1201 /* We don't want libintl.a to depend on any other library. So we
1202 avoid the non-standard function stpcpy. In GNU C Library this
1203 function is available, though. Also allow the symbol HAVE_STPCPY
1204 to be defined. */
1205 #if !_LIBC && !HAVE_STPCPY
1206 static char *
1207 stpcpy (dest, src)
1208 char *dest;
1209 const char *src;
1211 while ((*dest++ = *src++) != '\0')
1212 /* Do nothing. */ ;
1213 return dest - 1;
1215 #endif
1217 #if !_LIBC && !HAVE_MEMPCPY
1218 static void *
1219 mempcpy (dest, src, n)
1220 void *dest;
1221 const void *src;
1222 size_t n;
1224 return (void *) ((char *) memcpy (dest, src, n) + n);
1226 #endif
1229 #ifdef _LIBC
1230 /* If we want to free all resources we have to do some work at
1231 program's end. */
1232 static void __attribute__ ((unused))
1233 free_mem (void)
1235 void *old;
1237 while (_nl_domain_bindings != NULL)
1239 struct binding *oldp = _nl_domain_bindings;
1240 _nl_domain_bindings = _nl_domain_bindings->next;
1241 if (oldp->dirname != _nl_default_dirname)
1242 /* Yes, this is a pointer comparison. */
1243 free (oldp->dirname);
1244 free (oldp->codeset);
1245 free (oldp);
1248 if (_nl_current_default_domain != _nl_default_default_domain)
1249 /* Yes, again a pointer comparison. */
1250 free ((char *) _nl_current_default_domain);
1252 /* Remove the search tree with the known translations. */
1253 __tdestroy (root, free);
1254 root = NULL;
1256 while (transmem_list != NULL)
1258 old = transmem_list;
1259 transmem_list = transmem_list->next;
1260 free (old);
1264 text_set_element (__libc_subfreeres, free_mem);
1265 #endif