Remove support for CEN-style locale variables. It was never used and
[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   size_t act;
640   char *result;
641   size_t resultlen;
642
643   if (domain_file->decided == 0)
644     _nl_load_domain (domain_file, domainbinding);
645
646   if (domain_file->data == NULL)
647     return NULL;
648
649   domain = (struct loaded_domain *) domain_file->data;
650
651   /* Locate the MSGID and its translation.  */
652   if (domain->hash_size > 2 && domain->hash_tab != NULL)
653     {
654       /* Use the hashing table.  */
655       nls_uint32 len = strlen (msgid);
656       nls_uint32 hash_val = hash_string (msgid);
657       nls_uint32 idx = hash_val % domain->hash_size;
658       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
659
660       while (1)
661         {
662           nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
663
664           if (nstr == 0)
665             /* Hash table entry is empty.  */
666             return NULL;
667
668           /* Compare msgid with the original string at index nstr-1.
669              We compare the lengths with >=, not ==, because plural entries
670              are represented by strings with an embedded NUL.  */
671           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
672               && (strcmp (msgid,
673                           domain->data + W (domain->must_swap,
674                                             domain->orig_tab[nstr - 1].offset))
675                   == 0))
676             {
677               act = nstr - 1;
678               goto found;
679             }
680
681           if (idx >= domain->hash_size - incr)
682             idx -= domain->hash_size - incr;
683           else
684             idx += incr;
685         }
686       /* NOTREACHED */
687     }
688   else
689     {
690       /* Try the default method:  binary search in the sorted array of
691          messages.  */
692       size_t top, bottom;
693
694       bottom = 0;
695       top = domain->nstrings;
696       while (bottom < top)
697         {
698           int cmp_val;
699
700           act = (bottom + top) / 2;
701           cmp_val = strcmp (msgid, (domain->data
702                                     + W (domain->must_swap,
703                                          domain->orig_tab[act].offset)));
704           if (cmp_val < 0)
705             top = act;
706           else if (cmp_val > 0)
707             bottom = act + 1;
708           else
709             goto found;
710         }
711       /* No translation was found.  */
712       return NULL;
713     }
714
715  found:
716   /* The translation was found at index ACT.  If we have to convert the
717      string to use a different character set, this is the time.  */
718   result = ((char *) domain->data
719             + W (domain->must_swap, domain->trans_tab[act].offset));
720   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
721
722 #if defined _LIBC || HAVE_ICONV
723   if (domain->codeset_cntr
724       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
725     {
726       /* The domain's codeset has changed through bind_textdomain_codeset()
727          since the message catalog was initialized or last accessed.  We
728          have to reinitialize the converter.  */
729       _nl_free_domain_conv (domain);
730       _nl_init_domain_conv (domain_file, domain, domainbinding);
731     }
732
733   if (
734 # ifdef _LIBC
735       domain->conv != (__gconv_t) -1
736 # else
737 #  if HAVE_ICONV
738       domain->conv != (iconv_t) -1
739 #  endif
740 # endif
741       )
742     {
743       /* We are supposed to do a conversion.  First allocate an
744          appropriate table with the same structure as the table
745          of translations in the file, where we can put the pointers
746          to the converted strings in.
747          There is a slight complication with plural entries.  They
748          are represented by consecutive NUL terminated strings.  We
749          handle this case by converting RESULTLEN bytes, including
750          NULs.  */
751
752       if (domain->conv_tab == NULL
753           && ((domain->conv_tab = (char **) calloc (domain->nstrings,
754                                                     sizeof (char *)))
755               == NULL))
756         /* Mark that we didn't succeed allocating a table.  */
757         domain->conv_tab = (char **) -1;
758
759       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
760         /* Nothing we can do, no more memory.  */
761         goto converted;
762
763       if (domain->conv_tab[act] == NULL)
764         {
765           /* We haven't used this string so far, so it is not
766              translated yet.  Do this now.  */
767           /* We use a bit more efficient memory handling.
768              We allocate always larger blocks which get used over
769              time.  This is faster than many small allocations.   */
770           __libc_lock_define_initialized (static, lock)
771 # define INITIAL_BLOCK_SIZE     4080
772           static unsigned char *freemem;
773           static size_t freemem_size;
774
775           const unsigned char *inbuf;
776           unsigned char *outbuf;
777           int malloc_count;
778 # ifndef _LIBC
779           transmem_block_t *transmem_list = NULL;
780 # endif
781
782           __libc_lock_lock (lock);
783
784           inbuf = (const unsigned char *) result;
785           outbuf = freemem + sizeof (size_t);
786
787           malloc_count = 0;
788           while (1)
789             {
790               transmem_block_t *newmem;
791 # ifdef _LIBC
792               size_t non_reversible;
793               int res;
794
795               if (freemem_size < sizeof (size_t))
796                 goto resize_freemem;
797
798               res = __gconv (domain->conv,
799                              &inbuf, inbuf + resultlen,
800                              &outbuf,
801                              outbuf + freemem_size - sizeof (size_t),
802                              &non_reversible);
803
804               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
805                 break;
806
807               if (res != __GCONV_FULL_OUTPUT)
808                 {
809                   __libc_lock_unlock (lock);
810                   goto converted;
811                 }
812
813               inbuf = result;
814 # else
815 #  if HAVE_ICONV
816               const char *inptr = (const char *) inbuf;
817               size_t inleft = resultlen;
818               char *outptr = (char *) outbuf;
819               size_t outleft;
820
821               if (freemem_size < sizeof (size_t))
822                 goto resize_freemem;
823
824               outleft = freemem_size - sizeof (size_t);
825               if (iconv (domain->conv,
826                          (ICONV_CONST char **) &inptr, &inleft,
827                          &outptr, &outleft)
828                   != (size_t) (-1))
829                 {
830                   outbuf = (unsigned char *) outptr;
831                   break;
832                 }
833               if (errno != E2BIG)
834                 {
835                   __libc_lock_unlock (lock);
836                   goto converted;
837                 }
838 #  endif
839 # endif
840
841             resize_freemem:
842               /* We must allocate a new buffer or resize the old one.  */
843               if (malloc_count > 0)
844                 {
845                   ++malloc_count;
846                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
847                   newmem = (transmem_block_t *) realloc (transmem_list,
848                                                          freemem_size);
849 # ifdef _LIBC
850                   if (newmem != NULL)
851                     transmem_list = transmem_list->next;
852                   else
853                     {
854                       struct transmem_list *old = transmem_list;
855
856                       transmem_list = transmem_list->next;
857                       free (old);
858                     }
859 # endif
860                 }
861               else
862                 {
863                   malloc_count = 1;
864                   freemem_size = INITIAL_BLOCK_SIZE;
865                   newmem = (transmem_block_t *) malloc (freemem_size);
866                 }
867               if (__builtin_expect (newmem == NULL, 0))
868                 {
869                   freemem = NULL;
870                   freemem_size = 0;
871                   __libc_lock_unlock (lock);
872                   goto converted;
873                 }
874
875 # ifdef _LIBC
876               /* Add the block to the list of blocks we have to free
877                  at some point.  */
878               newmem->next = transmem_list;
879               transmem_list = newmem;
880
881               freemem = newmem->data;
882               freemem_size -= offsetof (struct transmem_list, data);
883 # else
884               transmem_list = newmem;
885               freemem = newmem;
886 # endif
887
888               outbuf = freemem + sizeof (size_t);
889             }
890
891           /* We have now in our buffer a converted string.  Put this
892              into the table of conversions.  */
893           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
894           domain->conv_tab[act] = (char *) freemem;
895           /* Shrink freemem, but keep it aligned.  */
896           freemem_size -= outbuf - freemem;
897           freemem = outbuf;
898           freemem += freemem_size & (alignof (size_t) - 1);
899           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
900
901           __libc_lock_unlock (lock);
902         }
903
904       /* Now domain->conv_tab[act] contains the translation of all
905          the plural variants.  */
906       result = domain->conv_tab[act] + sizeof (size_t);
907       resultlen = *(size_t *) domain->conv_tab[act];
908     }
909
910  converted:
911   /* The result string is converted.  */
912
913 #endif /* _LIBC || HAVE_ICONV */
914
915   *lengthp = resultlen;
916   return result;
917 }
918
919
920 /* Look up a plural variant.  */
921 static char *
922 internal_function
923 plural_lookup (domain, n, translation, translation_len)
924      struct loaded_l10nfile *domain;
925      unsigned long int n;
926      const char *translation;
927      size_t translation_len;
928 {
929   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
930   unsigned long int index;
931   const char *p;
932
933   index = plural_eval (domaindata->plural, n);
934   if (index >= domaindata->nplurals)
935     /* This should never happen.  It means the plural expression and the
936        given maximum value do not match.  */
937     index = 0;
938
939   /* Skip INDEX strings at TRANSLATION.  */
940   p = translation;
941   while (index-- > 0)
942     {
943 #ifdef _LIBC
944       p = __rawmemchr (p, '\0');
945 #else
946       p = strchr (p, '\0');
947 #endif
948       /* And skip over the NUL byte.  */
949       p++;
950
951       if (p >= translation + translation_len)
952         /* This should never happen.  It means the plural expression
953            evaluated to a value larger than the number of variants
954            available for MSGID1.  */
955         return (char *) translation;
956     }
957   return (char *) p;
958 }
959
960
961 /* Return string representation of locale CATEGORY.  */
962 static const char *
963 internal_function
964 category_to_name (category)
965      int category;
966 {
967   const char *retval;
968
969   switch (category)
970   {
971 #ifdef LC_COLLATE
972   case LC_COLLATE:
973     retval = "LC_COLLATE";
974     break;
975 #endif
976 #ifdef LC_CTYPE
977   case LC_CTYPE:
978     retval = "LC_CTYPE";
979     break;
980 #endif
981 #ifdef LC_MONETARY
982   case LC_MONETARY:
983     retval = "LC_MONETARY";
984     break;
985 #endif
986 #ifdef LC_NUMERIC
987   case LC_NUMERIC:
988     retval = "LC_NUMERIC";
989     break;
990 #endif
991 #ifdef LC_TIME
992   case LC_TIME:
993     retval = "LC_TIME";
994     break;
995 #endif
996 #ifdef LC_MESSAGES
997   case LC_MESSAGES:
998     retval = "LC_MESSAGES";
999     break;
1000 #endif
1001 #ifdef LC_RESPONSE
1002   case LC_RESPONSE:
1003     retval = "LC_RESPONSE";
1004     break;
1005 #endif
1006 #ifdef LC_ALL
1007   case LC_ALL:
1008     /* This might not make sense but is perhaps better than any other
1009        value.  */
1010     retval = "LC_ALL";
1011     break;
1012 #endif
1013   default:
1014     /* If you have a better idea for a default value let me know.  */
1015     retval = "LC_XXX";
1016   }
1017
1018   return retval;
1019 }
1020
1021 /* Guess value of current locale from value of the environment variables.  */
1022 static const char *
1023 internal_function
1024 guess_category_value (category, categoryname)
1025      int category;
1026      const char *categoryname;
1027 {
1028   const char *language;
1029   const char *retval;
1030
1031   /* The highest priority value is the `LANGUAGE' environment
1032      variable.  But we don't use the value if the currently selected
1033      locale is the C locale.  This is a GNU extension.  */
1034   language = getenv ("LANGUAGE");
1035   if (language != NULL && language[0] == '\0')
1036     language = NULL;
1037
1038   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1039      `LC_xxx', and `LANG'.  On some systems this can be done by the
1040      `setlocale' function itself.  */
1041 #ifdef _LIBC
1042   retval = setlocale (category, NULL);
1043 #else
1044   retval = _nl_locale_name (category, categoryname);
1045 #endif
1046
1047   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1048 }
1049
1050 /* @@ begin of epilog @@ */
1051
1052 /* We don't want libintl.a to depend on any other library.  So we
1053    avoid the non-standard function stpcpy.  In GNU C Library this
1054    function is available, though.  Also allow the symbol HAVE_STPCPY
1055    to be defined.  */
1056 #if !_LIBC && !HAVE_STPCPY
1057 static char *
1058 stpcpy (dest, src)
1059      char *dest;
1060      const char *src;
1061 {
1062   while ((*dest++ = *src++) != '\0')
1063     /* Do nothing. */ ;
1064   return dest - 1;
1065 }
1066 #endif
1067
1068 #if !_LIBC && !HAVE_MEMPCPY
1069 static void *
1070 mempcpy (dest, src, n)
1071      void *dest;
1072      const void *src;
1073      size_t n;
1074 {
1075   return (void *) ((char *) memcpy (dest, src, n) + n);
1076 }
1077 #endif
1078
1079
1080 #ifdef _LIBC
1081 /* If we want to free all resources we have to do some work at
1082    program's end.  */
1083 static void __attribute__ ((unused))
1084 free_mem (void)
1085 {
1086   void *old;
1087
1088   while (_nl_domain_bindings != NULL)
1089     {
1090       struct binding *oldp = _nl_domain_bindings;
1091       _nl_domain_bindings = _nl_domain_bindings->next;
1092       if (oldp->dirname != _nl_default_dirname)
1093         /* Yes, this is a pointer comparison.  */
1094         free (oldp->dirname);
1095       free (oldp->codeset);
1096       free (oldp);
1097     }
1098
1099   if (_nl_current_default_domain != _nl_default_default_domain)
1100     /* Yes, again a pointer comparison.  */
1101     free ((char *) _nl_current_default_domain);
1102
1103   /* Remove the search tree with the known translations.  */
1104   __tdestroy (root, free);
1105   root = NULL;
1106
1107   while (transmem_list != NULL)
1108     {
1109       old = transmem_list;
1110       transmem_list = transmem_list->next;
1111       free (old);
1112     }
1113 }
1114
1115 text_set_element (__libc_subfreeres, free_mem);
1116 #endif