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