(DCIGETTEXT): Increment path_max proportionally.
[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       for (;;)
455         {
456           dirname = (char *) alloca (path_max + dirname_len);
457           ADD_BLOCK (block_list, dirname);
458
459           __set_errno (0);
460           ret = getcwd (dirname, path_max);
461           if (ret != NULL || errno != ERANGE)
462             break;
463
464           path_max += path_max / 2;
465           path_max += PATH_INCR;
466         }
467
468       if (ret == NULL)
469         {
470           /* We cannot get the current working directory.  Don't signal an
471              error but simply return the default string.  */
472           FREE_BLOCKS (block_list);
473           __libc_rwlock_unlock (_nl_state_lock);
474           __set_errno (saved_errno);
475           return (plural == 0
476                   ? (char *) msgid1
477                   /* Use the Germanic plural rule.  */
478                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
479         }
480
481       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
482     }
483
484   /* Now determine the symbolic name of CATEGORY and its value.  */
485   categoryname = category_to_name (category);
486   categoryvalue = guess_category_value (category, categoryname);
487
488   domainname_len = strlen (domainname);
489   xdomainname = (char *) alloca (strlen (categoryname)
490                                  + domainname_len + 5);
491   ADD_BLOCK (block_list, xdomainname);
492
493   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
494                   domainname, domainname_len),
495           ".mo");
496
497   /* Creating working area.  */
498   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
499   ADD_BLOCK (block_list, single_locale);
500
501
502   /* Search for the given string.  This is a loop because we perhaps
503      got an ordered list of languages to consider for the translation.  */
504   while (1)
505     {
506       /* Make CATEGORYVALUE point to the next element of the list.  */
507       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
508         ++categoryvalue;
509       if (categoryvalue[0] == '\0')
510         {
511           /* The whole contents of CATEGORYVALUE has been searched but
512              no valid entry has been found.  We solve this situation
513              by implicitly appending a "C" entry, i.e. no translation
514              will take place.  */
515           single_locale[0] = 'C';
516           single_locale[1] = '\0';
517         }
518       else
519         {
520           char *cp = single_locale;
521           while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
522             *cp++ = *categoryvalue++;
523           *cp = '\0';
524
525           /* When this is a SUID binary we must not allow accessing files
526              outside the dedicated directories.  */
527           if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
528             /* Ingore this entry.  */
529             continue;
530         }
531
532       /* If the current locale value is C (or POSIX) we don't load a
533          domain.  Return the MSGID.  */
534       if (strcmp (single_locale, "C") == 0
535           || strcmp (single_locale, "POSIX") == 0)
536         {
537           FREE_BLOCKS (block_list);
538           __libc_rwlock_unlock (_nl_state_lock);
539           __set_errno (saved_errno);
540           return (plural == 0
541                   ? (char *) msgid1
542                   /* Use the Germanic plural rule.  */
543                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
544         }
545
546
547       /* Find structure describing the message catalog matching the
548          DOMAINNAME and CATEGORY.  */
549       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
550
551       if (domain != NULL)
552         {
553           retval = _nl_find_msg (domain, binding, msgid1, &retlen);
554
555           if (retval == NULL)
556             {
557               int cnt;
558
559               for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
560                 {
561                   retval = _nl_find_msg (domain->successor[cnt], binding,
562                                          msgid1, &retlen);
563
564                   if (retval != NULL)
565                     {
566                       domain = domain->successor[cnt];
567                       break;
568                     }
569                 }
570             }
571
572           if (retval != NULL)
573             {
574               /* Found the translation of MSGID1 in domain DOMAIN:
575                  starting at RETVAL, RETLEN bytes.  */
576               FREE_BLOCKS (block_list);
577               __set_errno (saved_errno);
578 #if defined HAVE_TSEARCH || defined _LIBC
579               if (foundp == NULL)
580                 {
581                   /* Create a new entry and add it to the search tree.  */
582                   struct known_translation_t *newp;
583
584                   newp = (struct known_translation_t *)
585                     malloc (offsetof (struct known_translation_t, msgid)
586                             + msgid_len + domainname_len + 1);
587                   if (newp != NULL)
588                     {
589                       newp->domainname =
590                         mempcpy (newp->msgid, msgid1, msgid_len);
591                       memcpy (newp->domainname, domainname, domainname_len + 1);
592                       newp->category = category;
593                       newp->counter = _nl_msg_cat_cntr;
594                       newp->domain = domain;
595                       newp->translation = retval;
596                       newp->translation_length = retlen;
597
598                       /* Insert the entry in the search tree.  */
599                       foundp = (struct known_translation_t **)
600                         tsearch (newp, &root, transcmp);
601                       if (foundp == NULL
602                           || __builtin_expect (*foundp != newp, 0))
603                         /* The insert failed.  */
604                         free (newp);
605                     }
606                 }
607               else
608                 {
609                   /* We can update the existing entry.  */
610                   (*foundp)->counter = _nl_msg_cat_cntr;
611                   (*foundp)->domain = domain;
612                   (*foundp)->translation = retval;
613                   (*foundp)->translation_length = retlen;
614                 }
615 #endif
616               /* Now deal with plural.  */
617               if (plural)
618                 retval = plural_lookup (domain, n, retval, retlen);
619
620               __libc_rwlock_unlock (_nl_state_lock);
621               return retval;
622             }
623         }
624     }
625   /* NOTREACHED */
626 }
627
628
629 char *
630 internal_function
631 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
632      struct loaded_l10nfile *domain_file;
633      struct binding *domainbinding;
634      const char *msgid;
635      size_t *lengthp;
636 {
637   struct loaded_domain *domain;
638   size_t act;
639   char *result;
640   size_t resultlen;
641
642   if (domain_file->decided == 0)
643     _nl_load_domain (domain_file, domainbinding);
644
645   if (domain_file->data == NULL)
646     return NULL;
647
648   domain = (struct loaded_domain *) domain_file->data;
649
650   /* Locate the MSGID and its translation.  */
651   if (domain->hash_size > 2 && domain->hash_tab != NULL)
652     {
653       /* Use the hashing table.  */
654       nls_uint32 len = strlen (msgid);
655       nls_uint32 hash_val = hash_string (msgid);
656       nls_uint32 idx = hash_val % domain->hash_size;
657       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
658
659       while (1)
660         {
661           nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
662
663           if (nstr == 0)
664             /* Hash table entry is empty.  */
665             return NULL;
666
667           /* Compare msgid with the original string at index nstr-1.
668              We compare the lengths with >=, not ==, because plural entries
669              are represented by strings with an embedded NUL.  */
670           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
671               && (strcmp (msgid,
672                           domain->data + W (domain->must_swap,
673                                             domain->orig_tab[nstr - 1].offset))
674                   == 0))
675             {
676               act = nstr - 1;
677               goto found;
678             }
679
680           if (idx >= domain->hash_size - incr)
681             idx -= domain->hash_size - incr;
682           else
683             idx += incr;
684         }
685       /* NOTREACHED */
686     }
687   else
688     {
689       /* Try the default method:  binary search in the sorted array of
690          messages.  */
691       size_t top, bottom;
692
693       bottom = 0;
694       top = domain->nstrings;
695       while (bottom < top)
696         {
697           int cmp_val;
698
699           act = (bottom + top) / 2;
700           cmp_val = strcmp (msgid, (domain->data
701                                     + W (domain->must_swap,
702                                          domain->orig_tab[act].offset)));
703           if (cmp_val < 0)
704             top = act;
705           else if (cmp_val > 0)
706             bottom = act + 1;
707           else
708             goto found;
709         }
710       /* No translation was found.  */
711       return NULL;
712     }
713
714  found:
715   /* The translation was found at index ACT.  If we have to convert the
716      string to use a different character set, this is the time.  */
717   result = ((char *) domain->data
718             + W (domain->must_swap, domain->trans_tab[act].offset));
719   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
720
721 #if defined _LIBC || HAVE_ICONV
722   if (domain->codeset_cntr
723       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
724     {
725       /* The domain's codeset has changed through bind_textdomain_codeset()
726          since the message catalog was initialized or last accessed.  We
727          have to reinitialize the converter.  */
728       _nl_free_domain_conv (domain);
729       _nl_init_domain_conv (domain_file, domain, domainbinding);
730     }
731
732   if (
733 # ifdef _LIBC
734       domain->conv != (__gconv_t) -1
735 # else
736 #  if HAVE_ICONV
737       domain->conv != (iconv_t) -1
738 #  endif
739 # endif
740       )
741     {
742       /* We are supposed to do a conversion.  First allocate an
743          appropriate table with the same structure as the table
744          of translations in the file, where we can put the pointers
745          to the converted strings in.
746          There is a slight complication with plural entries.  They
747          are represented by consecutive NUL terminated strings.  We
748          handle this case by converting RESULTLEN bytes, including
749          NULs.  */
750
751       if (domain->conv_tab == NULL
752           && ((domain->conv_tab = (char **) calloc (domain->nstrings,
753                                                     sizeof (char *)))
754               == NULL))
755         /* Mark that we didn't succeed allocating a table.  */
756         domain->conv_tab = (char **) -1;
757
758       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
759         /* Nothing we can do, no more memory.  */
760         goto converted;
761
762       if (domain->conv_tab[act] == NULL)
763         {
764           /* We haven't used this string so far, so it is not
765              translated yet.  Do this now.  */
766           /* We use a bit more efficient memory handling.
767              We allocate always larger blocks which get used over
768              time.  This is faster than many small allocations.   */
769           __libc_lock_define_initialized (static, lock)
770 # define INITIAL_BLOCK_SIZE     4080
771           static unsigned char *freemem;
772           static size_t freemem_size;
773
774           const unsigned char *inbuf;
775           unsigned char *outbuf;
776           int malloc_count;
777 # ifndef _LIBC
778           transmem_block_t *transmem_list = NULL;
779 # endif
780
781           __libc_lock_lock (lock);
782
783           inbuf = (const unsigned char *) result;
784           outbuf = freemem + sizeof (size_t);
785
786           malloc_count = 0;
787           while (1)
788             {
789               transmem_block_t *newmem;
790 # ifdef _LIBC
791               size_t non_reversible;
792               int res;
793
794               if (freemem_size < sizeof (size_t))
795                 goto resize_freemem;
796
797               res = __gconv (domain->conv,
798                              &inbuf, inbuf + resultlen,
799                              &outbuf,
800                              outbuf + freemem_size - sizeof (size_t),
801                              &non_reversible);
802
803               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
804                 break;
805
806               if (res != __GCONV_FULL_OUTPUT)
807                 {
808                   __libc_lock_unlock (lock);
809                   goto converted;
810                 }
811
812               inbuf = result;
813 # else
814 #  if HAVE_ICONV
815               const char *inptr = (const char *) inbuf;
816               size_t inleft = resultlen;
817               char *outptr = (char *) outbuf;
818               size_t outleft;
819
820               if (freemem_size < sizeof (size_t))
821                 goto resize_freemem;
822
823               outleft = freemem_size - sizeof (size_t);
824               if (iconv (domain->conv,
825                          (ICONV_CONST char **) &inptr, &inleft,
826                          &outptr, &outleft)
827                   != (size_t) (-1))
828                 {
829                   outbuf = (unsigned char *) outptr;
830                   break;
831                 }
832               if (errno != E2BIG)
833                 {
834                   __libc_lock_unlock (lock);
835                   goto converted;
836                 }
837 #  endif
838 # endif
839
840             resize_freemem:
841               /* We must allocate a new buffer or resize the old one.  */
842               if (malloc_count > 0)
843                 {
844                   ++malloc_count;
845                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
846                   newmem = (transmem_block_t *) realloc (transmem_list,
847                                                          freemem_size);
848 # ifdef _LIBC
849                   if (newmem != NULL)
850                     transmem_list = transmem_list->next;
851                   else
852                     {
853                       struct transmem_list *old = transmem_list;
854
855                       transmem_list = transmem_list->next;
856                       free (old);
857                     }
858 # endif
859                 }
860               else
861                 {
862                   malloc_count = 1;
863                   freemem_size = INITIAL_BLOCK_SIZE;
864                   newmem = (transmem_block_t *) malloc (freemem_size);
865                 }
866               if (__builtin_expect (newmem == NULL, 0))
867                 {
868                   freemem = NULL;
869                   freemem_size = 0;
870                   __libc_lock_unlock (lock);
871                   goto converted;
872                 }
873
874 # ifdef _LIBC
875               /* Add the block to the list of blocks we have to free
876                  at some point.  */
877               newmem->next = transmem_list;
878               transmem_list = newmem;
879
880               freemem = newmem->data;
881               freemem_size -= offsetof (struct transmem_list, data);
882 # else
883               transmem_list = newmem;
884               freemem = newmem;
885 # endif
886
887               outbuf = freemem + sizeof (size_t);
888             }
889
890           /* We have now in our buffer a converted string.  Put this
891              into the table of conversions.  */
892           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
893           domain->conv_tab[act] = (char *) freemem;
894           /* Shrink freemem, but keep it aligned.  */
895           freemem_size -= outbuf - freemem;
896           freemem = outbuf;
897           freemem += freemem_size & (alignof (size_t) - 1);
898           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
899
900           __libc_lock_unlock (lock);
901         }
902
903       /* Now domain->conv_tab[act] contains the translation of all
904          the plural variants.  */
905       result = domain->conv_tab[act] + sizeof (size_t);
906       resultlen = *(size_t *) domain->conv_tab[act];
907     }
908
909  converted:
910   /* The result string is converted.  */
911
912 #endif /* _LIBC || HAVE_ICONV */
913
914   *lengthp = resultlen;
915   return result;
916 }
917
918
919 /* Look up a plural variant.  */
920 static char *
921 internal_function
922 plural_lookup (domain, n, translation, translation_len)
923      struct loaded_l10nfile *domain;
924      unsigned long int n;
925      const char *translation;
926      size_t translation_len;
927 {
928   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
929   unsigned long int index;
930   const char *p;
931
932   index = plural_eval (domaindata->plural, n);
933   if (index >= domaindata->nplurals)
934     /* This should never happen.  It means the plural expression and the
935        given maximum value do not match.  */
936     index = 0;
937
938   /* Skip INDEX strings at TRANSLATION.  */
939   p = translation;
940   while (index-- > 0)
941     {
942 #ifdef _LIBC
943       p = __rawmemchr (p, '\0');
944 #else
945       p = strchr (p, '\0');
946 #endif
947       /* And skip over the NUL byte.  */
948       p++;
949
950       if (p >= translation + translation_len)
951         /* This should never happen.  It means the plural expression
952            evaluated to a value larger than the number of variants
953            available for MSGID1.  */
954         return (char *) translation;
955     }
956   return (char *) p;
957 }
958
959
960 /* Return string representation of locale CATEGORY.  */
961 static const char *
962 internal_function
963 category_to_name (category)
964      int category;
965 {
966   const char *retval;
967
968   switch (category)
969   {
970 #ifdef LC_COLLATE
971   case LC_COLLATE:
972     retval = "LC_COLLATE";
973     break;
974 #endif
975 #ifdef LC_CTYPE
976   case LC_CTYPE:
977     retval = "LC_CTYPE";
978     break;
979 #endif
980 #ifdef LC_MONETARY
981   case LC_MONETARY:
982     retval = "LC_MONETARY";
983     break;
984 #endif
985 #ifdef LC_NUMERIC
986   case LC_NUMERIC:
987     retval = "LC_NUMERIC";
988     break;
989 #endif
990 #ifdef LC_TIME
991   case LC_TIME:
992     retval = "LC_TIME";
993     break;
994 #endif
995 #ifdef LC_MESSAGES
996   case LC_MESSAGES:
997     retval = "LC_MESSAGES";
998     break;
999 #endif
1000 #ifdef LC_RESPONSE
1001   case LC_RESPONSE:
1002     retval = "LC_RESPONSE";
1003     break;
1004 #endif
1005 #ifdef LC_ALL
1006   case LC_ALL:
1007     /* This might not make sense but is perhaps better than any other
1008        value.  */
1009     retval = "LC_ALL";
1010     break;
1011 #endif
1012   default:
1013     /* If you have a better idea for a default value let me know.  */
1014     retval = "LC_XXX";
1015   }
1016
1017   return retval;
1018 }
1019
1020 /* Guess value of current locale from value of the environment variables.  */
1021 static const char *
1022 internal_function
1023 guess_category_value (category, categoryname)
1024      int category;
1025      const char *categoryname;
1026 {
1027   const char *language;
1028   const char *retval;
1029
1030   /* The highest priority value is the `LANGUAGE' environment
1031      variable.  But we don't use the value if the currently selected
1032      locale is the C locale.  This is a GNU extension.  */
1033   language = getenv ("LANGUAGE");
1034   if (language != NULL && language[0] == '\0')
1035     language = NULL;
1036
1037   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1038      `LC_xxx', and `LANG'.  On some systems this can be done by the
1039      `setlocale' function itself.  */
1040 #ifdef _LIBC
1041   retval = setlocale (category, NULL);
1042 #else
1043   retval = _nl_locale_name (category, categoryname);
1044 #endif
1045
1046   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1047 }
1048
1049 /* @@ begin of epilog @@ */
1050
1051 /* We don't want libintl.a to depend on any other library.  So we
1052    avoid the non-standard function stpcpy.  In GNU C Library this
1053    function is available, though.  Also allow the symbol HAVE_STPCPY
1054    to be defined.  */
1055 #if !_LIBC && !HAVE_STPCPY
1056 static char *
1057 stpcpy (dest, src)
1058      char *dest;
1059      const char *src;
1060 {
1061   while ((*dest++ = *src++) != '\0')
1062     /* Do nothing. */ ;
1063   return dest - 1;
1064 }
1065 #endif
1066
1067 #if !_LIBC && !HAVE_MEMPCPY
1068 static void *
1069 mempcpy (dest, src, n)
1070      void *dest;
1071      const void *src;
1072      size_t n;
1073 {
1074   return (void *) ((char *) memcpy (dest, src, n) + n);
1075 }
1076 #endif
1077
1078
1079 #ifdef _LIBC
1080 /* If we want to free all resources we have to do some work at
1081    program's end.  */
1082 static void __attribute__ ((unused))
1083 free_mem (void)
1084 {
1085   void *old;
1086
1087   while (_nl_domain_bindings != NULL)
1088     {
1089       struct binding *oldp = _nl_domain_bindings;
1090       _nl_domain_bindings = _nl_domain_bindings->next;
1091       if (oldp->dirname != _nl_default_dirname)
1092         /* Yes, this is a pointer comparison.  */
1093         free (oldp->dirname);
1094       free (oldp->codeset);
1095       free (oldp);
1096     }
1097
1098   if (_nl_current_default_domain != _nl_default_default_domain)
1099     /* Yes, again a pointer comparison.  */
1100     free ((char *) _nl_current_default_domain);
1101
1102   /* Remove the search tree with the known translations.  */
1103   __tdestroy (root, free);
1104   root = NULL;
1105
1106   while (transmem_list != NULL)
1107     {
1108       old = transmem_list;
1109       transmem_list = transmem_list->next;
1110       free (old);
1111     }
1112 }
1113
1114 text_set_element (__libc_subfreeres, free_mem);
1115 #endif