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