sync with sylpheed 0.5.1cvs7
[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           __set_errno (saved_errno);
521           return (plural == 0
522                   ? (char *) msgid1
523                   /* Use the Germanic plural rule.  */
524                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
525         }
526
527       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
528     }
529
530   /* Now determine the symbolic name of CATEGORY and its value.  */
531   categoryname = category_to_name (category);
532   categoryvalue = guess_category_value (category, categoryname);
533
534   domainname_len = strlen (domainname);
535   xdomainname = (char *) alloca (strlen (categoryname)
536                                  + domainname_len + 5);
537   ADD_BLOCK (block_list, xdomainname);
538
539   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
540                   domainname, domainname_len),
541           ".mo");
542
543   /* Creating working area.  */
544   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
545   ADD_BLOCK (block_list, single_locale);
546
547
548   /* Search for the given string.  This is a loop because we perhaps
549      got an ordered list of languages to consider for the translation.  */
550   while (1)
551     {
552       /* Make CATEGORYVALUE point to the next element of the list.  */
553       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
554         ++categoryvalue;
555       if (categoryvalue[0] == '\0')
556         {
557           /* The whole contents of CATEGORYVALUE has been searched but
558              no valid entry has been found.  We solve this situation
559              by implicitly appending a "C" entry, i.e. no translation
560              will take place.  */
561           single_locale[0] = 'C';
562           single_locale[1] = '\0';
563         }
564       else
565         {
566           char *cp = single_locale;
567           while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
568             *cp++ = *categoryvalue++;
569           *cp = '\0';
570
571           /* When this is a SUID binary we must not allow accessing files
572              outside the dedicated directories.  */
573           if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
574             /* Ingore this entry.  */
575             continue;
576         }
577
578       /* If the current locale value is C (or POSIX) we don't load a
579          domain.  Return the MSGID.  */
580       if (strcmp (single_locale, "C") == 0
581           || strcmp (single_locale, "POSIX") == 0)
582         {
583           FREE_BLOCKS (block_list);
584           __libc_rwlock_unlock (_nl_state_lock);
585           __set_errno (saved_errno);
586           return (plural == 0
587                   ? (char *) msgid1
588                   /* Use the Germanic plural rule.  */
589                   : n == 1 ? (char *) msgid1 : (char *) msgid2);
590         }
591
592
593       /* Find structure describing the message catalog matching the
594          DOMAINNAME and CATEGORY.  */
595       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
596
597       if (domain != NULL)
598         {
599           retval = _nl_find_msg (domain, binding, msgid1, &retlen);
600
601           if (retval == NULL)
602             {
603               int cnt;
604
605               for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
606                 {
607                   retval = _nl_find_msg (domain->successor[cnt], binding,
608                                          msgid1, &retlen);
609
610                   if (retval != NULL)
611                     {
612                       domain = domain->successor[cnt];
613                       break;
614                     }
615                 }
616             }
617
618           if (retval != NULL)
619             {
620               /* Found the translation of MSGID1 in domain DOMAIN:
621                  starting at RETVAL, RETLEN bytes.  */
622               FREE_BLOCKS (block_list);
623               __set_errno (saved_errno);
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                       /* Insert the entry in the search tree.  */
645                       foundp = (struct known_translation_t **)
646                         tsearch (newp, &root, transcmp);
647                       if (foundp == NULL
648                           || __builtin_expect (*foundp != newp, 0))
649                         /* The insert failed.  */
650                         free (newp);
651                     }
652                 }
653               else
654                 {
655                   /* We can update the existing entry.  */
656                   (*foundp)->counter = _nl_msg_cat_cntr;
657                   (*foundp)->domain = domain;
658                   (*foundp)->translation = retval;
659                   (*foundp)->translation_length = retlen;
660                 }
661 #endif
662               /* Now deal with plural.  */
663               if (plural)
664                 retval = plural_lookup (domain, n, retval, retlen);
665
666               __libc_rwlock_unlock (_nl_state_lock);
667               return retval;
668             }
669         }
670     }
671   /* NOTREACHED */
672 }
673
674
675 char *
676 internal_function
677 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
678      struct loaded_l10nfile *domain_file;
679      struct binding *domainbinding;
680      const char *msgid;
681      size_t *lengthp;
682 {
683   struct loaded_domain *domain;
684   size_t act;
685   char *result;
686   size_t resultlen;
687
688   if (domain_file->decided == 0)
689     _nl_load_domain (domain_file, domainbinding);
690
691   if (domain_file->data == NULL)
692     return NULL;
693
694   domain = (struct loaded_domain *) domain_file->data;
695
696   /* Locate the MSGID and its translation.  */
697   if (domain->hash_size > 2 && domain->hash_tab != NULL)
698     {
699       /* Use the hashing table.  */
700       nls_uint32 len = strlen (msgid);
701       nls_uint32 hash_val = hash_string (msgid);
702       nls_uint32 idx = hash_val % domain->hash_size;
703       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
704
705       while (1)
706         {
707           nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
708
709           if (nstr == 0)
710             /* Hash table entry is empty.  */
711             return NULL;
712
713           /* Compare msgid with the original string at index nstr-1.
714              We compare the lengths with >=, not ==, because plural entries
715              are represented by strings with an embedded NUL.  */
716           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
717               && (strcmp (msgid,
718                           domain->data + W (domain->must_swap,
719                                             domain->orig_tab[nstr - 1].offset))
720                   == 0))
721             {
722               act = nstr - 1;
723               goto found;
724             }
725
726           if (idx >= domain->hash_size - incr)
727             idx -= domain->hash_size - incr;
728           else
729             idx += incr;
730         }
731       /* NOTREACHED */
732     }
733   else
734     {
735       /* Try the default method:  binary search in the sorted array of
736          messages.  */
737       size_t top, bottom;
738
739       bottom = 0;
740       top = domain->nstrings;
741       while (bottom < top)
742         {
743           int cmp_val;
744
745           act = (bottom + top) / 2;
746           cmp_val = strcmp (msgid, (domain->data
747                                     + W (domain->must_swap,
748                                          domain->orig_tab[act].offset)));
749           if (cmp_val < 0)
750             top = act;
751           else if (cmp_val > 0)
752             bottom = act + 1;
753           else
754             goto found;
755         }
756       /* No translation was found.  */
757       return NULL;
758     }
759
760  found:
761   /* The translation was found at index ACT.  If we have to convert the
762      string to use a different character set, this is the time.  */
763   result = ((char *) domain->data
764             + W (domain->must_swap, domain->trans_tab[act].offset));
765   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
766
767 #if defined _LIBC || HAVE_ICONV
768   if (domain->codeset_cntr
769       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
770     {
771       /* The domain's codeset has changed through bind_textdomain_codeset()
772          since the message catalog was initialized or last accessed.  We
773          have to reinitialize the converter.  */
774       _nl_free_domain_conv (domain);
775       _nl_init_domain_conv (domain_file, domain, domainbinding);
776     }
777
778   if (
779 # ifdef _LIBC
780       domain->conv != (__gconv_t) -1
781 # else
782 #  if HAVE_ICONV
783       domain->conv != (iconv_t) -1
784 #  endif
785 # endif
786       )
787     {
788       /* We are supposed to do a conversion.  First allocate an
789          appropriate table with the same structure as the table
790          of translations in the file, where we can put the pointers
791          to the converted strings in.
792          There is a slight complication with plural entries.  They
793          are represented by consecutive NUL terminated strings.  We
794          handle this case by converting RESULTLEN bytes, including
795          NULs.  */
796
797       if (domain->conv_tab == NULL
798           && ((domain->conv_tab = (char **) calloc (domain->nstrings,
799                                                     sizeof (char *)))
800               == NULL))
801         /* Mark that we didn't succeed allocating a table.  */
802         domain->conv_tab = (char **) -1;
803
804       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
805         /* Nothing we can do, no more memory.  */
806         goto converted;
807
808       if (domain->conv_tab[act] == NULL)
809         {
810           /* We haven't used this string so far, so it is not
811              translated yet.  Do this now.  */
812           /* We use a bit more efficient memory handling.
813              We allocate always larger blocks which get used over
814              time.  This is faster than many small allocations.   */
815           __libc_lock_define_initialized (static, lock)
816 # define INITIAL_BLOCK_SIZE     4080
817           static unsigned char *freemem;
818           static size_t freemem_size;
819
820           const unsigned char *inbuf;
821           unsigned char *outbuf;
822           int malloc_count;
823 # ifndef _LIBC
824           transmem_block_t *transmem_list = NULL;
825 # endif
826
827           __libc_lock_lock (lock);
828
829           inbuf = (const unsigned char *) result;
830           outbuf = freemem + sizeof (size_t);
831
832           malloc_count = 0;
833           while (1)
834             {
835               transmem_block_t *newmem;
836 # ifdef _LIBC
837               size_t non_reversible;
838               int res;
839
840               if (freemem_size < sizeof (size_t))
841                 goto resize_freemem;
842
843               res = __gconv (domain->conv,
844                              &inbuf, inbuf + resultlen,
845                              &outbuf,
846                              outbuf + freemem_size - sizeof (size_t),
847                              &non_reversible);
848
849               if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
850                 break;
851
852               if (res != __GCONV_FULL_OUTPUT)
853                 {
854                   __libc_lock_unlock (lock);
855                   goto converted;
856                 }
857
858               inbuf = result;
859 # else
860 #  if HAVE_ICONV
861               const char *inptr = (const char *) inbuf;
862               size_t inleft = resultlen;
863               char *outptr = (char *) outbuf;
864               size_t outleft;
865
866               if (freemem_size < sizeof (size_t))
867                 goto resize_freemem;
868
869               outleft = freemem_size - sizeof (size_t);
870               if (iconv (domain->conv,
871                          (ICONV_CONST char **) &inptr, &inleft,
872                          &outptr, &outleft)
873                   != (size_t) (-1))
874                 {
875                   outbuf = (unsigned char *) outptr;
876                   break;
877                 }
878               if (errno != E2BIG)
879                 {
880                   __libc_lock_unlock (lock);
881                   goto converted;
882                 }
883 #  endif
884 # endif
885
886             resize_freemem:
887               /* We must allocate a new buffer or resize the old one.  */
888               if (malloc_count > 0)
889                 {
890                   ++malloc_count;
891                   freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
892                   newmem = (transmem_block_t *) realloc (transmem_list,
893                                                          freemem_size);
894 # ifdef _LIBC
895                   if (newmem != NULL)
896                     transmem_list = transmem_list->next;
897                   else
898                     {
899                       struct transmem_list *old = transmem_list;
900
901                       transmem_list = transmem_list->next;
902                       free (old);
903                     }
904 # endif
905                 }
906               else
907                 {
908                   malloc_count = 1;
909                   freemem_size = INITIAL_BLOCK_SIZE;
910                   newmem = (transmem_block_t *) malloc (freemem_size);
911                 }
912               if (__builtin_expect (newmem == NULL, 0))
913                 {
914                   freemem = NULL;
915                   freemem_size = 0;
916                   __libc_lock_unlock (lock);
917                   goto converted;
918                 }
919
920 # ifdef _LIBC
921               /* Add the block to the list of blocks we have to free
922                  at some point.  */
923               newmem->next = transmem_list;
924               transmem_list = newmem;
925
926               freemem = newmem->data;
927               freemem_size -= offsetof (struct transmem_list, data);
928 # else
929               transmem_list = newmem;
930               freemem = newmem;
931 # endif
932
933               outbuf = freemem + sizeof (size_t);
934             }
935
936           /* We have now in our buffer a converted string.  Put this
937              into the table of conversions.  */
938           *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
939           domain->conv_tab[act] = (char *) freemem;
940           /* Shrink freemem, but keep it aligned.  */
941           freemem_size -= outbuf - freemem;
942           freemem = outbuf;
943           freemem += freemem_size & (alignof (size_t) - 1);
944           freemem_size = freemem_size & ~ (alignof (size_t) - 1);
945
946           __libc_lock_unlock (lock);
947         }
948
949       /* Now domain->conv_tab[act] contains the translation of all
950          the plural variants.  */
951       result = domain->conv_tab[act] + sizeof (size_t);
952       resultlen = *(size_t *) domain->conv_tab[act];
953     }
954
955  converted:
956   /* The result string is converted.  */
957
958 #endif /* _LIBC || HAVE_ICONV */
959
960   *lengthp = resultlen;
961   return result;
962 }
963
964
965 /* Look up a plural variant.  */
966 static char *
967 internal_function
968 plural_lookup (domain, n, translation, translation_len)
969      struct loaded_l10nfile *domain;
970      unsigned long int n;
971      const char *translation;
972      size_t translation_len;
973 {
974   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
975   unsigned long int index;
976   const char *p;
977
978   index = plural_eval (domaindata->plural, n);
979   if (index >= domaindata->nplurals)
980     /* This should never happen.  It means the plural expression and the
981        given maximum value do not match.  */
982     index = 0;
983
984   /* Skip INDEX strings at TRANSLATION.  */
985   p = translation;
986   while (index-- > 0)
987     {
988 #ifdef _LIBC
989       p = __rawmemchr (p, '\0');
990 #else
991       p = strchr (p, '\0');
992 #endif
993       /* And skip over the NUL byte.  */
994       p++;
995
996       if (p >= translation + translation_len)
997         /* This should never happen.  It means the plural expression
998            evaluated to a value larger than the number of variants
999            available for MSGID1.  */
1000         return (char *) translation;
1001     }
1002   return (char *) p;
1003 }
1004
1005
1006 /* Function to evaluate the plural expression and return an index value.  */
1007 static unsigned long int
1008 internal_function
1009 plural_eval (pexp, n)
1010      struct expression *pexp;
1011      unsigned long int n;
1012 {
1013   switch (pexp->nargs)
1014     {
1015     case 0:
1016       switch (pexp->operation)
1017         {
1018         case var:
1019           return n;
1020         case num:
1021           return pexp->val.num;
1022         default:
1023           break;
1024         }
1025       /* NOTREACHED */
1026       break;
1027     case 1:
1028       {
1029         /* pexp->operation must be lnot.  */
1030         unsigned long int arg = plural_eval (pexp->val.args[0], n);
1031         return ! arg;
1032       }
1033     case 2:
1034       {
1035         unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
1036         if (pexp->operation == lor)
1037           return leftarg || plural_eval (pexp->val.args[1], n);
1038         else if (pexp->operation == land)
1039           return leftarg && plural_eval (pexp->val.args[1], n);
1040         else
1041           {
1042             unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
1043
1044             switch (pexp->operation)
1045               {
1046               case mult:
1047                 return leftarg * rightarg;
1048               case divide:
1049                 return leftarg / rightarg;
1050               case module:
1051                 return leftarg % rightarg;
1052               case plus:
1053                 return leftarg + rightarg;
1054               case minus:
1055                 return leftarg - rightarg;
1056               case less_than:
1057                 return leftarg < rightarg;
1058               case greater_than:
1059                 return leftarg > rightarg;
1060               case less_or_equal:
1061                 return leftarg <= rightarg;
1062               case greater_or_equal:
1063                 return leftarg >= rightarg;
1064               case equal:
1065                 return leftarg == rightarg;
1066               case not_equal:
1067                 return leftarg != rightarg;
1068               default:
1069                 break;
1070               }
1071           }
1072         /* NOTREACHED */
1073         break;
1074       }
1075     case 3:
1076       {
1077         /* pexp->operation must be qmop.  */
1078         unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
1079         return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
1080       }
1081     }
1082   /* NOTREACHED */
1083   return 0;
1084 }
1085
1086
1087 /* Return string representation of locale CATEGORY.  */
1088 static const char *
1089 internal_function
1090 category_to_name (category)
1091      int category;
1092 {
1093   const char *retval;
1094
1095   switch (category)
1096   {
1097 #ifdef LC_COLLATE
1098   case LC_COLLATE:
1099     retval = "LC_COLLATE";
1100     break;
1101 #endif
1102 #ifdef LC_CTYPE
1103   case LC_CTYPE:
1104     retval = "LC_CTYPE";
1105     break;
1106 #endif
1107 #ifdef LC_MONETARY
1108   case LC_MONETARY:
1109     retval = "LC_MONETARY";
1110     break;
1111 #endif
1112 #ifdef LC_NUMERIC
1113   case LC_NUMERIC:
1114     retval = "LC_NUMERIC";
1115     break;
1116 #endif
1117 #ifdef LC_TIME
1118   case LC_TIME:
1119     retval = "LC_TIME";
1120     break;
1121 #endif
1122 #ifdef LC_MESSAGES
1123   case LC_MESSAGES:
1124     retval = "LC_MESSAGES";
1125     break;
1126 #endif
1127 #ifdef LC_RESPONSE
1128   case LC_RESPONSE:
1129     retval = "LC_RESPONSE";
1130     break;
1131 #endif
1132 #ifdef LC_ALL
1133   case LC_ALL:
1134     /* This might not make sense but is perhaps better than any other
1135        value.  */
1136     retval = "LC_ALL";
1137     break;
1138 #endif
1139   default:
1140     /* If you have a better idea for a default value let me know.  */
1141     retval = "LC_XXX";
1142   }
1143
1144   return retval;
1145 }
1146
1147 /* Guess value of current locale from value of the environment variables.  */
1148 static const char *
1149 internal_function
1150 guess_category_value (category, categoryname)
1151      int category;
1152      const char *categoryname;
1153 {
1154   const char *language;
1155   const char *retval;
1156
1157   /* The highest priority value is the `LANGUAGE' environment
1158      variable.  But we don't use the value if the currently selected
1159      locale is the C locale.  This is a GNU extension.  */
1160   language = getenv ("LANGUAGE");
1161   if (language != NULL && language[0] == '\0')
1162     language = NULL;
1163
1164   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1165      `LC_xxx', and `LANG'.  On some systems this can be done by the
1166      `setlocale' function itself.  */
1167 #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
1168   retval = setlocale (category, NULL);
1169 #else
1170   /* Setting of LC_ALL overwrites all other.  */
1171   retval = getenv ("LC_ALL");
1172   if (retval == NULL || retval[0] == '\0')
1173     {
1174       /* Next comes the name of the desired category.  */
1175       retval = getenv (categoryname);
1176       if (retval == NULL || retval[0] == '\0')
1177         {
1178           /* Last possibility is the LANG environment variable.  */
1179           retval = getenv ("LANG");
1180           if (retval == NULL || retval[0] == '\0')
1181             /* We use C as the default domain.  POSIX says this is
1182                implementation defined.  */
1183             return "C";
1184         }
1185     }
1186 #endif
1187
1188   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1189 }
1190
1191 /* @@ begin of epilog @@ */
1192
1193 /* We don't want libintl.a to depend on any other library.  So we
1194    avoid the non-standard function stpcpy.  In GNU C Library this
1195    function is available, though.  Also allow the symbol HAVE_STPCPY
1196    to be defined.  */
1197 #if !_LIBC && !HAVE_STPCPY
1198 static char *
1199 stpcpy (dest, src)
1200      char *dest;
1201      const char *src;
1202 {
1203   while ((*dest++ = *src++) != '\0')
1204     /* Do nothing. */ ;
1205   return dest - 1;
1206 }
1207 #endif
1208
1209 #if !_LIBC && !HAVE_MEMPCPY
1210 static void *
1211 mempcpy (dest, src, n)
1212      void *dest;
1213      const void *src;
1214      size_t n;
1215 {
1216   return (void *) ((char *) memcpy (dest, src, n) + n);
1217 }
1218 #endif
1219
1220
1221 #ifdef _LIBC
1222 /* If we want to free all resources we have to do some work at
1223    program's end.  */
1224 static void __attribute__ ((unused))
1225 free_mem (void)
1226 {
1227   void *old;
1228
1229   while (_nl_domain_bindings != NULL)
1230     {
1231       struct binding *oldp = _nl_domain_bindings;
1232       _nl_domain_bindings = _nl_domain_bindings->next;
1233       if (oldp->dirname != _nl_default_dirname)
1234         /* Yes, this is a pointer comparison.  */
1235         free (oldp->dirname);
1236       free (oldp->codeset);
1237       free (oldp);
1238     }
1239
1240   if (_nl_current_default_domain != _nl_default_default_domain)
1241     /* Yes, again a pointer comparison.  */
1242     free ((char *) _nl_current_default_domain);
1243
1244   /* Remove the search tree with the known translations.  */
1245   __tdestroy (root, free);
1246   root = NULL;
1247
1248   while (transmem_list != NULL)
1249     {
1250       old = transmem_list;
1251       transmem_list = transmem_list->next;
1252       free (old);
1253     }
1254 }
1255
1256 text_set_element (__libc_subfreeres, free_mem);
1257 #endif