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