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