upload tizen1.0 source
[external/popt.git] / intl / dcigettext.c
1 /* Implementation of the internal dcigettext function.
2    Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17    USA.  */
18
19 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
20    This must come before <config.h> because <config.h> may include
21    <features.h>, and once <features.h> has been included, it's too late.  */
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE    1
24 #endif
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <sys/types.h>
31
32 #ifdef __GNUC__
33 # define alloca __builtin_alloca
34 # define HAVE_ALLOCA 1
35 #else
36 # if defined HAVE_ALLOCA_H || defined _LIBC
37 #  include <alloca.h>
38 # else
39 #  ifdef _AIX
40  #pragma alloca
41 #  else
42 #   ifndef alloca
43 char *alloca ();
44 #   endif
45 #  endif
46 # endif
47 #endif
48
49 #include <errno.h>
50 #ifndef errno
51 extern int errno;
52 #endif
53 #ifndef __set_errno
54 # define __set_errno(val) errno = (val)
55 #endif
56
57 #include <stddef.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #if defined HAVE_UNISTD_H || defined _LIBC
62 # include <unistd.h>
63 #endif
64
65 #include <locale.h>
66
67 #if defined HAVE_SYS_PARAM_H || defined _LIBC
68 # include <sys/param.h>
69 #endif
70
71 #include "gettextP.h"
72 #include "plural-exp.h"
73 #ifdef _LIBC
74 # include <libintl.h>
75 #else
76 # include "libgnuintl.h"
77 #endif
78 #include "hash-string.h"
79
80 /* Thread safetyness.  */
81 #ifdef _LIBC
82 # include <bits/libc-lock.h>
83 #else
84 /* Provide dummy implementation if this is outside glibc.  */
85 # define __libc_lock_define_initialized(CLASS, NAME)
86 # define __libc_lock_lock(NAME)
87 # define __libc_lock_unlock(NAME)
88 # define __libc_rwlock_define_initialized(CLASS, NAME)
89 # define __libc_rwlock_rdlock(NAME)
90 # define __libc_rwlock_unlock(NAME)
91 #endif
92
93 /* Alignment of types.  */
94 #if defined __GNUC__ && __GNUC__ >= 2
95 # define alignof(TYPE) __alignof__ (TYPE)
96 #else
97 # define alignof(TYPE) \
98     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
99 #endif
100
101 /* The internal variables in the standalone libintl.a must have different
102    names than the internal variables in GNU libc, otherwise programs
103    using libintl.a cannot be linked statically.  */
104 #if !defined _LIBC
105 # define _nl_default_default_domain _nl_default_default_domain__
106 # define _nl_current_default_domain _nl_current_default_domain__
107 # define _nl_default_dirname _nl_default_dirname__
108 # define _nl_domain_bindings _nl_domain_bindings__
109 #endif
110
111 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
112 #ifndef offsetof
113 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
114 #endif
115
116 /* @@ end of prolog @@ */
117
118 #ifdef _LIBC
119 /* Rename the non ANSI C functions.  This is required by the standard
120    because some ANSI C functions will require linking with this object
121    file and the name space must not be polluted.  */
122 # define getcwd __getcwd
123 # ifndef stpcpy
124 #  define stpcpy __stpcpy
125 # endif
126 # define tfind __tfind
127 #else
128 # if !defined HAVE_GETCWD
129 char *getwd ();
130 #  define getcwd(buf, max) getwd (buf)
131 # else
132 char *getcwd ();
133 # endif
134 # ifndef HAVE_STPCPY
135 static char *stpcpy PARAMS ((char *dest, const char *src));
136 # endif
137 # ifndef HAVE_MEMPCPY
138 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
139 # endif
140 #endif
141
142 /* Amount to increase buffer size by in each try.  */
143 #define PATH_INCR 32
144
145 /* The following is from pathmax.h.  */
146 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
147    PATH_MAX but might cause redefinition warnings when sys/param.h is
148    later included (as on MORE/BSD 4.3).  */
149 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
150 # include <limits.h>
151 #endif
152
153 #ifndef _POSIX_PATH_MAX
154 # define _POSIX_PATH_MAX 255
155 #endif
156
157 #if !defined PATH_MAX && defined _PC_PATH_MAX
158 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
159 #endif
160
161 /* Don't include sys/param.h if it already has been.  */
162 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
163 # include <sys/param.h>
164 #endif
165
166 #if !defined PATH_MAX && defined MAXPATHLEN
167 # define PATH_MAX MAXPATHLEN
168 #endif
169
170 #ifndef PATH_MAX
171 # define PATH_MAX _POSIX_PATH_MAX
172 #endif
173
174 /* Pathname support.
175    ISSLASH(C)           tests whether C is a directory separator character.
176    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
177                         it may be concatenated to a directory pathname.
178    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
179  */
180 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
181   /* Win32, OS/2, DOS */
182 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
183 # define HAS_DEVICE(P) \
184     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
185      && (P)[1] == ':')
186 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
187 # define IS_PATH_WITH_DIR(P) \
188     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
189 #else
190   /* Unix */
191 # define ISSLASH(C) ((C) == '/')
192 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
193 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
194 #endif
195
196 /* This is the type used for the search tree where known translations
197    are stored.  */
198 struct known_translation_t
199 {
200   /* Domain in which to search.  */
201   char *domainname;
202
203   /* The category.  */
204   int category;
205
206   /* State of the catalog counter at the point the string was found.  */
207   int counter;
208
209   /* Catalog where the string was found.  */
210   struct loaded_l10nfile *domain;
211
212   /* And finally the translation.  */
213   const char *translation;
214   size_t translation_length;
215
216   /* Pointer to the string in question.  */
217   char msgid[ZERO];
218 };
219
220 /* Root of the search tree with known translations.  We can use this
221    only if the system provides the `tsearch' function family.  */
222 #if defined HAVE_TSEARCH || defined _LIBC
223 # include <search.h>
224
225 static void *root;
226
227 # ifdef _LIBC
228 #  define tsearch __tsearch
229 # endif
230
231 /* Function to compare two entries in the table of known translations.  */
232 static int transcmp PARAMS ((const void *p1, const void *p2));
233 static int
234 transcmp (p1, p2)
235      const void *p1;
236      const void *p2;
237 {
238   const struct known_translation_t *s1;
239   const struct known_translation_t *s2;
240   int result;
241
242   s1 = (const struct known_translation_t *) p1;
243   s2 = (const struct known_translation_t *) p2;
244
245   result = strcmp (s1->msgid, s2->msgid);
246   if (result == 0)
247     {
248       result = strcmp (s1->domainname, s2->domainname);
249       if (result == 0)
250         /* We compare the category last (though this is the cheapest
251            operation) since it is hopefully always the same (namely
252            LC_MESSAGES).  */
253         result = s1->category - s2->category;
254     }
255
256   return result;
257 }
258 #endif
259
260 /* Name of the default domain used for gettext(3) prior any call to
261    textdomain(3).  The default value for this is "messages".  */
262 const char _nl_default_default_domain[] attribute_hidden = "messages";
263
264 /* Value used as the default domain for gettext(3).  */
265 const char *_nl_current_default_domain attribute_hidden
266      = _nl_default_default_domain;
267
268 /* Contains the default location of the message catalogs.  */
269 #if defined __EMX__
270 extern const char _nl_default_dirname[];
271 #else
272 const char _nl_default_dirname[] = LOCALEDIR;
273 #endif
274
275 /* List with bindings of specific domains created by bindtextdomain()
276    calls.  */
277 struct binding *_nl_domain_bindings;
278
279 /* Prototypes for local functions.  */
280 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
281                                     unsigned long int n,
282                                     const char *translation,
283                                     size_t translation_len))
284      internal_function;
285 static const char *category_to_name PARAMS ((int category)) internal_function;
286 static const char *guess_category_value PARAMS ((int category,
287                                                  const char *categoryname))
288      internal_function;
289
290
291 /* For those loosing systems which don't have `alloca' we have to add
292    some additional code emulating it.  */
293 #ifdef HAVE_ALLOCA
294 /* Nothing has to be done.  */
295 # define ADD_BLOCK(list, address) /* nothing */
296 # define FREE_BLOCKS(list) /* nothing */
297 #else
298 struct block_list
299 {
300   void *address;
301   struct block_list *next;
302 };
303 # define ADD_BLOCK(list, addr)                                                \
304   do {                                                                        \
305     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
306     /* If we cannot get a free block we cannot add the new element to         \
307        the list.  */                                                          \
308     if (newp != NULL) {                                                       \
309       newp->address = (addr);                                                 \
310       newp->next = (list);                                                    \
311       (list) = newp;                                                          \
312     }                                                                         \
313   } while (0)
314 # define FREE_BLOCKS(list)                                                    \
315   do {                                                                        \
316     while (list != NULL) {                                                    \
317       struct block_list *old = list;                                          \
318       list = list->next;                                                      \
319       free (old);                                                             \
320     }                                                                         \
321   } while (0)
322 # undef alloca
323 # define alloca(size) (malloc (size))
324 #endif  /* have alloca */
325
326
327 #ifdef _LIBC
328 /* List of blocks allocated for translations.  */
329 typedef struct transmem_list
330 {
331   struct transmem_list *next;
332   char data[ZERO];
333 } transmem_block_t;
334 static struct transmem_list *transmem_list;
335 #else
336 typedef unsigned char transmem_block_t;
337 #endif
338
339
340 /* Names for the libintl functions are a problem.  They must not clash
341    with existing names and they should follow ANSI C.  But this source
342    code is also used in GNU C Library where the names have a __
343    prefix.  So we have to make a difference here.  */
344 #ifdef _LIBC
345 # define DCIGETTEXT __dcigettext
346 #else
347 # define DCIGETTEXT dcigettext__
348 #endif
349
350 /* Lock variable to protect the global data in the gettext implementation.  */
351 #ifdef _LIBC
352 __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
353 #endif
354
355 /* Checking whether the binaries runs SUID must be done and glibc provides
356    easier methods therefore we make a difference here.  */
357 #ifdef _LIBC
358 # define ENABLE_SECURE __libc_enable_secure
359 # define DETERMINE_SECURE
360 #else
361 # ifndef HAVE_GETUID
362 #  define getuid() 0
363 # endif
364 # ifndef HAVE_GETGID
365 #  define getgid() 0
366 # endif
367 # ifndef HAVE_GETEUID
368 #  define geteuid() getuid()
369 # endif
370 # ifndef HAVE_GETEGID
371 #  define getegid() getgid()
372 # endif
373 static int enable_secure;
374 # define ENABLE_SECURE (enable_secure == 1)
375 # define DETERMINE_SECURE \
376   if (enable_secure == 0)                                                     \
377     {                                                                         \
378       if (getuid () != geteuid () || getgid () != getegid ())                 \
379         enable_secure = 1;                                                    \
380       else                                                                    \
381         enable_secure = -1;                                                   \
382     }
383 #endif
384
385 /* Get the function to evaluate the plural expression.  */
386 #include "eval-plural.h"
387
388 /* Look up MSGID in the DOMAINNAME message catalog for the current
389    CATEGORY locale and, if PLURAL is nonzero, search over string
390    depending on the plural form determined by N.  */
391 char *
392 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
393      const char *domainname;
394      const char *msgid1;
395      const char *msgid2;
396      int plural;
397      unsigned long int n;
398      int category;
399 {
400 #ifndef HAVE_ALLOCA
401   struct block_list *block_list = NULL;
402 #endif
403   struct loaded_l10nfile *domain;
404   struct binding *binding;
405   const char *categoryname;
406   const char *categoryvalue;
407   char *dirname, *xdomainname;
408   char *single_locale;
409   char *retval;
410   size_t retlen;
411   int saved_errno;
412 #if defined HAVE_TSEARCH || defined _LIBC
413   struct known_translation_t *search;
414   struct known_translation_t **foundp = NULL;
415   size_t msgid_len;
416 #endif
417   size_t domainname_len;
418
419   /* If no real MSGID is given return NULL.  */
420   if (msgid1 == NULL)
421     return NULL;
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   /* OS/2 specific: backward compatibility with older libintl versions  */
432 #ifdef LC_MESSAGES_COMPAT
433   if (category == LC_MESSAGES_COMPAT)
434     category = LC_MESSAGES;
435 #endif
436
437 #if defined HAVE_TSEARCH || defined _LIBC
438   msgid_len = strlen (msgid1) + 1;
439
440   /* Try to find the translation among those which we found at
441      some time.  */
442   search = (struct known_translation_t *)
443            alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
444   memcpy (search->msgid, msgid1, msgid_len);
445   search->domainname = (char *) domainname;
446   search->category = category;
447
448   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
449   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
450     {
451       /* Now deal with plural.  */
452       if (plural)
453         retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
454                                 (*foundp)->translation_length);
455       else
456         retval = (char *) (*foundp)->translation;
457
458       __libc_rwlock_unlock (_nl_state_lock);
459       return retval;
460     }
461 #endif
462
463   /* Preserve the `errno' value.  */
464   saved_errno = errno;
465
466   /* See whether this is a SUID binary or not.  */
467   DETERMINE_SECURE;
468
469   /* First find matching binding.  */
470   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
471     {
472       int compare = strcmp (domainname, binding->domainname);
473       if (compare == 0)
474         /* We found it!  */
475         break;
476       if (compare < 0)
477         {
478           /* It is not in the list.  */
479           binding = NULL;
480           break;
481         }
482     }
483
484   if (binding == NULL)
485     dirname = (char *) _nl_default_dirname;
486   else if (IS_ABSOLUTE_PATH (binding->dirname))
487     dirname = binding->dirname;
488   else
489     {
490       /* We have a relative path.  Make it absolute now.  */
491       size_t dirname_len = strlen (binding->dirname) + 1;
492       size_t path_max;
493       char *ret;
494
495       path_max = (unsigned int) PATH_MAX;
496       path_max += 2;            /* The getcwd docs say to do this.  */
497
498       for (;;)
499         {
500           dirname = (char *) alloca (path_max + dirname_len);
501           ADD_BLOCK (block_list, dirname);
502
503           __set_errno (0);
504           ret = getcwd (dirname, path_max);
505           if (ret != NULL || errno != ERANGE)
506             break;
507
508           path_max += path_max / 2;
509           path_max += PATH_INCR;
510         }
511
512       if (ret == NULL)
513         {
514           /* We cannot get the current working directory.  Don't signal an
515              error but simply return the default string.  */
516           FREE_BLOCKS (block_list);
517           __libc_rwlock_unlock (_nl_state_lock);
518           __set_errno (saved_errno);
519           return (plural == 0
520                   ? (char *) msgid1
521                   /* Use the Germanic plural rule.  */
522                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
523         }
524
525       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
526     }
527
528   /* Now determine the symbolic name of CATEGORY and its value.  */
529   categoryname = category_to_name (category);
530   categoryvalue = guess_category_value (category, categoryname);
531
532   domainname_len = strlen (domainname);
533   xdomainname = (char *) alloca (strlen (categoryname)
534                                  + domainname_len + 5);
535   ADD_BLOCK (block_list, xdomainname);
536
537   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
538                   domainname, domainname_len),
539           ".mo");
540
541   /* Creating working area.  */
542   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
543   ADD_BLOCK (block_list, single_locale);
544
545
546   /* Search for the given string.  This is a loop because we perhaps
547      got an ordered list of languages to consider for the translation.  */
548   while (1)
549     {
550       /* Make CATEGORYVALUE point to the next element of the list.  */
551       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
552         ++categoryvalue;
553       if (categoryvalue[0] == '\0')
554         {
555           /* The whole contents of CATEGORYVALUE has been searched but
556              no valid entry has been found.  We solve this situation
557              by implicitly appending a "C" entry, i.e. no translation
558              will take place.  */
559           single_locale[0] = 'C';
560           single_locale[1] = '\0';
561         }
562       else
563         {
564           char *cp = single_locale;
565           while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
566             *cp++ = *categoryvalue++;
567           *cp = '\0';
568
569           /* When this is a SUID binary we must not allow accessing files
570              outside the dedicated directories.  */
571           if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
572             /* Ingore this entry.  */
573             continue;
574         }
575
576       /* If the current locale value is C (or POSIX) we don't load a
577          domain.  Return the MSGID.  */
578       if (strcmp (single_locale, "C") == 0
579           || strcmp (single_locale, "POSIX") == 0)
580         {
581           FREE_BLOCKS (block_list);
582           __libc_rwlock_unlock (_nl_state_lock);
583           __set_errno (saved_errno);
584           return (plural == 0
585                   ? (char *) msgid1
586                   /* Use the Germanic plural rule.  */
587                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
588         }
589
590
591       /* Find structure describing the message catalog matching the
592          DOMAINNAME and CATEGORY.  */
593       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
594
595       if (domain != NULL)
596         {
597           retval = _nl_find_msg (domain, binding, msgid1, &retlen);
598
599           if (retval == NULL)
600             {
601               int cnt;
602
603               for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
604                 {
605                   retval = _nl_find_msg (domain->successor[cnt], binding,
606                                          msgid1, &retlen);
607
608                   if (retval != NULL)
609                     {
610                       domain = domain->successor[cnt];
611                       break;
612                     }
613                 }
614             }
615
616           if (retval != NULL)
617             {
618               /* Found the translation of MSGID1 in domain DOMAIN:
619                  starting at RETVAL, RETLEN bytes.  */
620               FREE_BLOCKS (block_list);
621               __set_errno (saved_errno);
622 #if defined HAVE_TSEARCH || defined _LIBC
623               if (foundp == NULL)
624                 {
625                   /* Create a new entry and add it to the search tree.  */
626                   struct known_translation_t *newp;
627
628                   newp = (struct known_translation_t *)
629                     malloc (offsetof (struct known_translation_t, msgid)
630                             + msgid_len + domainname_len + 1);
631                   if (newp != NULL)
632                     {
633                       newp->domainname =
634                         mempcpy (newp->msgid, msgid1, msgid_len);
635                       memcpy (newp->domainname, domainname, domainname_len + 1);
636                       newp->category = category;
637                       newp->counter = _nl_msg_cat_cntr;
638                       newp->domain = domain;
639                       newp->translation = retval;
640                       newp->translation_length = retlen;
641
642                       /* Insert the entry in the search tree.  */
643                       foundp = (struct known_translation_t **)
644                         tsearch (newp, &root, transcmp);
645                       if (foundp == NULL
646                           || __builtin_expect (*foundp != newp, 0))
647                         /* The insert failed.  */
648                         free (newp);
649                     }
650                 }
651               else
652                 {
653                   /* We can update the existing entry.  */
654                   (*foundp)->counter = _nl_msg_cat_cntr;
655                   (*foundp)->domain = domain;
656                   (*foundp)->translation = retval;
657                   (*foundp)->translation_length = retlen;
658                 }
659 #endif
660               /* Now deal with plural.  */
661               if (plural)
662                 retval = plural_lookup (domain, n, retval, retlen);
663
664               __libc_rwlock_unlock (_nl_state_lock);
665               return retval;
666             }
667         }
668     }
669   /* NOTREACHED */
670 }
671
672
673 char *
674 internal_function
675 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
676      struct loaded_l10nfile *domain_file;
677      struct binding *domainbinding;
678      const char *msgid;
679      size_t *lengthp;
680 {
681   struct loaded_domain *domain;
682   size_t act;
683   char *result;
684   size_t resultlen;
685
686   if (domain_file->decided == 0)
687     _nl_load_domain (domain_file, domainbinding);
688
689   if (domain_file->data == NULL)
690     return NULL;
691
692   domain = (struct loaded_domain *) domain_file->data;
693
694   /* Locate the MSGID and its translation.  */
695   if (domain->hash_size > 2 && domain->hash_tab != NULL)
696     {
697       /* Use the hashing table.  */
698       nls_uint32 len = strlen (msgid);
699       nls_uint32 hash_val = hash_string (msgid);
700       nls_uint32 idx = hash_val % domain->hash_size;
701       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
702
703       while (1)
704         {
705           nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
706
707           if (nstr == 0)
708             /* Hash table entry is empty.  */
709             return NULL;
710
711           /* Compare msgid with the original string at index nstr-1.
712              We compare the lengths with >=, not ==, because plural entries
713              are represented by strings with an embedded NUL.  */
714           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
715               && (strcmp (msgid,
716                           domain->data + W (domain->must_swap,
717                                             domain->orig_tab[nstr - 1].offset))
718                   == 0))
719             {
720               act = nstr - 1;
721               goto found;
722             }
723
724           if (idx >= domain->hash_size - incr)
725             idx -= domain->hash_size - incr;
726           else
727             idx += incr;
728         }
729       /* NOTREACHED */
730     }
731   else
732     {
733       /* Try the default method:  binary search in the sorted array of
734          messages.  */
735       size_t top, bottom;
736
737       bottom = 0;
738       top = domain->nstrings;
739       while (bottom < top)
740         {
741           int cmp_val;
742
743           act = (bottom + top) / 2;
744           cmp_val = strcmp (msgid, (domain->data
745                                     + W (domain->must_swap,
746                                          domain->orig_tab[act].offset)));
747           if (cmp_val < 0)
748             top = act;
749           else if (cmp_val > 0)
750             bottom = act + 1;
751           else
752             goto found;
753         }
754       /* No translation was found.  */
755       return NULL;
756     }
757
758  found:
759   /* The translation was found at index ACT.  If we have to convert the
760      string to use a different character set, this is the time.  */
761   result = ((char *) domain->data
762             + W (domain->must_swap, domain->trans_tab[act].offset));
763   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
764
765 #if defined _LIBC || HAVE_ICONV
766   if (domain->codeset_cntr
767       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
768     {
769       /* The domain's codeset has changed through bind_textdomain_codeset()
770          since the message catalog was initialized or last accessed.  We
771          have to reinitialize the converter.  */
772       _nl_free_domain_conv (domain);
773       _nl_init_domain_conv (domain_file, domain, domainbinding);
774     }
775
776   if (
777 # ifdef _LIBC
778       domain->conv != (__gconv_t) -1
779 # else
780 #  if HAVE_ICONV
781       domain->conv != (iconv_t) -1
782 #  endif
783 # endif
784       )
785     {
786       /* We are supposed to do a conversion.  First allocate an
787          appropriate table with the same structure as the table
788          of translations in the file, where we can put the pointers
789          to the converted strings in.
790          There is a slight complication with plural entries.  They
791          are represented by consecutive NUL terminated strings.  We
792          handle this case by converting RESULTLEN bytes, including
793          NULs.  */
794
795       if (domain->conv_tab == NULL
796           && ((domain->conv_tab = (char **) calloc (domain->nstrings,
797                                                     sizeof (char *)))
798               == NULL))
799         /* Mark that we didn't succeed allocating a table.  */
800         domain->conv_tab = (char **) -1;
801
802       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
803         /* Nothing we can do, no more memory.  */
804         goto converted;
805
806       if (domain->conv_tab[act] == NULL)
807         {
808           /* We haven't used this string so far, so it is not
809              translated yet.  Do this now.  */
810           /* We use a bit more efficient memory handling.
811              We allocate always larger blocks which get used over
812              time.  This is faster than many small allocations.   */
813           __libc_lock_define_initialized (static, lock)
814 # define INITIAL_BLOCK_SIZE     4080
815           static unsigned char *freemem;
816           static size_t freemem_size;
817
818           const unsigned char *inbuf;
819           unsigned char *outbuf;
820           int malloc_count;
821 # ifndef _LIBC
822           transmem_block_t *transmem_list = NULL;
823 # endif
824
825           __libc_lock_lock (lock);
826
827           inbuf = (const unsigned char *) result;
828           outbuf = freemem + sizeof (size_t);
829
830           malloc_count = 0;
831           while (1)
832             {
833               transmem_block_t *newmem;
834 # ifdef _LIBC
835               size_t non_reversible;
836               int res;
837
838               if (freemem_size < sizeof (size_t))
839                 goto resize_freemem;
840
841               res = __gconv (domain->conv,
842                              &inbuf, inbuf + resultlen,
843                              &outbuf,
844                              outbuf + freemem_size - sizeof (size_t),
845                              &non_reversible);
846
847               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
848                 break;
849
850               if (res != __GCONV_FULL_OUTPUT)
851                 {
852                   __libc_lock_unlock (lock);
853                   goto converted;
854                 }
855
856               inbuf = result;
857 # else
858 #  if HAVE_ICONV
859               const char *inptr = (const char *) inbuf;
860               size_t inleft = resultlen;
861               char *outptr = (char *) outbuf;
862               size_t outleft;
863
864               if (freemem_size < sizeof (size_t))
865                 goto resize_freemem;
866
867               outleft = freemem_size - sizeof (size_t);
868               if (iconv (domain->conv,
869                          (ICONV_CONST char **) &inptr, &inleft,
870                          &outptr, &outleft)
871                   != (size_t) (-1))
872                 {
873                   outbuf = (unsigned char *) outptr;
874                   break;
875                 }
876               if (errno != E2BIG)
877                 {
878                   __libc_lock_unlock (lock);
879                   goto converted;
880                 }
881 #  endif
882 # endif
883
884             resize_freemem:
885               /* We must allocate a new buffer or resize the old one.  */
886               if (malloc_count > 0)
887                 {
888                   ++malloc_count;
889                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
890                   newmem = (transmem_block_t *) realloc (transmem_list,
891                                                          freemem_size);
892 # ifdef _LIBC
893                   if (newmem != NULL)
894                     transmem_list = transmem_list->next;
895                   else
896                     {
897                       struct transmem_list *old = transmem_list;
898
899                       transmem_list = transmem_list->next;
900                       free (old);
901                     }
902 # endif
903                 }
904               else
905                 {
906                   malloc_count = 1;
907                   freemem_size = INITIAL_BLOCK_SIZE;
908                   newmem = (transmem_block_t *) malloc (freemem_size);
909                 }
910               if (__builtin_expect (newmem == NULL, 0))
911                 {
912                   freemem = NULL;
913                   freemem_size = 0;
914                   __libc_lock_unlock (lock);
915                   goto converted;
916                 }
917
918 # ifdef _LIBC
919               /* Add the block to the list of blocks we have to free
920                  at some point.  */
921               newmem->next = transmem_list;
922               transmem_list = newmem;
923
924               freemem = newmem->data;
925               freemem_size -= offsetof (struct transmem_list, data);
926 # else
927               transmem_list = newmem;
928               freemem = newmem;
929 # endif
930
931               outbuf = freemem + sizeof (size_t);
932             }
933
934           /* We have now in our buffer a converted string.  Put this
935              into the table of conversions.  */
936           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
937           domain->conv_tab[act] = (char *) freemem;
938           /* Shrink freemem, but keep it aligned.  */
939           freemem_size -= outbuf - freemem;
940           freemem = outbuf;
941           freemem += freemem_size & (alignof (size_t) - 1);
942           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
943
944           __libc_lock_unlock (lock);
945         }
946
947       /* Now domain->conv_tab[act] contains the translation of all
948          the plural variants.  */
949       result = domain->conv_tab[act] + sizeof (size_t);
950       resultlen = *(size_t *) domain->conv_tab[act];
951     }
952
953  converted:
954   /* The result string is converted.  */
955
956 #endif /* _LIBC || HAVE_ICONV */
957
958   *lengthp = resultlen;
959   return result;
960 }
961
962
963 /* Look up a plural variant.  */
964 static char *
965 internal_function
966 plural_lookup (domain, n, translation, translation_len)
967      struct loaded_l10nfile *domain;
968      unsigned long int n;
969      const char *translation;
970      size_t translation_len;
971 {
972   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
973   unsigned long int index;
974   const char *p;
975
976   index = plural_eval (domaindata->plural, n);
977   if (index >= domaindata->nplurals)
978     /* This should never happen.  It means the plural expression and the
979        given maximum value do not match.  */
980     index = 0;
981
982   /* Skip INDEX strings at TRANSLATION.  */
983   p = translation;
984   while (index-- > 0)
985     {
986 #ifdef _LIBC
987       p = __rawmemchr (p, '\0');
988 #else
989       p = strchr (p, '\0');
990 #endif
991       /* And skip over the NUL byte.  */
992       p++;
993
994       if (p >= translation + translation_len)
995         /* This should never happen.  It means the plural expression
996            evaluated to a value larger than the number of variants
997            available for MSGID1.  */
998         return (char *) translation;
999     }
1000   return (char *) p;
1001 }
1002
1003
1004 /* Return string representation of locale CATEGORY.  */
1005 static const char *
1006 internal_function
1007 category_to_name (category)
1008      int category;
1009 {
1010   const char *retval;
1011
1012   switch (category)
1013   {
1014 #ifdef LC_COLLATE
1015   case LC_COLLATE:
1016     retval = "LC_COLLATE";
1017     break;
1018 #endif
1019 #ifdef LC_CTYPE
1020   case LC_CTYPE:
1021     retval = "LC_CTYPE";
1022     break;
1023 #endif
1024 #ifdef LC_MONETARY
1025   case LC_MONETARY:
1026     retval = "LC_MONETARY";
1027     break;
1028 #endif
1029 #ifdef LC_NUMERIC
1030   case LC_NUMERIC:
1031     retval = "LC_NUMERIC";
1032     break;
1033 #endif
1034 #ifdef LC_TIME
1035   case LC_TIME:
1036     retval = "LC_TIME";
1037     break;
1038 #endif
1039 #ifdef LC_MESSAGES
1040   case LC_MESSAGES:
1041     retval = "LC_MESSAGES";
1042     break;
1043 #endif
1044 #ifdef LC_RESPONSE
1045   case LC_RESPONSE:
1046     retval = "LC_RESPONSE";
1047     break;
1048 #endif
1049 #ifdef LC_ALL
1050   case LC_ALL:
1051     /* This might not make sense but is perhaps better than any other
1052        value.  */
1053     retval = "LC_ALL";
1054     break;
1055 #endif
1056   default:
1057     /* If you have a better idea for a default value let me know.  */
1058     retval = "LC_XXX";
1059   }
1060
1061   return retval;
1062 }
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 = setlocale (category, NULL);
1086 #else
1087   retval = _nl_locale_name (category, categoryname);
1088 #endif
1089
1090   /* Ignore LANGUAGE if the locale is set to "C" because
1091      1. "C" locale usually uses the ASCII encoding, and most international
1092         messages use non-ASCII characters. These characters get displayed
1093         as question marks (if using glibc's iconv()) or as invalid 8-bit
1094         characters (because other iconv()s refuse to convert most non-ASCII
1095         characters to ASCII). In any case, the output is ugly.
1096      2. The precise output of some programs in the "C" locale is specified
1097         by POSIX and should not depend on environment variables like
1098         "LANGUAGE".  We allow such programs to use gettext().  */
1099   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1100 }
1101
1102 /* @@ begin of epilog @@ */
1103
1104 /* We don't want libintl.a to depend on any other library.  So we
1105    avoid the non-standard function stpcpy.  In GNU C Library this
1106    function is available, though.  Also allow the symbol HAVE_STPCPY
1107    to be defined.  */
1108 #if !_LIBC && !HAVE_STPCPY
1109 static char *
1110 stpcpy (dest, src)
1111      char *dest;
1112      const char *src;
1113 {
1114   while ((*dest++ = *src++) != '\0')
1115     /* Do nothing. */ ;
1116   return dest - 1;
1117 }
1118 #endif
1119
1120 #if !_LIBC && !HAVE_MEMPCPY
1121 static void *
1122 mempcpy (dest, src, n)
1123      void *dest;
1124      const void *src;
1125      size_t n;
1126 {
1127   return (void *) ((char *) memcpy (dest, src, n) + n);
1128 }
1129 #endif
1130
1131
1132 #ifdef _LIBC
1133 /* If we want to free all resources we have to do some work at
1134    program's end.  */
1135 static void __attribute__ ((unused))
1136 free_mem (void)
1137 {
1138   void *old;
1139
1140   while (_nl_domain_bindings != NULL)
1141     {
1142       struct binding *oldp = _nl_domain_bindings;
1143       _nl_domain_bindings = _nl_domain_bindings->next;
1144       if (oldp->dirname != _nl_default_dirname)
1145         /* Yes, this is a pointer comparison.  */
1146         free (oldp->dirname);
1147       free (oldp->codeset);
1148       free (oldp);
1149     }
1150
1151   if (_nl_current_default_domain != _nl_default_default_domain)
1152     /* Yes, again a pointer comparison.  */
1153     free ((char *) _nl_current_default_domain);
1154
1155   /* Remove the search tree with the known translations.  */
1156   __tdestroy (root, free);
1157   root = NULL;
1158
1159   while (transmem_list != NULL)
1160     {
1161       old = transmem_list;
1162       transmem_list = transmem_list->next;
1163       free (old);
1164     }
1165 }
1166
1167 text_set_element (__libc_subfreeres, free_mem);
1168 #endif