2002-08-03 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / intl / dcigettext.c
1 /* Implementation of the internal dcigettext function.
2    Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
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.  */
19
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
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <sys/types.h>
32
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
49
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
57
58 #include <stddef.h>
59 #include <stdlib.h>
60 #include <string.h>
61
62 #if defined HAVE_UNISTD_H || defined _LIBC
63 # include <unistd.h>
64 #endif
65
66 #include <locale.h>
67
68 #if defined HAVE_SYS_PARAM_H || defined _LIBC
69 # include <sys/param.h>
70 #endif
71
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"
80
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
93
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
101
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 _nl_default_default_domain__
107 # define _nl_current_default_domain _nl_current_default_domain__
108 # define _nl_default_dirname _nl_default_dirname__
109 # define _nl_domain_bindings _nl_domain_bindings__
110 #endif
111
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
116
117 /* @@ end of prolog @@ */
118
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
142
143 /* Amount to increase buffer size by in each try.  */
144 #define PATH_INCR 32
145
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
153
154 #ifndef _POSIX_PATH_MAX
155 # define _POSIX_PATH_MAX 255
156 #endif
157
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
161
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
166
167 #if !defined PATH_MAX && defined MAXPATHLEN
168 # define PATH_MAX MAXPATHLEN
169 #endif
170
171 #ifndef PATH_MAX
172 # define PATH_MAX _POSIX_PATH_MAX
173 #endif
174
175 /* This is the type used for the search tree where known translations
176    are stored.  */
177 struct known_translation_t
178 {
179   /* Domain in which to search.  */
180   char *domainname;
181
182   /* The category.  */
183   int category;
184
185   /* State of the catalog counter at the point the string was found.  */
186   int counter;
187
188   /* Catalog where the string was found.  */
189   struct loaded_l10nfile *domain;
190
191   /* And finally the translation.  */
192   const char *translation;
193   size_t translation_length;
194
195   /* Pointer to the string in question.  */
196   char msgid[ZERO];
197 };
198
199 /* Root of the search tree with known translations.  We can use this
200    only if the system provides the `tsearch' function family.  */
201 #if defined HAVE_TSEARCH || defined _LIBC
202 # include <search.h>
203
204 static void *root;
205
206 # ifdef _LIBC
207 #  define tsearch __tsearch
208 # endif
209
210 /* Function to compare two entries in the table of known translations.  */
211 static int transcmp PARAMS ((const void *p1, const void *p2));
212 static int
213 transcmp (p1, p2)
214      const void *p1;
215      const void *p2;
216 {
217   const struct known_translation_t *s1;
218   const struct known_translation_t *s2;
219   int result;
220
221   s1 = (const struct known_translation_t *) p1;
222   s2 = (const struct known_translation_t *) p2;
223
224   result = strcmp (s1->msgid, s2->msgid);
225   if (result == 0)
226     {
227       result = strcmp (s1->domainname, s2->domainname);
228       if (result == 0)
229         /* We compare the category last (though this is the cheapest
230            operation) since it is hopefully always the same (namely
231            LC_MESSAGES).  */
232         result = s1->category - s2->category;
233     }
234
235   return result;
236 }
237 #endif
238
239 /* Name of the default domain used for gettext(3) prior any call to
240    textdomain(3).  The default value for this is "messages".  */
241 const char _nl_default_default_domain[] attribute_hidden = "messages";
242
243 /* Value used as the default domain for gettext(3).  */
244 const char *_nl_current_default_domain attribute_hidden
245      = _nl_default_default_domain;
246
247 /* Contains the default location of the message catalogs.  */
248 const char _nl_default_dirname[] = LOCALEDIR;
249
250 /* List with bindings of specific domains created by bindtextdomain()
251    calls.  */
252 struct binding *_nl_domain_bindings;
253
254 /* Prototypes for local functions.  */
255 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
256                                     unsigned long int n,
257                                     const char *translation,
258                                     size_t translation_len))
259      internal_function;
260 static const char *category_to_name PARAMS ((int category)) internal_function;
261 static const char *guess_category_value PARAMS ((int category,
262                                                  const char *categoryname))
263      internal_function;
264
265
266 /* For those loosing systems which don't have `alloca' we have to add
267    some additional code emulating it.  */
268 #ifdef HAVE_ALLOCA
269 /* Nothing has to be done.  */
270 # define ADD_BLOCK(list, address) /* nothing */
271 # define FREE_BLOCKS(list) /* nothing */
272 #else
273 struct block_list
274 {
275   void *address;
276   struct block_list *next;
277 };
278 # define ADD_BLOCK(list, addr)                                                \
279   do {                                                                        \
280     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
281     /* If we cannot get a free block we cannot add the new element to         \
282        the list.  */                                                          \
283     if (newp != NULL) {                                                       \
284       newp->address = (addr);                                                 \
285       newp->next = (list);                                                    \
286       (list) = newp;                                                          \
287     }                                                                         \
288   } while (0)
289 # define FREE_BLOCKS(list)                                                    \
290   do {                                                                        \
291     while (list != NULL) {                                                    \
292       struct block_list *old = list;                                          \
293       list = list->next;                                                      \
294       free (old);                                                             \
295     }                                                                         \
296   } while (0)
297 # undef alloca
298 # define alloca(size) (malloc (size))
299 #endif  /* have alloca */
300
301
302 #ifdef _LIBC
303 /* List of blocks allocated for translations.  */
304 typedef struct transmem_list
305 {
306   struct transmem_list *next;
307   char data[ZERO];
308 } transmem_block_t;
309 static struct transmem_list *transmem_list;
310 #else
311 typedef unsigned char transmem_block_t;
312 #endif
313
314
315 /* Names for the libintl functions are a problem.  They must not clash
316    with existing names and they should follow ANSI C.  But this source
317    code is also used in GNU C Library where the names have a __
318    prefix.  So we have to make a difference here.  */
319 #ifdef _LIBC
320 # define DCIGETTEXT __dcigettext
321 #else
322 # define DCIGETTEXT dcigettext__
323 #endif
324
325 /* Lock variable to protect the global data in the gettext implementation.  */
326 #ifdef _LIBC
327 __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
328 #endif
329
330 /* Checking whether the binaries runs SUID must be done and glibc provides
331    easier methods therefore we make a difference here.  */
332 #ifdef _LIBC
333 # define ENABLE_SECURE __libc_enable_secure
334 # define DETERMINE_SECURE
335 #else
336 static int enable_secure;
337 # define ENABLE_SECURE (enable_secure == 1)
338 # define DETERMINE_SECURE \
339   if (enable_secure == 0)                                                     \
340     {                                                                         \
341       if (getuid () != geteuid () || getgid () != getegid ())                 \
342         enable_secure = 1;                                                    \
343       else                                                                    \
344         enable_secure = -1;                                                   \
345     }
346 #endif
347
348 /* Get the function to evaluate the plural expression.  */
349 #include "plural-eval.c"
350
351 /* Look up MSGID in the DOMAINNAME message catalog for the current
352    CATEGORY locale and, if PLURAL is nonzero, search over string
353    depending on the plural form determined by N.  */
354 char *
355 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
356      const char *domainname;
357      const char *msgid1;
358      const char *msgid2;
359      int plural;
360      unsigned long int n;
361      int category;
362 {
363 #ifndef HAVE_ALLOCA
364   struct block_list *block_list = NULL;
365 #endif
366   struct loaded_l10nfile *domain;
367   struct binding *binding;
368   const char *categoryname;
369   const char *categoryvalue;
370   char *dirname, *xdomainname;
371   char *single_locale;
372   char *retval;
373   size_t retlen;
374   int saved_errno;
375 #if defined HAVE_TSEARCH || defined _LIBC
376   struct known_translation_t *search;
377   struct known_translation_t **foundp = NULL;
378   size_t msgid_len;
379 #endif
380   size_t domainname_len;
381
382   /* If no real MSGID is given return NULL.  */
383   if (msgid1 == NULL)
384     return NULL;
385
386   __libc_rwlock_rdlock (_nl_state_lock);
387
388   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
389      CATEGORY is not LC_MESSAGES this might not make much sense but the
390      definition left this undefined.  */
391   if (domainname == NULL)
392     domainname = _nl_current_default_domain;
393
394 #if defined HAVE_TSEARCH || defined _LIBC
395   msgid_len = strlen (msgid1) + 1;
396
397   /* Try to find the translation among those which we found at
398      some time.  */
399   search = (struct known_translation_t *)
400            alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
401   memcpy (search->msgid, msgid1, msgid_len);
402   search->domainname = (char *) domainname;
403   search->category = category;
404
405   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
406   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
407     {
408       /* Now deal with plural.  */
409       if (plural)
410         retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
411                                 (*foundp)->translation_length);
412       else
413         retval = (char *) (*foundp)->translation;
414
415       __libc_rwlock_unlock (_nl_state_lock);
416       return retval;
417     }
418 #endif
419
420   /* Preserve the `errno' value.  */
421   saved_errno = errno;
422
423   /* See whether this is a SUID binary or not.  */
424   DETERMINE_SECURE;
425
426   /* First find matching binding.  */
427   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
428     {
429       int compare = strcmp (domainname, binding->domainname);
430       if (compare == 0)
431         /* We found it!  */
432         break;
433       if (compare < 0)
434         {
435           /* It is not in the list.  */
436           binding = NULL;
437           break;
438         }
439     }
440
441   if (binding == NULL)
442     dirname = (char *) _nl_default_dirname;
443   else if (binding->dirname[0] == '/')
444     dirname = binding->dirname;
445   else
446     {
447       /* We have a relative path.  Make it absolute now.  */
448       size_t dirname_len = strlen (binding->dirname) + 1;
449       size_t path_max;
450       char *ret;
451
452       path_max = (unsigned int) PATH_MAX;
453       path_max += 2;            /* The getcwd docs say to do this.  */
454
455       for (;;)
456         {
457           dirname = (char *) alloca (path_max + dirname_len);
458           ADD_BLOCK (block_list, dirname);
459
460           __set_errno (0);
461           ret = getcwd (dirname, path_max);
462           if (ret != NULL || errno != ERANGE)
463             break;
464
465           path_max += path_max / 2;
466           path_max += PATH_INCR;
467         }
468
469       if (ret == NULL)
470         {
471           /* We cannot get the current working directory.  Don't signal an
472              error but simply return the default string.  */
473           FREE_BLOCKS (block_list);
474           __libc_rwlock_unlock (_nl_state_lock);
475           __set_errno (saved_errno);
476           return (plural == 0
477                   ? (char *) msgid1
478                   /* Use the Germanic plural rule.  */
479                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
480         }
481
482       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
483     }
484
485   /* Now determine the symbolic name of CATEGORY and its value.  */
486   categoryname = category_to_name (category);
487   categoryvalue = guess_category_value (category, categoryname);
488
489   domainname_len = strlen (domainname);
490   xdomainname = (char *) alloca (strlen (categoryname)
491                                  + domainname_len + 5);
492   ADD_BLOCK (block_list, xdomainname);
493
494   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
495                   domainname, domainname_len),
496           ".mo");
497
498   /* Creating working area.  */
499   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
500   ADD_BLOCK (block_list, single_locale);
501
502
503   /* Search for the given string.  This is a loop because we perhaps
504      got an ordered list of languages to consider for the translation.  */
505   while (1)
506     {
507       /* Make CATEGORYVALUE point to the next element of the list.  */
508       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
509         ++categoryvalue;
510       if (categoryvalue[0] == '\0')
511         {
512           /* The whole contents of CATEGORYVALUE has been searched but
513              no valid entry has been found.  We solve this situation
514              by implicitly appending a "C" entry, i.e. no translation
515              will take place.  */
516           single_locale[0] = 'C';
517           single_locale[1] = '\0';
518         }
519       else
520         {
521           char *cp = single_locale;
522           while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
523             *cp++ = *categoryvalue++;
524           *cp = '\0';
525
526           /* When this is a SUID binary we must not allow accessing files
527              outside the dedicated directories.  */
528           if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
529             /* Ingore this entry.  */
530             continue;
531         }
532
533       /* If the current locale value is C (or POSIX) we don't load a
534          domain.  Return the MSGID.  */
535       if (strcmp (single_locale, "C") == 0
536           || strcmp (single_locale, "POSIX") == 0)
537         {
538           FREE_BLOCKS (block_list);
539           __libc_rwlock_unlock (_nl_state_lock);
540           __set_errno (saved_errno);
541           return (plural == 0
542                   ? (char *) msgid1
543                   /* Use the Germanic plural rule.  */
544                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
545         }
546
547
548       /* Find structure describing the message catalog matching the
549          DOMAINNAME and CATEGORY.  */
550       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
551
552       if (domain != NULL)
553         {
554           retval = _nl_find_msg (domain, binding, msgid1, &retlen);
555
556           if (retval == NULL)
557             {
558               int cnt;
559
560               for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
561                 {
562                   retval = _nl_find_msg (domain->successor[cnt], binding,
563                                          msgid1, &retlen);
564
565                   if (retval != NULL)
566                     {
567                       domain = domain->successor[cnt];
568                       break;
569                     }
570                 }
571             }
572
573           if (retval != NULL)
574             {
575               /* Found the translation of MSGID1 in domain DOMAIN:
576                  starting at RETVAL, RETLEN bytes.  */
577               FREE_BLOCKS (block_list);
578               __set_errno (saved_errno);
579 #if defined HAVE_TSEARCH || defined _LIBC
580               if (foundp == NULL)
581                 {
582                   /* Create a new entry and add it to the search tree.  */
583                   struct known_translation_t *newp;
584
585                   newp = (struct known_translation_t *)
586                     malloc (offsetof (struct known_translation_t, msgid)
587                             + msgid_len + domainname_len + 1);
588                   if (newp != NULL)
589                     {
590                       newp->domainname =
591                         mempcpy (newp->msgid, msgid1, msgid_len);
592                       memcpy (newp->domainname, domainname, domainname_len + 1);
593                       newp->category = category;
594                       newp->counter = _nl_msg_cat_cntr;
595                       newp->domain = domain;
596                       newp->translation = retval;
597                       newp->translation_length = retlen;
598
599                       /* Insert the entry in the search tree.  */
600                       foundp = (struct known_translation_t **)
601                         tsearch (newp, &root, transcmp);
602                       if (foundp == NULL
603                           || __builtin_expect (*foundp != newp, 0))
604                         /* The insert failed.  */
605                         free (newp);
606                     }
607                 }
608               else
609                 {
610                   /* We can update the existing entry.  */
611                   (*foundp)->counter = _nl_msg_cat_cntr;
612                   (*foundp)->domain = domain;
613                   (*foundp)->translation = retval;
614                   (*foundp)->translation_length = retlen;
615                 }
616 #endif
617               /* Now deal with plural.  */
618               if (plural)
619                 retval = plural_lookup (domain, n, retval, retlen);
620
621               __libc_rwlock_unlock (_nl_state_lock);
622               return retval;
623             }
624         }
625     }
626   /* NOTREACHED */
627 }
628
629
630 char *
631 internal_function
632 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
633      struct loaded_l10nfile *domain_file;
634      struct binding *domainbinding;
635      const char *msgid;
636      size_t *lengthp;
637 {
638   struct loaded_domain *domain;
639   nls_uint32 nstrings;
640   size_t act;
641   char *result;
642   size_t resultlen;
643
644   if (domain_file->decided == 0)
645     _nl_load_domain (domain_file, domainbinding);
646
647   if (domain_file->data == NULL)
648     return NULL;
649
650   domain = (struct loaded_domain *) domain_file->data;
651
652   nstrings = domain->nstrings;
653
654   /* Locate the MSGID and its translation.  */
655   if (domain->hash_tab != NULL)
656     {
657       /* Use the hashing table.  */
658       nls_uint32 len = strlen (msgid);
659       nls_uint32 hash_val = hash_string (msgid);
660       nls_uint32 idx = hash_val % domain->hash_size;
661       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
662
663       while (1)
664         {
665           nls_uint32 nstr =
666             W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
667
668           if (nstr == 0)
669             /* Hash table entry is empty.  */
670             return NULL;
671
672           nstr--;
673
674           /* Compare msgid with the original string at index nstr.
675              We compare the lengths with >=, not ==, because plural entries
676              are represented by strings with an embedded NUL.  */
677           if (nstr < nstrings
678               ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
679                 && (strcmp (msgid,
680                             domain->data + W (domain->must_swap,
681                                               domain->orig_tab[nstr].offset))
682                     == 0)
683               : domain->orig_sysdep_tab[nstr - nstrings].length > len
684                 && (strcmp (msgid,
685                             domain->orig_sysdep_tab[nstr - nstrings].pointer)
686                     == 0))
687             {
688               act = nstr;
689               goto found;
690             }
691
692           if (idx >= domain->hash_size - incr)
693             idx -= domain->hash_size - incr;
694           else
695             idx += incr;
696         }
697       /* NOTREACHED */
698     }
699   else
700     {
701       /* Try the default method:  binary search in the sorted array of
702          messages.  */
703       size_t top, bottom;
704
705       bottom = 0;
706       top = nstrings;
707       while (bottom < top)
708         {
709           int cmp_val;
710
711           act = (bottom + top) / 2;
712           cmp_val = strcmp (msgid, (domain->data
713                                     + W (domain->must_swap,
714                                          domain->orig_tab[act].offset)));
715           if (cmp_val < 0)
716             top = act;
717           else if (cmp_val > 0)
718             bottom = act + 1;
719           else
720             goto found;
721         }
722       /* No translation was found.  */
723       return NULL;
724     }
725
726  found:
727   /* The translation was found at index ACT.  If we have to convert the
728      string to use a different character set, this is the time.  */
729   if (act < nstrings)
730     {
731       result = (char *)
732         (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
733       resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
734     }
735   else
736     {
737       result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
738       resultlen = domain->trans_sysdep_tab[act - nstrings].length;
739     }
740
741 #if defined _LIBC || HAVE_ICONV
742   if (domain->codeset_cntr
743       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
744     {
745       /* The domain's codeset has changed through bind_textdomain_codeset()
746          since the message catalog was initialized or last accessed.  We
747          have to reinitialize the converter.  */
748       _nl_free_domain_conv (domain);
749       _nl_init_domain_conv (domain_file, domain, domainbinding);
750     }
751
752   if (
753 # ifdef _LIBC
754       domain->conv != (__gconv_t) -1
755 # else
756 #  if HAVE_ICONV
757       domain->conv != (iconv_t) -1
758 #  endif
759 # endif
760       )
761     {
762       /* We are supposed to do a conversion.  First allocate an
763          appropriate table with the same structure as the table
764          of translations in the file, where we can put the pointers
765          to the converted strings in.
766          There is a slight complication with plural entries.  They
767          are represented by consecutive NUL terminated strings.  We
768          handle this case by converting RESULTLEN bytes, including
769          NULs.  */
770
771       if (domain->conv_tab == NULL
772           && ((domain->conv_tab =
773                  (char **) calloc (nstrings + domain->n_sysdep_strings,
774                                    sizeof (char *)))
775               == NULL))
776         /* Mark that we didn't succeed allocating a table.  */
777         domain->conv_tab = (char **) -1;
778
779       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
780         /* Nothing we can do, no more memory.  */
781         goto converted;
782
783       if (domain->conv_tab[act] == NULL)
784         {
785           /* We haven't used this string so far, so it is not
786              translated yet.  Do this now.  */
787           /* We use a bit more efficient memory handling.
788              We allocate always larger blocks which get used over
789              time.  This is faster than many small allocations.   */
790           __libc_lock_define_initialized (static, lock)
791 # define INITIAL_BLOCK_SIZE     4080
792           static unsigned char *freemem;
793           static size_t freemem_size;
794
795           const unsigned char *inbuf;
796           unsigned char *outbuf;
797           int malloc_count;
798 # ifndef _LIBC
799           transmem_block_t *transmem_list = NULL;
800 # endif
801
802           __libc_lock_lock (lock);
803
804           inbuf = (const unsigned char *) result;
805           outbuf = freemem + sizeof (size_t);
806
807           malloc_count = 0;
808           while (1)
809             {
810               transmem_block_t *newmem;
811 # ifdef _LIBC
812               size_t non_reversible;
813               int res;
814
815               if (freemem_size < sizeof (size_t))
816                 goto resize_freemem;
817
818               res = __gconv (domain->conv,
819                              &inbuf, inbuf + resultlen,
820                              &outbuf,
821                              outbuf + freemem_size - sizeof (size_t),
822                              &non_reversible);
823
824               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
825                 break;
826
827               if (res != __GCONV_FULL_OUTPUT)
828                 {
829                   __libc_lock_unlock (lock);
830                   goto converted;
831                 }
832
833               inbuf = result;
834 # else
835 #  if HAVE_ICONV
836               const char *inptr = (const char *) inbuf;
837               size_t inleft = resultlen;
838               char *outptr = (char *) outbuf;
839               size_t outleft;
840
841               if (freemem_size < sizeof (size_t))
842                 goto resize_freemem;
843
844               outleft = freemem_size - sizeof (size_t);
845               if (iconv (domain->conv,
846                          (ICONV_CONST char **) &inptr, &inleft,
847                          &outptr, &outleft)
848                   != (size_t) (-1))
849                 {
850                   outbuf = (unsigned char *) outptr;
851                   break;
852                 }
853               if (errno != E2BIG)
854                 {
855                   __libc_lock_unlock (lock);
856                   goto converted;
857                 }
858 #  endif
859 # endif
860
861             resize_freemem:
862               /* We must allocate a new buffer or resize the old one.  */
863               if (malloc_count > 0)
864                 {
865                   ++malloc_count;
866                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
867                   newmem = (transmem_block_t *) realloc (transmem_list,
868                                                          freemem_size);
869 # ifdef _LIBC
870                   if (newmem != NULL)
871                     transmem_list = transmem_list->next;
872                   else
873                     {
874                       struct transmem_list *old = transmem_list;
875
876                       transmem_list = transmem_list->next;
877                       free (old);
878                     }
879 # endif
880                 }
881               else
882                 {
883                   malloc_count = 1;
884                   freemem_size = INITIAL_BLOCK_SIZE;
885                   newmem = (transmem_block_t *) malloc (freemem_size);
886                 }
887               if (__builtin_expect (newmem == NULL, 0))
888                 {
889                   freemem = NULL;
890                   freemem_size = 0;
891                   __libc_lock_unlock (lock);
892                   goto converted;
893                 }
894
895 # ifdef _LIBC
896               /* Add the block to the list of blocks we have to free
897                  at some point.  */
898               newmem->next = transmem_list;
899               transmem_list = newmem;
900
901               freemem = newmem->data;
902               freemem_size -= offsetof (struct transmem_list, data);
903 # else
904               transmem_list = newmem;
905               freemem = newmem;
906 # endif
907
908               outbuf = freemem + sizeof (size_t);
909             }
910
911           /* We have now in our buffer a converted string.  Put this
912              into the table of conversions.  */
913           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
914           domain->conv_tab[act] = (char *) freemem;
915           /* Shrink freemem, but keep it aligned.  */
916           freemem_size -= outbuf - freemem;
917           freemem = outbuf;
918           freemem += freemem_size & (alignof (size_t) - 1);
919           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
920
921           __libc_lock_unlock (lock);
922         }
923
924       /* Now domain->conv_tab[act] contains the translation of all
925          the plural variants.  */
926       result = domain->conv_tab[act] + sizeof (size_t);
927       resultlen = *(size_t *) domain->conv_tab[act];
928     }
929
930  converted:
931   /* The result string is converted.  */
932
933 #endif /* _LIBC || HAVE_ICONV */
934
935   *lengthp = resultlen;
936   return result;
937 }
938
939
940 /* Look up a plural variant.  */
941 static char *
942 internal_function
943 plural_lookup (domain, n, translation, translation_len)
944      struct loaded_l10nfile *domain;
945      unsigned long int n;
946      const char *translation;
947      size_t translation_len;
948 {
949   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
950   unsigned long int index;
951   const char *p;
952
953   index = plural_eval (domaindata->plural, n);
954   if (index >= domaindata->nplurals)
955     /* This should never happen.  It means the plural expression and the
956        given maximum value do not match.  */
957     index = 0;
958
959   /* Skip INDEX strings at TRANSLATION.  */
960   p = translation;
961   while (index-- > 0)
962     {
963 #ifdef _LIBC
964       p = __rawmemchr (p, '\0');
965 #else
966       p = strchr (p, '\0');
967 #endif
968       /* And skip over the NUL byte.  */
969       p++;
970
971       if (p >= translation + translation_len)
972         /* This should never happen.  It means the plural expression
973            evaluated to a value larger than the number of variants
974            available for MSGID1.  */
975         return (char *) translation;
976     }
977   return (char *) p;
978 }
979
980
981 /* Return string representation of locale CATEGORY.  */
982 static const char *
983 internal_function
984 category_to_name (category)
985      int category;
986 {
987   const char *retval;
988
989   switch (category)
990   {
991 #ifdef LC_COLLATE
992   case LC_COLLATE:
993     retval = "LC_COLLATE";
994     break;
995 #endif
996 #ifdef LC_CTYPE
997   case LC_CTYPE:
998     retval = "LC_CTYPE";
999     break;
1000 #endif
1001 #ifdef LC_MONETARY
1002   case LC_MONETARY:
1003     retval = "LC_MONETARY";
1004     break;
1005 #endif
1006 #ifdef LC_NUMERIC
1007   case LC_NUMERIC:
1008     retval = "LC_NUMERIC";
1009     break;
1010 #endif
1011 #ifdef LC_TIME
1012   case LC_TIME:
1013     retval = "LC_TIME";
1014     break;
1015 #endif
1016 #ifdef LC_MESSAGES
1017   case LC_MESSAGES:
1018     retval = "LC_MESSAGES";
1019     break;
1020 #endif
1021 #ifdef LC_RESPONSE
1022   case LC_RESPONSE:
1023     retval = "LC_RESPONSE";
1024     break;
1025 #endif
1026 #ifdef LC_ALL
1027   case LC_ALL:
1028     /* This might not make sense but is perhaps better than any other
1029        value.  */
1030     retval = "LC_ALL";
1031     break;
1032 #endif
1033   default:
1034     /* If you have a better idea for a default value let me know.  */
1035     retval = "LC_XXX";
1036   }
1037
1038   return retval;
1039 }
1040
1041 /* Guess value of current locale from value of the environment variables.  */
1042 static const char *
1043 internal_function
1044 guess_category_value (category, categoryname)
1045      int category;
1046      const char *categoryname;
1047 {
1048   const char *language;
1049   const char *retval;
1050
1051   /* The highest priority value is the `LANGUAGE' environment
1052      variable.  But we don't use the value if the currently selected
1053      locale is the C locale.  This is a GNU extension.  */
1054   language = getenv ("LANGUAGE");
1055   if (language != NULL && language[0] == '\0')
1056     language = NULL;
1057
1058   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1059      `LC_xxx', and `LANG'.  On some systems this can be done by the
1060      `setlocale' function itself.  */
1061 #ifdef _LIBC
1062   retval = __current_locale_name (category);
1063 #else
1064   retval = _nl_locale_name (category, categoryname);
1065 #endif
1066
1067   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1068 }
1069
1070 /* @@ begin of epilog @@ */
1071
1072 /* We don't want libintl.a to depend on any other library.  So we
1073    avoid the non-standard function stpcpy.  In GNU C Library this
1074    function is available, though.  Also allow the symbol HAVE_STPCPY
1075    to be defined.  */
1076 #if !_LIBC && !HAVE_STPCPY
1077 static char *
1078 stpcpy (dest, src)
1079      char *dest;
1080      const char *src;
1081 {
1082   while ((*dest++ = *src++) != '\0')
1083     /* Do nothing. */ ;
1084   return dest - 1;
1085 }
1086 #endif
1087
1088 #if !_LIBC && !HAVE_MEMPCPY
1089 static void *
1090 mempcpy (dest, src, n)
1091      void *dest;
1092      const void *src;
1093      size_t n;
1094 {
1095   return (void *) ((char *) memcpy (dest, src, n) + n);
1096 }
1097 #endif
1098
1099
1100 #ifdef _LIBC
1101 /* If we want to free all resources we have to do some work at
1102    program's end.  */
1103 static void __attribute__ ((unused))
1104 free_mem (void)
1105 {
1106   void *old;
1107
1108   while (_nl_domain_bindings != NULL)
1109     {
1110       struct binding *oldp = _nl_domain_bindings;
1111       _nl_domain_bindings = _nl_domain_bindings->next;
1112       if (oldp->dirname != _nl_default_dirname)
1113         /* Yes, this is a pointer comparison.  */
1114         free (oldp->dirname);
1115       free (oldp->codeset);
1116       free (oldp);
1117     }
1118
1119   if (_nl_current_default_domain != _nl_default_default_domain)
1120     /* Yes, again a pointer comparison.  */
1121     free ((char *) _nl_current_default_domain);
1122
1123   /* Remove the search tree with the known translations.  */
1124   __tdestroy (root, free);
1125   root = NULL;
1126
1127   while (transmem_list != NULL)
1128     {
1129       old = transmem_list;
1130       transmem_list = transmem_list->next;
1131       free (old);
1132     }
1133 }
1134
1135 text_set_element (__libc_subfreeres, free_mem);
1136 #endif