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