OSDN Git Service

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