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