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