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