make toolbar refresh smoother
[claws.git] / intl / dcigettext.c
1 /* Implementation of the internal dcigettext function.
2    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
19    This must come before <config.h> because <config.h> may include
20    <features.h>, and once <features.h> has been included, it's too late.  */
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE    1
23 #endif
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include <sys/types.h>
30
31 #ifdef __GNUC__
32 # define alloca __builtin_alloca
33 # define HAVE_ALLOCA 1
34 #else
35 # if defined HAVE_ALLOCA_H || defined _LIBC
36 #  include <alloca.h>
37 # else
38 #  ifdef _AIX
39  #pragma alloca
40 #  else
41 #   ifndef alloca
42 char *alloca ();
43 #   endif
44 #  endif
45 # endif
46 #endif
47
48 #include <errno.h>
49 #ifndef errno
50 extern int errno;
51 #endif
52 #ifndef __set_errno
53 # define __set_errno(val) errno = (val)
54 #endif
55
56 #include <stddef.h>
57 #include <stdlib.h>
58
59 #include <string.h>
60 #if !HAVE_STRCHR && !defined _LIBC
61 # ifndef strchr
62 #  define strchr index
63 # endif
64 #endif
65
66 #if defined HAVE_UNISTD_H || defined _LIBC
67 # include <unistd.h>
68 #endif
69
70 #include <locale.h>
71
72 #if defined HAVE_SYS_PARAM_H || defined _LIBC
73 # include <sys/param.h>
74 #endif
75
76 #include "gettextP.h"
77 #ifdef _LIBC
78 # include <libintl.h>
79 #else
80 # include "libgnuintl.h"
81 #endif
82 #include "hash-string.h"
83
84 /* Thread safetyness.  */
85 #ifdef _LIBC
86 # include <bits/libc-lock.h>
87 #else
88 /* Provide dummy implementation if this is outside glibc.  */
89 # define __libc_lock_define_initialized(CLASS, NAME)
90 # define __libc_lock_lock(NAME)
91 # define __libc_lock_unlock(NAME)
92 # define __libc_rwlock_define_initialized(CLASS, NAME)
93 # define __libc_rwlock_rdlock(NAME)
94 # define __libc_rwlock_unlock(NAME)
95 #endif
96
97 /* Alignment of types.  */
98 #if defined __GNUC__ && __GNUC__ >= 2
99 # define alignof(TYPE) __alignof__ (TYPE)
100 #else
101 # define alignof(TYPE) \
102     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
103 #endif
104
105 /* The internal variables in the standalone libintl.a must have different
106    names than the internal variables in GNU libc, otherwise programs
107    using libintl.a cannot be linked statically.  */
108 #if !defined _LIBC
109 # define _nl_default_default_domain _nl_default_default_domain__
110 # define _nl_current_default_domain _nl_current_default_domain__
111 # define _nl_default_dirname _nl_default_dirname__
112 # define _nl_domain_bindings _nl_domain_bindings__
113 #endif
114
115 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
116 #ifndef offsetof
117 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
118 #endif
119
120 /* @@ end of prolog @@ */
121
122 #ifdef _LIBC
123 /* Rename the non ANSI C functions.  This is required by the standard
124    because some ANSI C functions will require linking with this object
125    file and the name space must not be polluted.  */
126 # define getcwd __getcwd
127 # ifndef stpcpy
128 #  define stpcpy __stpcpy
129 # endif
130 # define tfind __tfind
131 #else
132 # if !defined HAVE_GETCWD
133 char *getwd ();
134 #  define getcwd(buf, max) getwd (buf)
135 # else
136 char *getcwd ();
137 # endif
138 # ifndef HAVE_STPCPY
139 static char *stpcpy PARAMS ((char *dest, const char *src));
140 # endif
141 # ifndef HAVE_MEMPCPY
142 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
143 # endif
144 #endif
145
146 /* Amount to increase buffer size by in each try.  */
147 #define PATH_INCR 32
148
149 /* The following is from pathmax.h.  */
150 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
151    PATH_MAX but might cause redefinition warnings when sys/param.h is
152    later included (as on MORE/BSD 4.3).  */
153 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
154 # include <limits.h>
155 #endif
156
157 #ifndef _POSIX_PATH_MAX
158 # define _POSIX_PATH_MAX 255
159 #endif
160
161 #if !defined PATH_MAX && defined _PC_PATH_MAX
162 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
163 #endif
164
165 /* Don't include sys/param.h if it already has been.  */
166 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
167 # include <sys/param.h>
168 #endif
169
170 #if !defined PATH_MAX && defined MAXPATHLEN
171 # define PATH_MAX MAXPATHLEN
172 #endif
173
174 #ifndef PATH_MAX
175 # define PATH_MAX _POSIX_PATH_MAX
176 #endif
177
178 /* Pathname support.
179    ISSLASH(C)           tests whether C is a directory separator character.
180    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
181                         it may be concatenated to a directory pathname.
182    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
183  */
184 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
185   /* Win32, OS/2, DOS */
186 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
187 # define HAS_DEVICE(P) \
188     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
189      && (P)[1] == ':')
190 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
191 # define IS_PATH_WITH_DIR(P) \
192     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
193 #else
194   /* Unix */
195 # define ISSLASH(C) ((C) == '/')
196 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
197 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
198 #endif
199
200 /* XPG3 defines the result of `setlocale (category, NULL)' as:
201    ``Directs `setlocale()' to query `category' and return the current
202      setting of `local'.''
203    However it does not specify the exact format.  Neither do SUSV2 and
204    ISO C 99.  So we can use this feature only on selected systems (e.g.
205    those using GNU C Library).  */
206 #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
207 # define HAVE_LOCALE_NULL
208 #endif
209
210 /* This is the type used for the search tree where known translations
211    are stored.  */
212 struct known_translation_t
213 {
214   /* Domain in which to search.  */
215   char *domainname;
216
217   /* The category.  */
218   int category;
219
220   /* State of the catalog counter at the point the string was found.  */
221   int counter;
222
223   /* Catalog where the string was found.  */
224   struct loaded_l10nfile *domain;
225
226   /* And finally the translation.  */
227   const char *translation;
228   size_t translation_length;
229
230   /* Pointer to the string in question.  */
231   char msgid[ZERO];
232 };
233
234 /* Root of the search tree with known translations.  We can use this
235    only if the system provides the `tsearch' function family.  */
236 #if defined HAVE_TSEARCH || defined _LIBC
237 # include <search.h>
238
239 static void *root;
240
241 # ifdef _LIBC
242 #  define tsearch __tsearch
243 # endif
244
245 /* Function to compare two entries in the table of known translations.  */
246 static int transcmp PARAMS ((const void *p1, const void *p2));
247 static int
248 transcmp (p1, p2)
249      const void *p1;
250      const void *p2;
251 {
252   const struct known_translation_t *s1;
253   const struct known_translation_t *s2;
254   int result;
255
256   s1 = (const struct known_translation_t *) p1;
257   s2 = (const struct known_translation_t *) p2;
258
259   result = strcmp (s1->msgid, s2->msgid);
260   if (result == 0)
261     {
262       result = strcmp (s1->domainname, s2->domainname);
263       if (result == 0)
264         /* We compare the category last (though this is the cheapest
265            operation) since it is hopefully always the same (namely
266            LC_MESSAGES).  */
267         result = s1->category - s2->category;
268     }
269
270   return result;
271 }
272 #endif
273
274 /* Name of the default domain used for gettext(3) prior any call to
275    textdomain(3).  The default value for this is "messages".  */
276 const char _nl_default_default_domain[] = "messages";
277
278 /* Value used as the default domain for gettext(3).  */
279 const char *_nl_current_default_domain = _nl_default_default_domain;
280
281 /* Contains the default location of the message catalogs.  */
282 const char _nl_default_dirname[] = LOCALEDIR;
283
284 /* List with bindings of specific domains created by bindtextdomain()
285    calls.  */
286 struct binding *_nl_domain_bindings;
287
288 /* Prototypes for local functions.  */
289 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
290                                     unsigned long int n,
291                                     const char *translation,
292                                     size_t translation_len))
293      internal_function;
294 static unsigned long int plural_eval PARAMS ((struct expression *pexp,
295                                               unsigned long int n))
296      internal_function;
297 static const char *category_to_name PARAMS ((int category)) internal_function;
298 static const char *guess_category_value PARAMS ((int category,
299                                                  const char *categoryname))
300      internal_function;
301
302
303 /* For those loosing systems which don't have `alloca' we have to add
304    some additional code emulating it.  */
305 #ifdef HAVE_ALLOCA
306 /* Nothing has to be done.  */
307 # define ADD_BLOCK(list, address) /* nothing */
308 # define FREE_BLOCKS(list) /* nothing */
309 #else
310 struct block_list
311 {
312   void *address;
313   struct block_list *next;
314 };
315 # define ADD_BLOCK(list, addr)                                                \
316   do {                                                                        \
317     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
318     /* If we cannot get a free block we cannot add the new element to         \
319        the list.  */                                                          \
320     if (newp != NULL) {                                                       \
321       newp->address = (addr);                                                 \
322       newp->next = (list);                                                    \
323       (list) = newp;                                                          \
324     }                                                                         \
325   } while (0)
326 # define FREE_BLOCKS(list)                                                    \
327   do {                                                                        \
328     while (list != NULL) {                                                    \
329       struct block_list *old = list;                                          \
330       list = list->next;                                                      \
331       free (old);                                                             \
332     }                                                                         \
333   } while (0)
334 # undef alloca
335 # define alloca(size) (malloc (size))
336 #endif  /* have alloca */
337
338
339 #ifdef _LIBC
340 /* List of blocks allocated for translations.  */
341 typedef struct transmem_list
342 {
343   struct transmem_list *next;
344   char data[ZERO];
345 } transmem_block_t;
346 static struct transmem_list *transmem_list;
347 #else
348 typedef unsigned char transmem_block_t;
349 #endif
350
351
352 /* Names for the libintl functions are a problem.  They must not clash
353    with existing names and they should follow ANSI C.  But this source
354    code is also used in GNU C Library where the names have a __
355    prefix.  So we have to make a difference here.  */
356 #ifdef _LIBC
357 # define DCIGETTEXT __dcigettext
358 #else
359 # define DCIGETTEXT dcigettext__
360 #endif
361
362 /* Lock variable to protect the global data in the gettext implementation.  */
363 #ifdef _LIBC
364 __libc_rwlock_define_initialized (, _nl_state_lock)
365 #endif
366
367 /* Checking whether the binaries runs SUID must be done and glibc provides
368    easier methods therefore we make a difference here.  */
369 #ifdef _LIBC
370 # define ENABLE_SECURE __libc_enable_secure
371 # define DETERMINE_SECURE
372 #else
373 # ifndef HAVE_GETUID
374 #  define getuid() 0
375 # endif
376 # ifndef HAVE_GETGID
377 #  define getgid() 0
378 # endif
379 # ifndef HAVE_GETEUID
380 #  define geteuid() getuid()
381 # endif
382 # ifndef HAVE_GETEGID
383 #  define getegid() getgid()
384 # endif
385 static int enable_secure;
386 # define ENABLE_SECURE (enable_secure == 1)
387 # define DETERMINE_SECURE \
388   if (enable_secure == 0)                                                     \
389     {                                                                         \
390       if (getuid () != geteuid () || getgid () != getegid ())                 \
391         enable_secure = 1;                                                    \
392       else                                                                    \
393         enable_secure = -1;                                                   \
394     }
395 #endif
396
397 /* Look up MSGID in the DOMAINNAME message catalog for the current
398    CATEGORY locale and, if PLURAL is nonzero, search over string
399    depending on the plural form determined by N.  */
400 char *
401 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
402      const char *domainname;
403      const char *msgid1;
404      const char *msgid2;
405      int plural;
406      unsigned long int n;
407      int category;
408 {
409 #ifndef HAVE_ALLOCA
410   struct block_list *block_list = NULL;
411 #endif
412   struct loaded_l10nfile *domain;
413   struct binding *binding;
414   const char *categoryname;
415   const char *categoryvalue;
416   char *dirname, *xdomainname;
417   char *single_locale;
418   char *retval;
419   size_t retlen;
420   int saved_errno;
421 #if defined HAVE_TSEARCH || defined _LIBC
422   struct known_translation_t *search;
423   struct known_translation_t **foundp = NULL;
424   size_t msgid_len;
425 #endif
426   size_t domainname_len;
427
428   /* If no real MSGID is given return NULL.  */
429   if (msgid1 == NULL)
430     return NULL;
431
432   __libc_rwlock_rdlock (_nl_state_lock);
433
434   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
435      CATEGORY is not LC_MESSAGES this might not make much sense but the
436      definition left this undefined.  */
437   if (domainname == NULL)
438     domainname = _nl_current_default_domain;
439
440 #if defined HAVE_TSEARCH || defined _LIBC
441   msgid_len = strlen (msgid1) + 1;
442
443   /* Try to find the translation among those which we found at
444      some time.  */
445   search = (struct known_translation_t *)
446            alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
447   memcpy (search->msgid, msgid1, msgid_len);
448   search->domainname = (char *) domainname;
449   search->category = category;
450
451   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
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 (IS_ABSOLUTE_PATH (binding->dirname))
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 && IS_PATH_WITH_DIR (single_locale))
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               __set_errno (saved_errno);
625 #if defined HAVE_TSEARCH || defined _LIBC
626               if (foundp == NULL)
627                 {
628                   /* Create a new entry and add it to the search tree.  */
629                   struct known_translation_t *newp;
630
631                   newp = (struct known_translation_t *)
632                     malloc (offsetof (struct known_translation_t, msgid)
633                             + msgid_len + domainname_len + 1);
634                   if (newp != NULL)
635                     {
636                       newp->domainname =
637                         mempcpy (newp->msgid, msgid1, msgid_len);
638                       memcpy (newp->domainname, domainname, domainname_len + 1);
639                       newp->category = category;
640                       newp->counter = _nl_msg_cat_cntr;
641                       newp->domain = domain;
642                       newp->translation = retval;
643                       newp->translation_length = retlen;
644
645                       /* Insert the entry in the search tree.  */
646                       foundp = (struct known_translation_t **)
647                         tsearch (newp, &root, transcmp);
648                       if (foundp == NULL
649                           || __builtin_expect (*foundp != newp, 0))
650                         /* The insert failed.  */
651                         free (newp);
652                     }
653                 }
654               else
655                 {
656                   /* We can update the existing entry.  */
657                   (*foundp)->counter = _nl_msg_cat_cntr;
658                   (*foundp)->domain = domain;
659                   (*foundp)->translation = retval;
660                   (*foundp)->translation_length = retlen;
661                 }
662 #endif
663               /* Now deal with plural.  */
664               if (plural)
665                 retval = plural_lookup (domain, n, retval, retlen);
666
667               __libc_rwlock_unlock (_nl_state_lock);
668               return retval;
669             }
670         }
671     }
672   /* NOTREACHED */
673 }
674
675
676 char *
677 internal_function
678 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
679      struct loaded_l10nfile *domain_file;
680      struct binding *domainbinding;
681      const char *msgid;
682      size_t *lengthp;
683 {
684   struct loaded_domain *domain;
685   size_t act;
686   char *result;
687   size_t resultlen;
688
689   if (domain_file->decided == 0)
690     _nl_load_domain (domain_file, domainbinding);
691
692   if (domain_file->data == NULL)
693     return NULL;
694
695   domain = (struct loaded_domain *) domain_file->data;
696
697   /* Locate the MSGID and its translation.  */
698   if (domain->hash_size > 2 && domain->hash_tab != NULL)
699     {
700       /* Use the hashing table.  */
701       nls_uint32 len = strlen (msgid);
702       nls_uint32 hash_val = hash_string (msgid);
703       nls_uint32 idx = hash_val % domain->hash_size;
704       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
705
706       while (1)
707         {
708           nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
709
710           if (nstr == 0)
711             /* Hash table entry is empty.  */
712             return NULL;
713
714           /* Compare msgid with the original string at index nstr-1.
715              We compare the lengths with >=, not ==, because plural entries
716              are represented by strings with an embedded NUL.  */
717           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
718               && (strcmp (msgid,
719                           domain->data + W (domain->must_swap,
720                                             domain->orig_tab[nstr - 1].offset))
721                   == 0))
722             {
723               act = nstr - 1;
724               goto found;
725             }
726
727           if (idx >= domain->hash_size - incr)
728             idx -= domain->hash_size - incr;
729           else
730             idx += incr;
731         }
732       /* NOTREACHED */
733     }
734   else
735     {
736       /* Try the default method:  binary search in the sorted array of
737          messages.  */
738       size_t top, bottom;
739
740       bottom = 0;
741       top = domain->nstrings;
742       while (bottom < top)
743         {
744           int cmp_val;
745
746           act = (bottom + top) / 2;
747           cmp_val = strcmp (msgid, (domain->data
748                                     + W (domain->must_swap,
749                                          domain->orig_tab[act].offset)));
750           if (cmp_val < 0)
751             top = act;
752           else if (cmp_val > 0)
753             bottom = act + 1;
754           else
755             goto found;
756         }
757       /* No translation was found.  */
758       return NULL;
759     }
760
761  found:
762   /* The translation was found at index ACT.  If we have to convert the
763      string to use a different character set, this is the time.  */
764   result = ((char *) domain->data
765             + W (domain->must_swap, domain->trans_tab[act].offset));
766   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
767
768 #if defined _LIBC || HAVE_ICONV
769   if (domain->codeset_cntr
770       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
771     {
772       /* The domain's codeset has changed through bind_textdomain_codeset()
773          since the message catalog was initialized or last accessed.  We
774          have to reinitialize the converter.  */
775       _nl_free_domain_conv (domain);
776       _nl_init_domain_conv (domain_file, domain, domainbinding);
777     }
778
779   if (
780 # ifdef _LIBC
781       domain->conv != (__gconv_t) -1
782 # else
783 #  if HAVE_ICONV
784       domain->conv != (iconv_t) -1
785 #  endif
786 # endif
787       )
788     {
789       /* We are supposed to do a conversion.  First allocate an
790          appropriate table with the same structure as the table
791          of translations in the file, where we can put the pointers
792          to the converted strings in.
793          There is a slight complication with plural entries.  They
794          are represented by consecutive NUL terminated strings.  We
795          handle this case by converting RESULTLEN bytes, including
796          NULs.  */
797
798       if (domain->conv_tab == NULL
799           && ((domain->conv_tab = (char **) calloc (domain->nstrings,
800                                                     sizeof (char *)))
801               == NULL))
802         /* Mark that we didn't succeed allocating a table.  */
803         domain->conv_tab = (char **) -1;
804
805       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
806         /* Nothing we can do, no more memory.  */
807         goto converted;
808
809       if (domain->conv_tab[act] == NULL)
810         {
811           /* We haven't used this string so far, so it is not
812              translated yet.  Do this now.  */
813           /* We use a bit more efficient memory handling.
814              We allocate always larger blocks which get used over
815              time.  This is faster than many small allocations.   */
816           __libc_lock_define_initialized (static, lock)
817 # define INITIAL_BLOCK_SIZE     4080
818           static unsigned char *freemem;
819           static size_t freemem_size;
820
821           const unsigned char *inbuf;
822           unsigned char *outbuf;
823           int malloc_count;
824 # ifndef _LIBC
825           transmem_block_t *transmem_list = NULL;
826 # endif
827
828           __libc_lock_lock (lock);
829
830           inbuf = (const unsigned char *) result;
831           outbuf = freemem + sizeof (size_t);
832
833           malloc_count = 0;
834           while (1)
835             {
836               transmem_block_t *newmem;
837 # ifdef _LIBC
838               size_t non_reversible;
839               int res;
840
841               if (freemem_size < sizeof (size_t))
842                 goto resize_freemem;
843
844               res = __gconv (domain->conv,
845                              &inbuf, inbuf + resultlen,
846                              &outbuf,
847                              outbuf + freemem_size - sizeof (size_t),
848                              &non_reversible);
849
850               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
851                 break;
852
853               if (res != __GCONV_FULL_OUTPUT)
854                 {
855                   __libc_lock_unlock (lock);
856                   goto converted;
857                 }
858
859               inbuf = result;
860 # else
861 #  if HAVE_ICONV
862               const char *inptr = (const char *) inbuf;
863               size_t inleft = resultlen;
864               char *outptr = (char *) outbuf;
865               size_t outleft;
866
867               if (freemem_size < sizeof (size_t))
868                 goto resize_freemem;
869
870               outleft = freemem_size - sizeof (size_t);
871               if (iconv (domain->conv,
872                          (ICONV_CONST char **) &inptr, &inleft,
873                          &outptr, &outleft)
874                   != (size_t) (-1))
875                 {
876                   outbuf = (unsigned char *) outptr;
877                   break;
878                 }
879               if (errno != E2BIG)
880                 {
881                   __libc_lock_unlock (lock);
882                   goto converted;
883                 }
884 #  endif
885 # endif
886
887             resize_freemem:
888               /* We must allocate a new buffer or resize the old one.  */
889               if (malloc_count > 0)
890                 {
891                   ++malloc_count;
892                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
893                   newmem = (transmem_block_t *) realloc (transmem_list,
894                                                          freemem_size);
895 # ifdef _LIBC
896                   if (newmem != NULL)
897                     transmem_list = transmem_list->next;
898                   else
899                     {
900                       struct transmem_list *old = transmem_list;
901
902                       transmem_list = transmem_list->next;
903                       free (old);
904                     }
905 # endif
906                 }
907               else
908                 {
909                   malloc_count = 1;
910                   freemem_size = INITIAL_BLOCK_SIZE;
911                   newmem = (transmem_block_t *) malloc (freemem_size);
912                 }
913               if (__builtin_expect (newmem == NULL, 0))
914                 {
915                   freemem = NULL;
916                   freemem_size = 0;
917                   __libc_lock_unlock (lock);
918                   goto converted;
919                 }
920
921 # ifdef _LIBC
922               /* Add the block to the list of blocks we have to free
923                  at some point.  */
924               newmem->next = transmem_list;
925               transmem_list = newmem;
926
927               freemem = newmem->data;
928               freemem_size -= offsetof (struct transmem_list, data);
929 # else
930               transmem_list = newmem;
931               freemem = newmem;
932 # endif
933
934               outbuf = freemem + sizeof (size_t);
935             }
936
937           /* We have now in our buffer a converted string.  Put this
938              into the table of conversions.  */
939           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
940           domain->conv_tab[act] = (char *) freemem;
941           /* Shrink freemem, but keep it aligned.  */
942           freemem_size -= outbuf - freemem;
943           freemem = outbuf;
944           freemem += freemem_size & (alignof (size_t) - 1);
945           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
946
947           __libc_lock_unlock (lock);
948         }
949
950       /* Now domain->conv_tab[act] contains the translation of all
951          the plural variants.  */
952       result = domain->conv_tab[act] + sizeof (size_t);
953       resultlen = *(size_t *) domain->conv_tab[act];
954     }
955
956  converted:
957   /* The result string is converted.  */
958
959 #endif /* _LIBC || HAVE_ICONV */
960
961   *lengthp = resultlen;
962   return result;
963 }
964
965
966 /* Look up a plural variant.  */
967 static char *
968 internal_function
969 plural_lookup (domain, n, translation, translation_len)
970      struct loaded_l10nfile *domain;
971      unsigned long int n;
972      const char *translation;
973      size_t translation_len;
974 {
975   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
976   unsigned long int index;
977   const char *p;
978
979   index = plural_eval (domaindata->plural, n);
980   if (index >= domaindata->nplurals)
981     /* This should never happen.  It means the plural expression and the
982        given maximum value do not match.  */
983     index = 0;
984
985   /* Skip INDEX strings at TRANSLATION.  */
986   p = translation;
987   while (index-- > 0)
988     {
989 #ifdef _LIBC
990       p = __rawmemchr (p, '\0');
991 #else
992       p = strchr (p, '\0');
993 #endif
994       /* And skip over the NUL byte.  */
995       p++;
996
997       if (p >= translation + translation_len)
998         /* This should never happen.  It means the plural expression
999            evaluated to a value larger than the number of variants
1000            available for MSGID1.  */
1001         return (char *) translation;
1002     }
1003   return (char *) p;
1004 }
1005
1006
1007 /* Function to evaluate the plural expression and return an index value.  */
1008 static unsigned long int
1009 internal_function
1010 plural_eval (pexp, n)
1011      struct expression *pexp;
1012      unsigned long int n;
1013 {
1014   switch (pexp->nargs)
1015     {
1016     case 0:
1017       switch (pexp->operation)
1018         {
1019         case var:
1020           return n;
1021         case num:
1022           return pexp->val.num;
1023         default:
1024           break;
1025         }
1026       /* NOTREACHED */
1027       break;
1028     case 1:
1029       {
1030         /* pexp->operation must be lnot.  */
1031         unsigned long int arg = plural_eval (pexp->val.args[0], n);
1032         return ! arg;
1033       }
1034     case 2:
1035       {
1036         unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
1037         if (pexp->operation == lor)
1038           return leftarg || plural_eval (pexp->val.args[1], n);
1039         else if (pexp->operation == land)
1040           return leftarg && plural_eval (pexp->val.args[1], n);
1041         else
1042           {
1043             unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
1044
1045             switch (pexp->operation)
1046               {
1047               case mult:
1048                 return leftarg * rightarg;
1049               case divide:
1050                 return leftarg / rightarg;
1051               case module:
1052                 return leftarg % rightarg;
1053               case plus:
1054                 return leftarg + rightarg;
1055               case minus:
1056                 return leftarg - rightarg;
1057               case less_than:
1058                 return leftarg < rightarg;
1059               case greater_than:
1060                 return leftarg > rightarg;
1061               case less_or_equal:
1062                 return leftarg <= rightarg;
1063               case greater_or_equal:
1064                 return leftarg >= rightarg;
1065               case equal:
1066                 return leftarg == rightarg;
1067               case not_equal:
1068                 return leftarg != rightarg;
1069               default:
1070                 break;
1071               }
1072           }
1073         /* NOTREACHED */
1074         break;
1075       }
1076     case 3:
1077       {
1078         /* pexp->operation must be qmop.  */
1079         unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
1080         return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
1081       }
1082     }
1083   /* NOTREACHED */
1084   return 0;
1085 }
1086
1087
1088 /* Return string representation of locale CATEGORY.  */
1089 static const char *
1090 internal_function
1091 category_to_name (category)
1092      int category;
1093 {
1094   const char *retval;
1095
1096   switch (category)
1097   {
1098 #ifdef LC_COLLATE
1099   case LC_COLLATE:
1100     retval = "LC_COLLATE";
1101     break;
1102 #endif
1103 #ifdef LC_CTYPE
1104   case LC_CTYPE:
1105     retval = "LC_CTYPE";
1106     break;
1107 #endif
1108 #ifdef LC_MONETARY
1109   case LC_MONETARY:
1110     retval = "LC_MONETARY";
1111     break;
1112 #endif
1113 #ifdef LC_NUMERIC
1114   case LC_NUMERIC:
1115     retval = "LC_NUMERIC";
1116     break;
1117 #endif
1118 #ifdef LC_TIME
1119   case LC_TIME:
1120     retval = "LC_TIME";
1121     break;
1122 #endif
1123 #ifdef LC_MESSAGES
1124   case LC_MESSAGES:
1125     retval = "LC_MESSAGES";
1126     break;
1127 #endif
1128 #ifdef LC_RESPONSE
1129   case LC_RESPONSE:
1130     retval = "LC_RESPONSE";
1131     break;
1132 #endif
1133 #ifdef LC_ALL
1134   case LC_ALL:
1135     /* This might not make sense but is perhaps better than any other
1136        value.  */
1137     retval = "LC_ALL";
1138     break;
1139 #endif
1140   default:
1141     /* If you have a better idea for a default value let me know.  */
1142     retval = "LC_XXX";
1143   }
1144
1145   return retval;
1146 }
1147
1148 /* Guess value of current locale from value of the environment variables.  */
1149 static const char *
1150 internal_function
1151 guess_category_value (category, categoryname)
1152      int category;
1153      const char *categoryname;
1154 {
1155   const char *language;
1156   const char *retval;
1157
1158   /* The highest priority value is the `LANGUAGE' environment
1159      variable.  But we don't use the value if the currently selected
1160      locale is the C locale.  This is a GNU extension.  */
1161   language = getenv ("LANGUAGE");
1162   if (language != NULL && language[0] == '\0')
1163     language = NULL;
1164
1165   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1166      `LC_xxx', and `LANG'.  On some systems this can be done by the
1167      `setlocale' function itself.  */
1168 #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
1169   retval = setlocale (category, NULL);
1170 #else
1171   /* Setting of LC_ALL overwrites all other.  */
1172   retval = getenv ("LC_ALL");
1173   if (retval == NULL || retval[0] == '\0')
1174     {
1175       /* Next comes the name of the desired category.  */
1176       retval = getenv (categoryname);
1177       if (retval == NULL || retval[0] == '\0')
1178         {
1179           /* Last possibility is the LANG environment variable.  */
1180           retval = getenv ("LANG");
1181           if (retval == NULL || retval[0] == '\0')
1182             /* We use C as the default domain.  POSIX says this is
1183                implementation defined.  */
1184             return "C";
1185         }
1186     }
1187 #endif
1188
1189   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1190 }
1191
1192 /* @@ begin of epilog @@ */
1193
1194 /* We don't want libintl.a to depend on any other library.  So we
1195    avoid the non-standard function stpcpy.  In GNU C Library this
1196    function is available, though.  Also allow the symbol HAVE_STPCPY
1197    to be defined.  */
1198 #if !_LIBC && !HAVE_STPCPY
1199 static char *
1200 stpcpy (dest, src)
1201      char *dest;
1202      const char *src;
1203 {
1204   while ((*dest++ = *src++) != '\0')
1205     /* Do nothing. */ ;
1206   return dest - 1;
1207 }
1208 #endif
1209
1210 #if !_LIBC && !HAVE_MEMPCPY
1211 static void *
1212 mempcpy (dest, src, n)
1213      void *dest;
1214      const void *src;
1215      size_t n;
1216 {
1217   return (void *) ((char *) memcpy (dest, src, n) + n);
1218 }
1219 #endif
1220
1221
1222 #ifdef _LIBC
1223 /* If we want to free all resources we have to do some work at
1224    program's end.  */
1225 static void __attribute__ ((unused))
1226 free_mem (void)
1227 {
1228   void *old;
1229
1230   while (_nl_domain_bindings != NULL)
1231     {
1232       struct binding *oldp = _nl_domain_bindings;
1233       _nl_domain_bindings = _nl_domain_bindings->next;
1234       if (oldp->dirname != _nl_default_dirname)
1235         /* Yes, this is a pointer comparison.  */
1236         free (oldp->dirname);
1237       free (oldp->codeset);
1238       free (oldp);
1239     }
1240
1241   if (_nl_current_default_domain != _nl_default_default_domain)
1242     /* Yes, again a pointer comparison.  */
1243     free ((char *) _nl_current_default_domain);
1244
1245   /* Remove the search tree with the known translations.  */
1246   __tdestroy (root, free);
1247   root = NULL;
1248
1249   while (transmem_list != NULL)
1250     {
1251       old = transmem_list;
1252       transmem_list = transmem_list->next;
1253       free (old);
1254     }
1255 }
1256
1257 text_set_element (__libc_subfreeres, free_mem);
1258 #endif