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