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