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