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