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