Use the new find program, and the new way of locating it (/ instead of )
[findutils.git] / intl / dcigettext.c
blob191226522128380cafc615a32bfc60093c9e684c
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
5 it under the terms of the GNU General Public License as published by
6 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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
19 This must come before <config.h> because <config.h> may include
20 <features.h>, and once <features.h> has been included, it's too late. */
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE 1
23 #endif
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
29 #include <sys/types.h>
31 #ifdef __GNUC__
32 # define alloca __builtin_alloca
33 # define HAVE_ALLOCA 1
34 #else
35 # if defined HAVE_ALLOCA_H || defined _LIBC
36 # include <alloca.h>
37 # else
38 # ifdef _AIX
39 #pragma alloca
40 # else
41 # ifndef alloca
42 char *alloca ();
43 # endif
44 # endif
45 # endif
46 #endif
48 #include <errno.h>
49 #ifndef errno
50 extern int errno;
51 #endif
52 #ifndef __set_errno
53 # define __set_errno(val) errno = (val)
54 #endif
56 #include <stddef.h>
57 #include <stdlib.h>
59 #include <string.h>
60 #if !HAVE_STRCHR && !defined _LIBC
61 # ifndef strchr
62 # define strchr index
63 # endif
64 #endif
66 /* The presence of unistd.h is assumed by gnulib these days, so we
67 * might as well assume it too.
69 #include <unistd.h>
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 # define getcwd __getcwd
128 # ifndef stpcpy
129 # define stpcpy __stpcpy
130 # endif
131 # define tfind __tfind
132 #else
133 # if !defined HAVE_GETCWD
134 char *getwd ();
135 # define getcwd(buf, max) getwd (buf)
136 # else
137 char *getcwd ();
138 # endif
139 # ifndef HAVE_STPCPY
140 static char *stpcpy PARAMS ((char *dest, const char *src));
141 # endif
142 # ifndef HAVE_MEMPCPY
143 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
144 # endif
145 #endif
147 /* Amount to increase buffer size by in each try. */
148 #define PATH_INCR 32
150 /* The following is from pathmax.h. */
151 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
152 PATH_MAX but might cause redefinition warnings when sys/param.h is
153 later included (as on MORE/BSD 4.3). */
154 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
155 # include <limits.h>
156 #endif
158 #ifndef _POSIX_PATH_MAX
159 # define _POSIX_PATH_MAX 255
160 #endif
162 #if !defined PATH_MAX && defined _PC_PATH_MAX
163 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
164 #endif
166 /* Don't include sys/param.h if it already has been. */
167 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
168 # include <sys/param.h>
169 #endif
171 #if !defined PATH_MAX && defined MAXPATHLEN
172 # define PATH_MAX MAXPATHLEN
173 #endif
175 #ifndef PATH_MAX
176 # define PATH_MAX _POSIX_PATH_MAX
177 #endif
179 /* Pathname support.
180 ISSLASH(C) tests whether C is a directory separator character.
181 IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
182 it may be concatenated to a directory pathname.
183 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
185 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
186 /* Win32, OS/2, DOS */
187 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
188 # define HAS_DEVICE(P) \
189 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
190 && (P)[1] == ':')
191 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
192 # define IS_PATH_WITH_DIR(P) \
193 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
194 #else
195 /* Unix */
196 # define ISSLASH(C) ((C) == '/')
197 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
198 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
199 #endif
201 /* XPG3 defines the result of `setlocale (category, NULL)' as:
202 ``Directs `setlocale()' to query `category' and return the current
203 setting of `local'.''
204 However it does not specify the exact format. Neither do SUSV2 and
205 ISO C 99. So we can use this feature only on selected systems (e.g.
206 those using GNU C Library). */
207 #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
208 # define HAVE_LOCALE_NULL
209 #endif
211 /* This is the type used for the search tree where known translations
212 are stored. */
213 struct known_translation_t
215 /* Domain in which to search. */
216 char *domainname;
218 /* The category. */
219 int category;
221 /* State of the catalog counter at the point the string was found. */
222 int counter;
224 /* Catalog where the string was found. */
225 struct loaded_l10nfile *domain;
227 /* And finally the translation. */
228 const char *translation;
229 size_t translation_length;
231 /* Pointer to the string in question. */
232 char msgid[ZERO];
235 /* Root of the search tree with known translations. We can use this
236 only if the system provides the `tsearch' function family. */
237 #if defined HAVE_TSEARCH || defined _LIBC
238 # include <search.h>
240 static void *root;
242 # ifdef _LIBC
243 # define tsearch __tsearch
244 # endif
246 /* Function to compare two entries in the table of known translations. */
247 static int transcmp PARAMS ((const void *p1, const void *p2));
248 static int
249 transcmp (p1, p2)
250 const void *p1;
251 const void *p2;
253 const struct known_translation_t *s1;
254 const struct known_translation_t *s2;
255 int result;
257 s1 = (const struct known_translation_t *) p1;
258 s2 = (const struct known_translation_t *) p2;
260 result = strcmp (s1->msgid, s2->msgid);
261 if (result == 0)
263 result = strcmp (s1->domainname, s2->domainname);
264 if (result == 0)
265 /* We compare the category last (though this is the cheapest
266 operation) since it is hopefully always the same (namely
267 LC_MESSAGES). */
268 result = s1->category - s2->category;
271 return result;
273 #endif
275 /* Name of the default domain used for gettext(3) prior any call to
276 textdomain(3). The default value for this is "messages". */
277 const char _nl_default_default_domain[] = "messages";
279 /* Value used as the default domain for gettext(3). */
280 const char *_nl_current_default_domain = _nl_default_default_domain;
282 /* Contains the default location of the message catalogs. */
283 const char _nl_default_dirname[] = LOCALEDIR;
285 /* List with bindings of specific domains created by bindtextdomain()
286 calls. */
287 struct binding *_nl_domain_bindings;
289 /* Prototypes for local functions. */
290 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
291 unsigned long int n,
292 const char *translation,
293 size_t translation_len))
294 internal_function;
295 static unsigned long int plural_eval PARAMS ((struct expression *pexp,
296 unsigned long int n))
297 internal_function;
298 static const char *category_to_name PARAMS ((int category)) internal_function;
299 static const char *guess_category_value PARAMS ((int category,
300 const char *categoryname))
301 internal_function;
304 /* For those loosing systems which don't have `alloca' we have to add
305 some additional code emulating it. */
306 #ifdef HAVE_ALLOCA
307 /* Nothing has to be done. */
308 # define ADD_BLOCK(list, address) /* nothing */
309 # define FREE_BLOCKS(list) /* nothing */
310 #else
311 struct block_list
313 void *address;
314 struct block_list *next;
316 # define ADD_BLOCK(list, addr) \
317 do { \
318 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
319 /* If we cannot get a free block we cannot add the new element to \
320 the list. */ \
321 if (newp != NULL) { \
322 newp->address = (addr); \
323 newp->next = (list); \
324 (list) = newp; \
326 } while (0)
327 # define FREE_BLOCKS(list) \
328 do { \
329 while (list != NULL) { \
330 struct block_list *old = list; \
331 list = list->next; \
332 free (old); \
334 } while (0)
335 # undef alloca
336 # define alloca(size) (malloc (size))
337 #endif /* have alloca */
340 #ifdef _LIBC
341 /* List of blocks allocated for translations. */
342 typedef struct transmem_list
344 struct transmem_list *next;
345 char data[ZERO];
346 } transmem_block_t;
347 static struct transmem_list *transmem_list;
348 #else
349 typedef unsigned char transmem_block_t;
350 #endif
353 /* Names for the libintl functions are a problem. They must not clash
354 with existing names and they should follow ANSI C. But this source
355 code is also used in GNU C Library where the names have a __
356 prefix. So we have to make a difference here. */
357 #ifdef _LIBC
358 # define DCIGETTEXT __dcigettext
359 #else
360 # define DCIGETTEXT dcigettext__
361 #endif
363 /* Lock variable to protect the global data in the gettext implementation. */
364 #ifdef _LIBC
365 __libc_rwlock_define_initialized (, _nl_state_lock)
366 #endif
368 /* Checking whether the binaries runs SUID must be done and glibc provides
369 easier methods therefore we make a difference here. */
370 #ifdef _LIBC
371 # define ENABLE_SECURE __libc_enable_secure
372 # define DETERMINE_SECURE
373 #else
374 # ifndef HAVE_GETUID
375 # define getuid() 0
376 # endif
377 # ifndef HAVE_GETGID
378 # define getgid() 0
379 # endif
380 # ifndef HAVE_GETEUID
381 # define geteuid() getuid()
382 # endif
383 # ifndef HAVE_GETEGID
384 # define getegid() getgid()
385 # endif
386 static int enable_secure;
387 # define ENABLE_SECURE (enable_secure == 1)
388 # define DETERMINE_SECURE \
389 if (enable_secure == 0) \
391 if (getuid () != geteuid () || getgid () != getegid ()) \
392 enable_secure = 1; \
393 else \
394 enable_secure = -1; \
396 #endif
398 /* Look up MSGID in the DOMAINNAME message catalog for the current
399 CATEGORY locale and, if PLURAL is nonzero, search over string
400 depending on the plural form determined by N. */
401 char *
402 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
403 const char *domainname;
404 const char *msgid1;
405 const char *msgid2;
406 int plural;
407 unsigned long int n;
408 int category;
410 #ifndef HAVE_ALLOCA
411 struct block_list *block_list = NULL;
412 #endif
413 struct loaded_l10nfile *domain;
414 struct binding *binding;
415 const char *categoryname;
416 const char *categoryvalue;
417 char *dirname, *xdomainname;
418 char *single_locale;
419 char *retval;
420 size_t retlen;
421 int saved_errno;
422 #if defined HAVE_TSEARCH || defined _LIBC
423 struct known_translation_t *search;
424 struct known_translation_t **foundp = NULL;
425 size_t msgid_len;
426 #endif
427 size_t domainname_len;
429 /* If no real MSGID is given return NULL. */
430 if (msgid1 == NULL)
431 return NULL;
433 __libc_rwlock_rdlock (_nl_state_lock);
435 /* If DOMAINNAME is NULL, we are interested in the default domain. If
436 CATEGORY is not LC_MESSAGES this might not make much sense but the
437 definition left this undefined. */
438 if (domainname == NULL)
439 domainname = _nl_current_default_domain;
441 #if defined HAVE_TSEARCH || defined _LIBC
442 msgid_len = strlen (msgid1) + 1;
444 /* Try to find the translation among those which we found at
445 some time. */
446 search = (struct known_translation_t *)
447 alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
448 memcpy (search->msgid, msgid1, msgid_len);
449 search->domainname = (char *) domainname;
450 search->category = category;
452 foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
453 if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
455 /* Now deal with plural. */
456 if (plural)
457 retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
458 (*foundp)->translation_length);
459 else
460 retval = (char *) (*foundp)->translation;
462 __libc_rwlock_unlock (_nl_state_lock);
463 return retval;
465 #endif
467 /* Preserve the `errno' value. */
468 saved_errno = errno;
470 /* See whether this is a SUID binary or not. */
471 DETERMINE_SECURE;
473 /* First find matching binding. */
474 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
476 int compare = strcmp (domainname, binding->domainname);
477 if (compare == 0)
478 /* We found it! */
479 break;
480 if (compare < 0)
482 /* It is not in the list. */
483 binding = NULL;
484 break;
488 if (binding == NULL)
489 dirname = (char *) _nl_default_dirname;
490 else if (IS_ABSOLUTE_PATH (binding->dirname))
491 dirname = binding->dirname;
492 else
494 /* We have a relative path. Make it absolute now. */
495 size_t dirname_len = strlen (binding->dirname) + 1;
496 size_t path_max;
497 char *ret;
499 path_max = (unsigned int) PATH_MAX;
500 path_max += 2; /* The getcwd docs say to do this. */
502 for (;;)
504 dirname = (char *) alloca (path_max + dirname_len);
505 ADD_BLOCK (block_list, dirname);
507 __set_errno (0);
508 ret = getcwd (dirname, path_max);
509 if (ret != NULL || errno != ERANGE)
510 break;
512 path_max += path_max / 2;
513 path_max += PATH_INCR;
516 if (ret == NULL)
518 /* We cannot get the current working directory. Don't signal an
519 error but simply return the default string. */
520 FREE_BLOCKS (block_list);
521 __set_errno (saved_errno);
522 return (plural == 0
523 ? (char *) msgid1
524 /* Use the Germanic plural rule. */
525 : n == 1 ? (char *) msgid1 : (char *) msgid2);
528 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
531 /* Now determine the symbolic name of CATEGORY and its value. */
532 categoryname = category_to_name (category);
533 categoryvalue = guess_category_value (category, categoryname);
535 domainname_len = strlen (domainname);
536 xdomainname = (char *) alloca (strlen (categoryname)
537 + domainname_len + 5);
538 ADD_BLOCK (block_list, xdomainname);
540 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
541 domainname, domainname_len),
542 ".mo");
544 /* Creating working area. */
545 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
546 ADD_BLOCK (block_list, single_locale);
549 /* Search for the given string. This is a loop because we perhaps
550 got an ordered list of languages to consider for the translation. */
551 while (1)
553 /* Make CATEGORYVALUE point to the next element of the list. */
554 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
555 ++categoryvalue;
556 if (categoryvalue[0] == '\0')
558 /* The whole contents of CATEGORYVALUE has been searched but
559 no valid entry has been found. We solve this situation
560 by implicitly appending a "C" entry, i.e. no translation
561 will take place. */
562 single_locale[0] = 'C';
563 single_locale[1] = '\0';
565 else
567 char *cp = single_locale;
568 while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
569 *cp++ = *categoryvalue++;
570 *cp = '\0';
572 /* When this is a SUID binary we must not allow accessing files
573 outside the dedicated directories. */
574 if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
575 /* Ingore this entry. */
576 continue;
579 /* If the current locale value is C (or POSIX) we don't load a
580 domain. Return the MSGID. */
581 if (strcmp (single_locale, "C") == 0
582 || strcmp (single_locale, "POSIX") == 0)
584 FREE_BLOCKS (block_list);
585 __libc_rwlock_unlock (_nl_state_lock);
586 __set_errno (saved_errno);
587 return (plural == 0
588 ? (char *) msgid1
589 /* Use the Germanic plural rule. */
590 : n == 1 ? (char *) msgid1 : (char *) msgid2);
594 /* Find structure describing the message catalog matching the
595 DOMAINNAME and CATEGORY. */
596 domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
598 if (domain != NULL)
600 retval = _nl_find_msg (domain, binding, msgid1, &retlen);
602 if (retval == NULL)
604 int cnt;
606 for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
608 retval = _nl_find_msg (domain->successor[cnt], binding,
609 msgid1, &retlen);
611 if (retval != NULL)
613 domain = domain->successor[cnt];
614 break;
619 if (retval != NULL)
621 /* Found the translation of MSGID1 in domain DOMAIN:
622 starting at RETVAL, RETLEN bytes. */
623 FREE_BLOCKS (block_list);
624 __set_errno (saved_errno);
625 #if defined HAVE_TSEARCH || defined _LIBC
626 if (foundp == NULL)
628 /* Create a new entry and add it to the search tree. */
629 struct known_translation_t *newp;
631 newp = (struct known_translation_t *)
632 malloc (offsetof (struct known_translation_t, msgid)
633 + msgid_len + domainname_len + 1);
634 if (newp != NULL)
636 newp->domainname =
637 mempcpy (newp->msgid, msgid1, msgid_len);
638 memcpy (newp->domainname, domainname, domainname_len + 1);
639 newp->category = category;
640 newp->counter = _nl_msg_cat_cntr;
641 newp->domain = domain;
642 newp->translation = retval;
643 newp->translation_length = retlen;
645 /* Insert the entry in the search tree. */
646 foundp = (struct known_translation_t **)
647 tsearch (newp, &root, transcmp);
648 if (foundp == NULL
649 || __builtin_expect (*foundp != newp, 0))
650 /* The insert failed. */
651 free (newp);
654 else
656 /* We can update the existing entry. */
657 (*foundp)->counter = _nl_msg_cat_cntr;
658 (*foundp)->domain = domain;
659 (*foundp)->translation = retval;
660 (*foundp)->translation_length = retlen;
662 #endif
663 /* Now deal with plural. */
664 if (plural)
665 retval = plural_lookup (domain, n, retval, retlen);
667 __libc_rwlock_unlock (_nl_state_lock);
668 return retval;
672 /* NOTREACHED */
676 char *
677 internal_function
678 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
679 struct loaded_l10nfile *domain_file;
680 struct binding *domainbinding;
681 const char *msgid;
682 size_t *lengthp;
684 struct loaded_domain *domain;
685 size_t act;
686 char *result;
687 size_t resultlen;
689 if (domain_file->decided == 0)
690 _nl_load_domain (domain_file, domainbinding);
692 if (domain_file->data == NULL)
693 return NULL;
695 domain = (struct loaded_domain *) domain_file->data;
697 /* Locate the MSGID and its translation. */
698 if (domain->hash_size > 2 && domain->hash_tab != NULL)
700 /* Use the hashing table. */
701 nls_uint32 len = strlen (msgid);
702 nls_uint32 hash_val = hash_string (msgid);
703 nls_uint32 idx = hash_val % domain->hash_size;
704 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
706 while (1)
708 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
710 if (nstr == 0)
711 /* Hash table entry is empty. */
712 return NULL;
714 /* Compare msgid with the original string at index nstr-1.
715 We compare the lengths with >=, not ==, because plural entries
716 are represented by strings with an embedded NUL. */
717 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
718 && (strcmp (msgid,
719 domain->data + W (domain->must_swap,
720 domain->orig_tab[nstr - 1].offset))
721 == 0))
723 act = nstr - 1;
724 goto found;
727 if (idx >= domain->hash_size - incr)
728 idx -= domain->hash_size - incr;
729 else
730 idx += incr;
732 /* NOTREACHED */
734 else
736 /* Try the default method: binary search in the sorted array of
737 messages. */
738 size_t top, bottom;
740 bottom = 0;
741 top = domain->nstrings;
742 while (bottom < top)
744 int cmp_val;
746 act = (bottom + top) / 2;
747 cmp_val = strcmp (msgid, (domain->data
748 + W (domain->must_swap,
749 domain->orig_tab[act].offset)));
750 if (cmp_val < 0)
751 top = act;
752 else if (cmp_val > 0)
753 bottom = act + 1;
754 else
755 goto found;
757 /* No translation was found. */
758 return NULL;
761 found:
762 /* The translation was found at index ACT. If we have to convert the
763 string to use a different character set, this is the time. */
764 result = ((char *) domain->data
765 + W (domain->must_swap, domain->trans_tab[act].offset));
766 resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
768 #if defined _LIBC || HAVE_ICONV
769 if (domain->codeset_cntr
770 != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
772 /* The domain's codeset has changed through bind_textdomain_codeset()
773 since the message catalog was initialized or last accessed. We
774 have to reinitialize the converter. */
775 _nl_free_domain_conv (domain);
776 _nl_init_domain_conv (domain_file, domain, domainbinding);
779 if (
780 # ifdef _LIBC
781 domain->conv != (__gconv_t) -1
782 # else
783 # if HAVE_ICONV
784 domain->conv != (iconv_t) -1
785 # endif
786 # endif
789 /* We are supposed to do a conversion. First allocate an
790 appropriate table with the same structure as the table
791 of translations in the file, where we can put the pointers
792 to the converted strings in.
793 There is a slight complication with plural entries. They
794 are represented by consecutive NUL terminated strings. We
795 handle this case by converting RESULTLEN bytes, including
796 NULs. */
798 if (domain->conv_tab == NULL
799 && ((domain->conv_tab = (char **) calloc (domain->nstrings,
800 sizeof (char *)))
801 == NULL))
802 /* Mark that we didn't succeed allocating a table. */
803 domain->conv_tab = (char **) -1;
805 if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
806 /* Nothing we can do, no more memory. */
807 goto converted;
809 if (domain->conv_tab[act] == NULL)
811 /* We haven't used this string so far, so it is not
812 translated yet. Do this now. */
813 /* We use a bit more efficient memory handling.
814 We allocate always larger blocks which get used over
815 time. This is faster than many small allocations. */
816 __libc_lock_define_initialized (static, lock)
817 # define INITIAL_BLOCK_SIZE 4080
818 static unsigned char *freemem;
819 static size_t freemem_size;
821 const unsigned char *inbuf;
822 unsigned char *outbuf;
823 int malloc_count;
824 # ifndef _LIBC
825 transmem_block_t *transmem_list = NULL;
826 # endif
828 __libc_lock_lock (lock);
830 inbuf = (const unsigned char *) result;
831 outbuf = freemem + sizeof (size_t);
833 malloc_count = 0;
834 while (1)
836 transmem_block_t *newmem;
837 # ifdef _LIBC
838 size_t non_reversible;
839 int res;
841 if (freemem_size < sizeof (size_t))
842 goto resize_freemem;
844 res = __gconv (domain->conv,
845 &inbuf, inbuf + resultlen,
846 &outbuf,
847 outbuf + freemem_size - sizeof (size_t),
848 &non_reversible);
850 if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
851 break;
853 if (res != __GCONV_FULL_OUTPUT)
855 __libc_lock_unlock (lock);
856 goto converted;
859 inbuf = result;
860 # else
861 # if HAVE_ICONV
862 const char *inptr = (const char *) inbuf;
863 size_t inleft = resultlen;
864 char *outptr = (char *) outbuf;
865 size_t outleft;
867 if (freemem_size < sizeof (size_t))
868 goto resize_freemem;
870 outleft = freemem_size - sizeof (size_t);
871 if (iconv (domain->conv,
872 (ICONV_CONST char **) &inptr, &inleft,
873 &outptr, &outleft)
874 != (size_t) (-1))
876 outbuf = (unsigned char *) outptr;
877 break;
879 if (errno != E2BIG)
881 __libc_lock_unlock (lock);
882 goto converted;
884 # endif
885 # endif
887 resize_freemem:
888 /* We must allocate a new buffer or resize the old one. */
889 if (malloc_count > 0)
891 ++malloc_count;
892 freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
893 newmem = (transmem_block_t *) realloc (transmem_list,
894 freemem_size);
895 # ifdef _LIBC
896 if (newmem != NULL)
897 transmem_list = transmem_list->next;
898 else
900 struct transmem_list *old = transmem_list;
902 transmem_list = transmem_list->next;
903 free (old);
905 # endif
907 else
909 malloc_count = 1;
910 freemem_size = INITIAL_BLOCK_SIZE;
911 newmem = (transmem_block_t *) malloc (freemem_size);
913 if (__builtin_expect (newmem == NULL, 0))
915 freemem = NULL;
916 freemem_size = 0;
917 __libc_lock_unlock (lock);
918 goto converted;
921 # ifdef _LIBC
922 /* Add the block to the list of blocks we have to free
923 at some point. */
924 newmem->next = transmem_list;
925 transmem_list = newmem;
927 freemem = newmem->data;
928 freemem_size -= offsetof (struct transmem_list, data);
929 # else
930 transmem_list = newmem;
931 freemem = newmem;
932 # endif
934 outbuf = freemem + sizeof (size_t);
937 /* We have now in our buffer a converted string. Put this
938 into the table of conversions. */
939 *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
940 domain->conv_tab[act] = (char *) freemem;
941 /* Shrink freemem, but keep it aligned. */
942 freemem_size -= outbuf - freemem;
943 freemem = outbuf;
944 freemem += freemem_size & (alignof (size_t) - 1);
945 freemem_size = freemem_size & ~ (alignof (size_t) - 1);
947 __libc_lock_unlock (lock);
950 /* Now domain->conv_tab[act] contains the translation of all
951 the plural variants. */
952 result = domain->conv_tab[act] + sizeof (size_t);
953 resultlen = *(size_t *) domain->conv_tab[act];
956 converted:
957 /* The result string is converted. */
959 #endif /* _LIBC || HAVE_ICONV */
961 *lengthp = resultlen;
962 return result;
966 /* Look up a plural variant. */
967 static char *
968 internal_function
969 plural_lookup (domain, n, translation, translation_len)
970 struct loaded_l10nfile *domain;
971 unsigned long int n;
972 const char *translation;
973 size_t translation_len;
975 struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
976 unsigned long int idx; /* can't call this index, we may need to use index() */
977 const char *p;
979 idx = plural_eval (domaindata->plural, n);
980 if (idx >= domaindata->nplurals)
981 /* This should never happen. It means the plural expression and the
982 given maximum value do not match. */
983 idx = 0;
985 /* Skip INDEX strings at TRANSLATION. */
986 p = translation;
987 while (idx-- > 0)
989 #ifdef _LIBC
990 p = __rawmemchr (p, '\0');
991 #else
992 p = strchr (p, '\0');
993 #endif
994 /* And skip over the NUL byte. */
995 p++;
997 if (p >= translation + translation_len)
998 /* This should never happen. It means the plural expression
999 evaluated to a value larger than the number of variants
1000 available for MSGID1. */
1001 return (char *) translation;
1003 return (char *) p;
1007 /* Function to evaluate the plural expression and return an index value. */
1008 static unsigned long int
1009 internal_function
1010 plural_eval (pexp, n)
1011 struct expression *pexp;
1012 unsigned long int n;
1014 switch (pexp->nargs)
1016 case 0:
1017 switch (pexp->operation)
1019 case var:
1020 return n;
1021 case num:
1022 return pexp->val.num;
1023 default:
1024 break;
1026 /* NOTREACHED */
1027 break;
1028 case 1:
1030 /* pexp->operation must be lnot. */
1031 unsigned long int arg = plural_eval (pexp->val.args[0], n);
1032 return ! arg;
1034 case 2:
1036 unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
1037 if (pexp->operation == lor)
1038 return leftarg || plural_eval (pexp->val.args[1], n);
1039 else if (pexp->operation == land)
1040 return leftarg && plural_eval (pexp->val.args[1], n);
1041 else
1043 unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
1045 switch (pexp->operation)
1047 case mult:
1048 return leftarg * rightarg;
1049 case divide:
1050 return leftarg / rightarg;
1051 case module:
1052 return leftarg % rightarg;
1053 case plus:
1054 return leftarg + rightarg;
1055 case minus:
1056 return leftarg - rightarg;
1057 case less_than:
1058 return leftarg < rightarg;
1059 case greater_than:
1060 return leftarg > rightarg;
1061 case less_or_equal:
1062 return leftarg <= rightarg;
1063 case greater_or_equal:
1064 return leftarg >= rightarg;
1065 case equal:
1066 return leftarg == rightarg;
1067 case not_equal:
1068 return leftarg != rightarg;
1069 default:
1070 break;
1073 /* NOTREACHED */
1074 break;
1076 case 3:
1078 /* pexp->operation must be qmop. */
1079 unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
1080 return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
1083 /* NOTREACHED */
1084 return 0;
1088 /* Return string representation of locale CATEGORY. */
1089 static const char *
1090 internal_function
1091 category_to_name (category)
1092 int category;
1094 const char *retval;
1096 switch (category)
1098 #ifdef LC_COLLATE
1099 case LC_COLLATE:
1100 retval = "LC_COLLATE";
1101 break;
1102 #endif
1103 #ifdef LC_CTYPE
1104 case LC_CTYPE:
1105 retval = "LC_CTYPE";
1106 break;
1107 #endif
1108 #ifdef LC_MONETARY
1109 case LC_MONETARY:
1110 retval = "LC_MONETARY";
1111 break;
1112 #endif
1113 #ifdef LC_NUMERIC
1114 case LC_NUMERIC:
1115 retval = "LC_NUMERIC";
1116 break;
1117 #endif
1118 #ifdef LC_TIME
1119 case LC_TIME:
1120 retval = "LC_TIME";
1121 break;
1122 #endif
1123 #ifdef LC_MESSAGES
1124 case LC_MESSAGES:
1125 retval = "LC_MESSAGES";
1126 break;
1127 #endif
1128 #ifdef LC_RESPONSE
1129 case LC_RESPONSE:
1130 retval = "LC_RESPONSE";
1131 break;
1132 #endif
1133 #ifdef LC_ALL
1134 case LC_ALL:
1135 /* This might not make sense but is perhaps better than any other
1136 value. */
1137 retval = "LC_ALL";
1138 break;
1139 #endif
1140 default:
1141 /* If you have a better idea for a default value let me know. */
1142 retval = "LC_XXX";
1145 return retval;
1148 /* Guess value of current locale from value of the environment variables. */
1149 static const char *
1150 internal_function
1151 guess_category_value (category, categoryname)
1152 int category;
1153 const char *categoryname;
1155 const char *language;
1156 const char *retval;
1158 /* The highest priority value is the `LANGUAGE' environment
1159 variable. But we don't use the value if the currently selected
1160 locale is the C locale. This is a GNU extension. */
1161 language = getenv ("LANGUAGE");
1162 if (language != NULL && language[0] == '\0')
1163 language = NULL;
1165 /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1166 `LC_xxx', and `LANG'. On some systems this can be done by the
1167 `setlocale' function itself. */
1168 #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
1169 retval = setlocale (category, NULL);
1170 #else
1171 /* Setting of LC_ALL overwrites all other. */
1172 retval = getenv ("LC_ALL");
1173 if (retval == NULL || retval[0] == '\0')
1175 /* Next comes the name of the desired category. */
1176 retval = getenv (categoryname);
1177 if (retval == NULL || retval[0] == '\0')
1179 /* Last possibility is the LANG environment variable. */
1180 retval = getenv ("LANG");
1181 if (retval == NULL || retval[0] == '\0')
1182 /* We use C as the default domain. POSIX says this is
1183 implementation defined. */
1184 return "C";
1187 #endif
1189 return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1192 /* @@ begin of epilog @@ */
1194 /* We don't want libintl.a to depend on any other library. So we
1195 avoid the non-standard function stpcpy. In GNU C Library this
1196 function is available, though. Also allow the symbol HAVE_STPCPY
1197 to be defined. */
1198 #if !_LIBC && !HAVE_STPCPY
1199 static char *
1200 stpcpy (dest, src)
1201 char *dest;
1202 const char *src;
1204 while ((*dest++ = *src++) != '\0')
1205 /* Do nothing. */ ;
1206 return dest - 1;
1208 #endif
1210 #if !_LIBC && !HAVE_MEMPCPY
1211 static void *
1212 mempcpy (dest, src, n)
1213 void *dest;
1214 const void *src;
1215 size_t n;
1217 return (void *) ((char *) memcpy (dest, src, n) + n);
1219 #endif
1222 #ifdef _LIBC
1223 /* If we want to free all resources we have to do some work at
1224 program's end. */
1225 static void __attribute__ ((unused))
1226 free_mem (void)
1228 void *old;
1230 while (_nl_domain_bindings != NULL)
1232 struct binding *oldp = _nl_domain_bindings;
1233 _nl_domain_bindings = _nl_domain_bindings->next;
1234 if (oldp->dirname != _nl_default_dirname)
1235 /* Yes, this is a pointer comparison. */
1236 free (oldp->dirname);
1237 free (oldp->codeset);
1238 free (oldp);
1241 if (_nl_current_default_domain != _nl_default_default_domain)
1242 /* Yes, again a pointer comparison. */
1243 free ((char *) _nl_current_default_domain);
1245 /* Remove the search tree with the known translations. */
1246 __tdestroy (root, free);
1247 root = NULL;
1249 while (transmem_list != NULL)
1251 old = transmem_list;
1252 transmem_list = transmem_list->next;
1253 free (old);
1257 text_set_element (__libc_subfreeres, free_mem);
1258 #endif