dcigettext.c revision 1.1 1 1.1 christos /* Implementation of the internal dcigettext function.
2 1.1 christos Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This program is free software; you can redistribute it and/or modify it
5 1.1 christos under the terms of the GNU Library General Public License as published
6 1.1 christos by the Free Software Foundation; either version 2, or (at your option)
7 1.1 christos any later version.
8 1.1 christos
9 1.1 christos This program is distributed in the hope that it will be useful,
10 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
11 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 1.1 christos Library General Public License for more details.
13 1.1 christos
14 1.1 christos You should have received a copy of the GNU Library General Public
15 1.1 christos License along with this program; if not, write to the Free Software
16 1.1 christos Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 1.1 christos USA. */
18 1.1 christos
19 1.1 christos /* Tell glibc's <string.h> to provide a prototype for mempcpy().
20 1.1 christos This must come before <config.h> because <config.h> may include
21 1.1 christos <features.h>, and once <features.h> has been included, it's too late. */
22 1.1 christos #ifndef _GNU_SOURCE
23 1.1 christos # define _GNU_SOURCE 1
24 1.1 christos #endif
25 1.1 christos
26 1.1 christos #ifdef HAVE_CONFIG_H
27 1.1 christos # include <config.h>
28 1.1 christos #endif
29 1.1 christos
30 1.1 christos /* NL_LOCALE_NAME does not work in glibc-2.4. Ignore it. */
31 1.1 christos #undef HAVE_NL_LOCALE_NAME
32 1.1 christos
33 1.1 christos #include <sys/types.h>
34 1.1 christos
35 1.1 christos #ifdef __GNUC__
36 1.1 christos # define alloca __builtin_alloca
37 1.1 christos # define HAVE_ALLOCA 1
38 1.1 christos #else
39 1.1 christos # ifdef _MSC_VER
40 1.1 christos # include <malloc.h>
41 1.1 christos # define alloca _alloca
42 1.1 christos # else
43 1.1 christos # if defined HAVE_ALLOCA_H || defined _LIBC
44 1.1 christos # include <alloca.h>
45 1.1 christos # else
46 1.1 christos # ifdef _AIX
47 1.1 christos #pragma alloca
48 1.1 christos # else
49 1.1 christos # ifndef alloca
50 1.1 christos char *alloca ();
51 1.1 christos # endif
52 1.1 christos # endif
53 1.1 christos # endif
54 1.1 christos # endif
55 1.1 christos #endif
56 1.1 christos
57 1.1 christos #include <errno.h>
58 1.1 christos #ifndef errno
59 1.1 christos extern int errno;
60 1.1 christos #endif
61 1.1 christos #ifndef __set_errno
62 1.1 christos # define __set_errno(val) errno = (val)
63 1.1 christos #endif
64 1.1 christos
65 1.1 christos #include <stddef.h>
66 1.1 christos #include <stdlib.h>
67 1.1 christos #include <string.h>
68 1.1 christos
69 1.1 christos #if defined HAVE_UNISTD_H || defined _LIBC
70 1.1 christos # include <unistd.h>
71 1.1 christos #endif
72 1.1 christos
73 1.1 christos #include <locale.h>
74 1.1 christos
75 1.1 christos #ifdef _LIBC
76 1.1 christos /* Guess whether integer division by zero raises signal SIGFPE.
77 1.1 christos Set to 1 only if you know for sure. In case of doubt, set to 0. */
78 1.1 christos # if defined __alpha__ || defined __arm__ || defined __i386__ \
79 1.1 christos || defined __m68k__ || defined __s390__
80 1.1 christos # define INTDIV0_RAISES_SIGFPE 1
81 1.1 christos # else
82 1.1 christos # define INTDIV0_RAISES_SIGFPE 0
83 1.1 christos # endif
84 1.1 christos #endif
85 1.1 christos #if !INTDIV0_RAISES_SIGFPE
86 1.1 christos # include <signal.h>
87 1.1 christos #endif
88 1.1 christos
89 1.1 christos #if defined HAVE_SYS_PARAM_H || defined _LIBC
90 1.1 christos # include <sys/param.h>
91 1.1 christos #endif
92 1.1 christos
93 1.1 christos #if !defined _LIBC && HAVE_NL_LOCALE_NAME
94 1.1 christos # include <langinfo.h>
95 1.1 christos #endif
96 1.1 christos
97 1.1 christos #include "gettextP.h"
98 1.1 christos #include "plural-exp.h"
99 1.1 christos #ifdef _LIBC
100 1.1 christos # include <libintl.h>
101 1.1 christos #else
102 1.1 christos # ifdef IN_LIBGLOCALE
103 1.1 christos # include <libintl.h>
104 1.1 christos # endif
105 1.1 christos # include "libgnuintl.h"
106 1.1 christos #endif
107 1.1 christos #include "hash-string.h"
108 1.1 christos
109 1.1 christos /* Handle multi-threaded applications. */
110 1.1 christos #ifdef _LIBC
111 1.1 christos # include <bits/libc-lock.h>
112 1.1 christos # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
113 1.1 christos # define gl_rwlock_rdlock __libc_rwlock_rdlock
114 1.1 christos # define gl_rwlock_wrlock __libc_rwlock_wrlock
115 1.1 christos # define gl_rwlock_unlock __libc_rwlock_unlock
116 1.1 christos #else
117 1.1 christos # include "lock.h"
118 1.1 christos #endif
119 1.1 christos
120 1.1 christos /* Alignment of types. */
121 1.1 christos #if defined __GNUC__ && __GNUC__ >= 2
122 1.1 christos # define alignof(TYPE) __alignof__ (TYPE)
123 1.1 christos #else
124 1.1 christos # define alignof(TYPE) \
125 1.1 christos ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
126 1.1 christos #endif
127 1.1 christos
128 1.1 christos /* The internal variables in the standalone libintl.a must have different
129 1.1 christos names than the internal variables in GNU libc, otherwise programs
130 1.1 christos using libintl.a cannot be linked statically. */
131 1.1 christos #if !defined _LIBC
132 1.1 christos # define _nl_default_default_domain libintl_nl_default_default_domain
133 1.1 christos # define _nl_current_default_domain libintl_nl_current_default_domain
134 1.1 christos # define _nl_default_dirname libintl_nl_default_dirname
135 1.1 christos # define _nl_domain_bindings libintl_nl_domain_bindings
136 1.1 christos #endif
137 1.1 christos
138 1.1 christos /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
139 1.1 christos #ifndef offsetof
140 1.1 christos # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
141 1.1 christos #endif
142 1.1 christos
143 1.1 christos /* @@ end of prolog @@ */
144 1.1 christos
145 1.1 christos #ifdef _LIBC
146 1.1 christos /* Rename the non ANSI C functions. This is required by the standard
147 1.1 christos because some ANSI C functions will require linking with this object
148 1.1 christos file and the name space must not be polluted. */
149 1.1 christos # define getcwd __getcwd
150 1.1 christos # ifndef stpcpy
151 1.1 christos # define stpcpy __stpcpy
152 1.1 christos # endif
153 1.1 christos # define tfind __tfind
154 1.1 christos #else
155 1.1 christos # if !defined HAVE_GETCWD
156 1.1 christos char *getwd ();
157 1.1 christos # define getcwd(buf, max) getwd (buf)
158 1.1 christos # else
159 1.1 christos # if VMS
160 1.1 christos # define getcwd(buf, max) (getcwd) (buf, max, 0)
161 1.1 christos # else
162 1.1 christos char *getcwd ();
163 1.1 christos # endif
164 1.1 christos # endif
165 1.1 christos # ifndef HAVE_STPCPY
166 1.1 christos static char *stpcpy (char *dest, const char *src);
167 1.1 christos # endif
168 1.1 christos # ifndef HAVE_MEMPCPY
169 1.1 christos static void *mempcpy (void *dest, const void *src, size_t n);
170 1.1 christos # endif
171 1.1 christos #endif
172 1.1 christos
173 1.1 christos /* Amount to increase buffer size by in each try. */
174 1.1 christos #define PATH_INCR 32
175 1.1 christos
176 1.1 christos /* The following is from pathmax.h. */
177 1.1 christos /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
178 1.1 christos PATH_MAX but might cause redefinition warnings when sys/param.h is
179 1.1 christos later included (as on MORE/BSD 4.3). */
180 1.1 christos #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
181 1.1 christos # include <limits.h>
182 1.1 christos #endif
183 1.1 christos
184 1.1 christos #ifndef _POSIX_PATH_MAX
185 1.1 christos # define _POSIX_PATH_MAX 255
186 1.1 christos #endif
187 1.1 christos
188 1.1 christos #if !defined PATH_MAX && defined _PC_PATH_MAX
189 1.1 christos # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
190 1.1 christos #endif
191 1.1 christos
192 1.1 christos /* Don't include sys/param.h if it already has been. */
193 1.1 christos #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
194 1.1 christos # include <sys/param.h>
195 1.1 christos #endif
196 1.1 christos
197 1.1 christos #if !defined PATH_MAX && defined MAXPATHLEN
198 1.1 christos # define PATH_MAX MAXPATHLEN
199 1.1 christos #endif
200 1.1 christos
201 1.1 christos #ifndef PATH_MAX
202 1.1 christos # define PATH_MAX _POSIX_PATH_MAX
203 1.1 christos #endif
204 1.1 christos
205 1.1 christos /* Pathname support.
206 1.1 christos ISSLASH(C) tests whether C is a directory separator character.
207 1.1 christos IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
208 1.1 christos it may be concatenated to a directory pathname.
209 1.1 christos IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
210 1.1 christos */
211 1.1 christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
212 1.1 christos /* Win32, Cygwin, OS/2, DOS */
213 1.1 christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
214 1.1 christos # define HAS_DEVICE(P) \
215 1.1 christos ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
216 1.1 christos && (P)[1] == ':')
217 1.1 christos # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
218 1.1 christos # define IS_PATH_WITH_DIR(P) \
219 1.1 christos (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
220 1.1 christos #else
221 1.1 christos /* Unix */
222 1.1 christos # define ISSLASH(C) ((C) == '/')
223 1.1 christos # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
224 1.1 christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
225 1.1 christos #endif
226 1.1 christos
227 1.1 christos /* Whether to support different locales in different threads. */
228 1.1 christos #if defined _LIBC || HAVE_NL_LOCALE_NAME || (HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS) || defined IN_LIBGLOCALE
229 1.1 christos # define HAVE_PER_THREAD_LOCALE
230 1.1 christos #endif
231 1.1 christos
232 1.1 christos /* This is the type used for the search tree where known translations
233 1.1 christos are stored. */
234 1.1 christos struct known_translation_t
235 1.1 christos {
236 1.1 christos /* Domain in which to search. */
237 1.1 christos const char *domainname;
238 1.1 christos
239 1.1 christos /* The category. */
240 1.1 christos int category;
241 1.1 christos
242 1.1 christos #ifdef HAVE_PER_THREAD_LOCALE
243 1.1 christos /* Name of the relevant locale category, or "" for the global locale. */
244 1.1 christos const char *localename;
245 1.1 christos #endif
246 1.1 christos
247 1.1 christos #ifdef IN_LIBGLOCALE
248 1.1 christos /* The character encoding. */
249 1.1 christos const char *encoding;
250 1.1 christos #endif
251 1.1 christos
252 1.1 christos /* State of the catalog counter at the point the string was found. */
253 1.1 christos int counter;
254 1.1 christos
255 1.1 christos /* Catalog where the string was found. */
256 1.1 christos struct loaded_l10nfile *domain;
257 1.1 christos
258 1.1 christos /* And finally the translation. */
259 1.1 christos const char *translation;
260 1.1 christos size_t translation_length;
261 1.1 christos
262 1.1 christos /* Pointer to the string in question. */
263 1.1 christos char msgid[ZERO];
264 1.1 christos };
265 1.1 christos
266 1.1 christos /* Root of the search tree with known translations. We can use this
267 1.1 christos only if the system provides the `tsearch' function family. */
268 1.1 christos #if defined HAVE_TSEARCH || defined _LIBC
269 1.1 christos # include <search.h>
270 1.1 christos
271 1.1 christos gl_rwlock_define_initialized (static, tree_lock)
272 1.1 christos
273 1.1 christos static void *root;
274 1.1 christos
275 1.1 christos # ifdef _LIBC
276 1.1 christos # define tsearch __tsearch
277 1.1 christos # endif
278 1.1 christos
279 1.1 christos /* Function to compare two entries in the table of known translations. */
280 1.1 christos static int
281 1.1 christos transcmp (const void *p1, const void *p2)
282 1.1 christos {
283 1.1 christos const struct known_translation_t *s1;
284 1.1 christos const struct known_translation_t *s2;
285 1.1 christos int result;
286 1.1 christos
287 1.1 christos s1 = (const struct known_translation_t *) p1;
288 1.1 christos s2 = (const struct known_translation_t *) p2;
289 1.1 christos
290 1.1 christos result = strcmp (s1->msgid, s2->msgid);
291 1.1 christos if (result == 0)
292 1.1 christos {
293 1.1 christos result = strcmp (s1->domainname, s2->domainname);
294 1.1 christos if (result == 0)
295 1.1 christos {
296 1.1 christos #ifdef HAVE_PER_THREAD_LOCALE
297 1.1 christos result = strcmp (s1->localename, s2->localename);
298 1.1 christos if (result == 0)
299 1.1 christos #endif
300 1.1 christos {
301 1.1 christos #ifdef IN_LIBGLOCALE
302 1.1 christos result = strcmp (s1->encoding, s2->encoding);
303 1.1 christos if (result == 0)
304 1.1 christos #endif
305 1.1 christos /* We compare the category last (though this is the cheapest
306 1.1 christos operation) since it is hopefully always the same (namely
307 1.1 christos LC_MESSAGES). */
308 1.1 christos result = s1->category - s2->category;
309 1.1 christos }
310 1.1 christos }
311 1.1 christos }
312 1.1 christos
313 1.1 christos return result;
314 1.1 christos }
315 1.1 christos #endif
316 1.1 christos
317 1.1 christos /* Name of the default domain used for gettext(3) prior any call to
318 1.1 christos textdomain(3). The default value for this is "messages". */
319 1.1 christos const char _nl_default_default_domain[] attribute_hidden = "messages";
320 1.1 christos
321 1.1 christos #ifndef IN_LIBGLOCALE
322 1.1 christos /* Value used as the default domain for gettext(3). */
323 1.1 christos const char *_nl_current_default_domain attribute_hidden
324 1.1 christos = _nl_default_default_domain;
325 1.1 christos #endif
326 1.1 christos
327 1.1 christos /* Contains the default location of the message catalogs. */
328 1.1 christos #if defined __EMX__
329 1.1 christos extern const char _nl_default_dirname[];
330 1.1 christos #else
331 1.1 christos # ifdef _LIBC
332 1.1 christos extern const char _nl_default_dirname[];
333 1.1 christos libc_hidden_proto (_nl_default_dirname)
334 1.1 christos # endif
335 1.1 christos const char _nl_default_dirname[] = LOCALEDIR;
336 1.1 christos # ifdef _LIBC
337 1.1 christos libc_hidden_data_def (_nl_default_dirname)
338 1.1 christos # endif
339 1.1 christos #endif
340 1.1 christos
341 1.1 christos #ifndef IN_LIBGLOCALE
342 1.1 christos /* List with bindings of specific domains created by bindtextdomain()
343 1.1 christos calls. */
344 1.1 christos struct binding *_nl_domain_bindings;
345 1.1 christos #endif
346 1.1 christos
347 1.1 christos /* Prototypes for local functions. */
348 1.1 christos static char *plural_lookup (struct loaded_l10nfile *domain,
349 1.1 christos unsigned long int n,
350 1.1 christos const char *translation, size_t translation_len)
351 1.1 christos internal_function;
352 1.1 christos
353 1.1 christos #ifdef IN_LIBGLOCALE
354 1.1 christos static const char *guess_category_value (int category,
355 1.1 christos const char *categoryname,
356 1.1 christos const char *localename)
357 1.1 christos internal_function;
358 1.1 christos #else
359 1.1 christos static const char *guess_category_value (int category,
360 1.1 christos const char *categoryname)
361 1.1 christos internal_function;
362 1.1 christos #endif
363 1.1 christos
364 1.1 christos #ifdef _LIBC
365 1.1 christos # include "../locale/localeinfo.h"
366 1.1 christos # define category_to_name(category) \
367 1.1 christos _nl_category_names.str + _nl_category_name_idxs[category]
368 1.1 christos #else
369 1.1 christos static const char *category_to_name (int category) internal_function;
370 1.1 christos #endif
371 1.1 christos #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
372 1.1 christos static const char *get_output_charset (struct binding *domainbinding)
373 1.1 christos internal_function;
374 1.1 christos #endif
375 1.1 christos
376 1.1 christos
377 1.1 christos /* For those loosing systems which don't have `alloca' we have to add
378 1.1 christos some additional code emulating it. */
379 1.1 christos #ifdef HAVE_ALLOCA
380 1.1 christos /* Nothing has to be done. */
381 1.1 christos # define freea(p) /* nothing */
382 1.1 christos # define ADD_BLOCK(list, address) /* nothing */
383 1.1 christos # define FREE_BLOCKS(list) /* nothing */
384 1.1 christos #else
385 1.1 christos struct block_list
386 1.1 christos {
387 1.1 christos void *address;
388 1.1 christos struct block_list *next;
389 1.1 christos };
390 1.1 christos # define ADD_BLOCK(list, addr) \
391 1.1 christos do { \
392 1.1 christos struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
393 1.1 christos /* If we cannot get a free block we cannot add the new element to \
394 1.1 christos the list. */ \
395 1.1 christos if (newp != NULL) { \
396 1.1 christos newp->address = (addr); \
397 1.1 christos newp->next = (list); \
398 1.1 christos (list) = newp; \
399 1.1 christos } \
400 1.1 christos } while (0)
401 1.1 christos # define FREE_BLOCKS(list) \
402 1.1 christos do { \
403 1.1 christos while (list != NULL) { \
404 1.1 christos struct block_list *old = list; \
405 1.1 christos list = list->next; \
406 1.1 christos free (old->address); \
407 1.1 christos free (old); \
408 1.1 christos } \
409 1.1 christos } while (0)
410 1.1 christos # undef alloca
411 1.1 christos # define alloca(size) (malloc (size))
412 1.1 christos # define freea(p) free (p)
413 1.1 christos #endif /* have alloca */
414 1.1 christos
415 1.1 christos
416 1.1 christos #ifdef _LIBC
417 1.1 christos /* List of blocks allocated for translations. */
418 1.1 christos typedef struct transmem_list
419 1.1 christos {
420 1.1 christos struct transmem_list *next;
421 1.1 christos char data[ZERO];
422 1.1 christos } transmem_block_t;
423 1.1 christos static struct transmem_list *transmem_list;
424 1.1 christos #else
425 1.1 christos typedef unsigned char transmem_block_t;
426 1.1 christos #endif
427 1.1 christos
428 1.1 christos
429 1.1 christos /* Names for the libintl functions are a problem. They must not clash
430 1.1 christos with existing names and they should follow ANSI C. But this source
431 1.1 christos code is also used in GNU C Library where the names have a __
432 1.1 christos prefix. So we have to make a difference here. */
433 1.1 christos #ifdef _LIBC
434 1.1 christos # define DCIGETTEXT __dcigettext
435 1.1 christos #else
436 1.1 christos # define DCIGETTEXT libintl_dcigettext
437 1.1 christos #endif
438 1.1 christos
439 1.1 christos /* Lock variable to protect the global data in the gettext implementation. */
440 1.1 christos gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
441 1.1 christos
442 1.1 christos /* Checking whether the binaries runs SUID must be done and glibc provides
443 1.1 christos easier methods therefore we make a difference here. */
444 1.1 christos #ifdef _LIBC
445 1.1 christos # define ENABLE_SECURE __libc_enable_secure
446 1.1 christos # define DETERMINE_SECURE
447 1.1 christos #else
448 1.1 christos # ifndef HAVE_GETUID
449 1.1 christos # define getuid() 0
450 1.1 christos # endif
451 1.1 christos # ifndef HAVE_GETGID
452 1.1 christos # define getgid() 0
453 1.1 christos # endif
454 1.1 christos # ifndef HAVE_GETEUID
455 1.1 christos # define geteuid() getuid()
456 1.1 christos # endif
457 1.1 christos # ifndef HAVE_GETEGID
458 1.1 christos # define getegid() getgid()
459 1.1 christos # endif
460 1.1 christos static int enable_secure;
461 1.1 christos # define ENABLE_SECURE (enable_secure == 1)
462 1.1 christos # define DETERMINE_SECURE \
463 1.1 christos if (enable_secure == 0) \
464 1.1 christos { \
465 1.1 christos if (getuid () != geteuid () || getgid () != getegid ()) \
466 1.1 christos enable_secure = 1; \
467 1.1 christos else \
468 1.1 christos enable_secure = -1; \
469 1.1 christos }
470 1.1 christos #endif
471 1.1 christos
472 1.1 christos /* Get the function to evaluate the plural expression. */
473 1.1 christos #include "eval-plural.h"
474 1.1 christos
475 1.1 christos /* Look up MSGID in the DOMAINNAME message catalog for the current
476 1.1 christos CATEGORY locale and, if PLURAL is nonzero, search over string
477 1.1 christos depending on the plural form determined by N. */
478 1.1 christos #ifdef IN_LIBGLOCALE
479 1.1 christos char *
480 1.1 christos gl_dcigettext (const char *domainname,
481 1.1 christos const char *msgid1, const char *msgid2,
482 1.1 christos int plural, unsigned long int n,
483 1.1 christos int category,
484 1.1 christos const char *localename, const char *encoding)
485 1.1 christos #else
486 1.1 christos char *
487 1.1 christos DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
488 1.1 christos int plural, unsigned long int n, int category)
489 1.1 christos #endif
490 1.1 christos {
491 1.1 christos #ifndef HAVE_ALLOCA
492 1.1 christos struct block_list *block_list = NULL;
493 1.1 christos #endif
494 1.1 christos struct loaded_l10nfile *domain;
495 1.1 christos struct binding *binding;
496 1.1 christos const char *categoryname;
497 1.1 christos const char *categoryvalue;
498 1.1 christos const char *dirname;
499 1.1 christos char *xdomainname;
500 1.1 christos char *single_locale;
501 1.1 christos char *retval;
502 1.1 christos size_t retlen;
503 1.1 christos int saved_errno;
504 1.1 christos #if defined HAVE_TSEARCH || defined _LIBC
505 1.1 christos struct known_translation_t *search;
506 1.1 christos struct known_translation_t **foundp = NULL;
507 1.1 christos size_t msgid_len;
508 1.1 christos # if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
509 1.1 christos const char *localename;
510 1.1 christos # endif
511 1.1 christos #endif
512 1.1 christos size_t domainname_len;
513 1.1 christos
514 1.1 christos /* If no real MSGID is given return NULL. */
515 1.1 christos if (msgid1 == NULL)
516 1.1 christos return NULL;
517 1.1 christos
518 1.1 christos #ifdef _LIBC
519 1.1 christos if (category < 0 || category >= __LC_LAST || category == LC_ALL)
520 1.1 christos /* Bogus. */
521 1.1 christos return (plural == 0
522 1.1 christos ? (char *) msgid1
523 1.1 christos /* Use the Germanic plural rule. */
524 1.1 christos : n == 1 ? (char *) msgid1 : (char *) msgid2);
525 1.1 christos #endif
526 1.1 christos
527 1.1 christos gl_rwlock_rdlock (_nl_state_lock);
528 1.1 christos
529 1.1 christos /* If DOMAINNAME is NULL, we are interested in the default domain. If
530 1.1 christos CATEGORY is not LC_MESSAGES this might not make much sense but the
531 1.1 christos definition left this undefined. */
532 1.1 christos if (domainname == NULL)
533 1.1 christos domainname = _nl_current_default_domain;
534 1.1 christos
535 1.1 christos /* OS/2 specific: backward compatibility with older libintl versions */
536 1.1 christos #ifdef LC_MESSAGES_COMPAT
537 1.1 christos if (category == LC_MESSAGES_COMPAT)
538 1.1 christos category = LC_MESSAGES;
539 1.1 christos #endif
540 1.1 christos
541 1.1 christos #if defined HAVE_TSEARCH || defined _LIBC
542 1.1 christos msgid_len = strlen (msgid1) + 1;
543 1.1 christos
544 1.1 christos /* Try to find the translation among those which we found at
545 1.1 christos some time. */
546 1.1 christos search = (struct known_translation_t *)
547 1.1 christos alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
548 1.1 christos memcpy (search->msgid, msgid1, msgid_len);
549 1.1 christos search->domainname = domainname;
550 1.1 christos search->category = category;
551 1.1 christos # ifdef HAVE_PER_THREAD_LOCALE
552 1.1 christos # ifndef IN_LIBGLOCALE
553 1.1 christos # ifdef _LIBC
554 1.1 christos localename = __current_locale_name (category);
555 1.1 christos # else
556 1.1 christos # if HAVE_NL_LOCALE_NAME
557 1.1 christos /* NL_LOCALE_NAME is public glibc API introduced in glibc-2.4. */
558 1.1 christos localename = nl_langinfo (NL_LOCALE_NAME (category));
559 1.1 christos # else
560 1.1 christos # if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
561 1.1 christos /* The __names field is not public glibc API and must therefore not be used
562 1.1 christos in code that is installed in public locations. */
563 1.1 christos {
564 1.1 christos locale_t thread_locale = uselocale (NULL);
565 1.1 christos if (thread_locale != LC_GLOBAL_LOCALE)
566 1.1 christos localename = thread_locale->__names[category];
567 1.1 christos else
568 1.1 christos localename = "";
569 1.1 christos }
570 1.1 christos # endif
571 1.1 christos # endif
572 1.1 christos # endif
573 1.1 christos # endif
574 1.1 christos search->localename = localename;
575 1.1 christos # ifdef IN_LIBGLOCALE
576 1.1 christos search->encoding = encoding;
577 1.1 christos # endif
578 1.1 christos # endif
579 1.1 christos
580 1.1 christos /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
581 1.1 christos tsearch calls can be fatal. */
582 1.1 christos gl_rwlock_rdlock (tree_lock);
583 1.1 christos
584 1.1 christos foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
585 1.1 christos
586 1.1 christos gl_rwlock_unlock (tree_lock);
587 1.1 christos
588 1.1 christos freea (search);
589 1.1 christos if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
590 1.1 christos {
591 1.1 christos /* Now deal with plural. */
592 1.1 christos if (plural)
593 1.1 christos retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
594 1.1 christos (*foundp)->translation_length);
595 1.1 christos else
596 1.1 christos retval = (char *) (*foundp)->translation;
597 1.1 christos
598 1.1 christos gl_rwlock_unlock (_nl_state_lock);
599 1.1 christos return retval;
600 1.1 christos }
601 1.1 christos #endif
602 1.1 christos
603 1.1 christos /* Preserve the `errno' value. */
604 1.1 christos saved_errno = errno;
605 1.1 christos
606 1.1 christos /* See whether this is a SUID binary or not. */
607 1.1 christos DETERMINE_SECURE;
608 1.1 christos
609 1.1 christos /* First find matching binding. */
610 1.1 christos #ifdef IN_LIBGLOCALE
611 1.1 christos /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
612 1.1 christos and _nl_load_domain and _nl_find_domain just pass it through. */
613 1.1 christos binding = NULL;
614 1.1 christos dirname = bindtextdomain (domainname, NULL);
615 1.1 christos #else
616 1.1 christos for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
617 1.1 christos {
618 1.1 christos int compare = strcmp (domainname, binding->domainname);
619 1.1 christos if (compare == 0)
620 1.1 christos /* We found it! */
621 1.1 christos break;
622 1.1 christos if (compare < 0)
623 1.1 christos {
624 1.1 christos /* It is not in the list. */
625 1.1 christos binding = NULL;
626 1.1 christos break;
627 1.1 christos }
628 1.1 christos }
629 1.1 christos
630 1.1 christos if (binding == NULL)
631 1.1 christos dirname = _nl_default_dirname;
632 1.1 christos else
633 1.1 christos {
634 1.1 christos dirname = binding->dirname;
635 1.1 christos #endif
636 1.1 christos if (!IS_ABSOLUTE_PATH (dirname))
637 1.1 christos {
638 1.1 christos /* We have a relative path. Make it absolute now. */
639 1.1 christos size_t dirname_len = strlen (dirname) + 1;
640 1.1 christos size_t path_max;
641 1.1 christos char *resolved_dirname;
642 1.1 christos char *ret;
643 1.1 christos
644 1.1 christos path_max = (unsigned int) PATH_MAX;
645 1.1 christos path_max += 2; /* The getcwd docs say to do this. */
646 1.1 christos
647 1.1 christos for (;;)
648 1.1 christos {
649 1.1 christos resolved_dirname = (char *) alloca (path_max + dirname_len);
650 1.1 christos ADD_BLOCK (block_list, tmp_dirname);
651 1.1 christos
652 1.1 christos __set_errno (0);
653 1.1 christos ret = getcwd (resolved_dirname, path_max);
654 1.1 christos if (ret != NULL || errno != ERANGE)
655 1.1 christos break;
656 1.1 christos
657 1.1 christos path_max += path_max / 2;
658 1.1 christos path_max += PATH_INCR;
659 1.1 christos }
660 1.1 christos
661 1.1 christos if (ret == NULL)
662 1.1 christos /* We cannot get the current working directory. Don't signal an
663 1.1 christos error but simply return the default string. */
664 1.1 christos goto return_untranslated;
665 1.1 christos
666 1.1 christos stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
667 1.1 christos dirname = resolved_dirname;
668 1.1 christos }
669 1.1 christos #ifndef IN_LIBGLOCALE
670 1.1 christos }
671 1.1 christos #endif
672 1.1 christos
673 1.1 christos /* Now determine the symbolic name of CATEGORY and its value. */
674 1.1 christos categoryname = category_to_name (category);
675 1.1 christos #ifdef IN_LIBGLOCALE
676 1.1 christos categoryvalue = guess_category_value (category, categoryname, localename);
677 1.1 christos #else
678 1.1 christos categoryvalue = guess_category_value (category, categoryname);
679 1.1 christos #endif
680 1.1 christos
681 1.1 christos domainname_len = strlen (domainname);
682 1.1 christos xdomainname = (char *) alloca (strlen (categoryname)
683 1.1 christos + domainname_len + 5);
684 1.1 christos ADD_BLOCK (block_list, xdomainname);
685 1.1 christos
686 1.1 christos stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
687 1.1 christos domainname, domainname_len),
688 1.1 christos ".mo");
689 1.1 christos
690 1.1 christos /* Creating working area. */
691 1.1 christos single_locale = (char *) alloca (strlen (categoryvalue) + 1);
692 1.1 christos ADD_BLOCK (block_list, single_locale);
693 1.1 christos
694 1.1 christos
695 1.1 christos /* Search for the given string. This is a loop because we perhaps
696 1.1 christos got an ordered list of languages to consider for the translation. */
697 1.1 christos while (1)
698 1.1 christos {
699 1.1 christos /* Make CATEGORYVALUE point to the next element of the list. */
700 1.1 christos while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
701 1.1 christos ++categoryvalue;
702 1.1 christos if (categoryvalue[0] == '\0')
703 1.1 christos {
704 1.1 christos /* The whole contents of CATEGORYVALUE has been searched but
705 1.1 christos no valid entry has been found. We solve this situation
706 1.1 christos by implicitly appending a "C" entry, i.e. no translation
707 1.1 christos will take place. */
708 1.1 christos single_locale[0] = 'C';
709 1.1 christos single_locale[1] = '\0';
710 1.1 christos }
711 1.1 christos else
712 1.1 christos {
713 1.1 christos char *cp = single_locale;
714 1.1 christos while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
715 1.1 christos *cp++ = *categoryvalue++;
716 1.1 christos *cp = '\0';
717 1.1 christos
718 1.1 christos /* When this is a SUID binary we must not allow accessing files
719 1.1 christos outside the dedicated directories. */
720 1.1 christos if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
721 1.1 christos /* Ingore this entry. */
722 1.1 christos continue;
723 1.1 christos }
724 1.1 christos
725 1.1 christos /* If the current locale value is C (or POSIX) we don't load a
726 1.1 christos domain. Return the MSGID. */
727 1.1 christos if (strcmp (single_locale, "C") == 0
728 1.1 christos || strcmp (single_locale, "POSIX") == 0)
729 1.1 christos break;
730 1.1 christos
731 1.1 christos /* Find structure describing the message catalog matching the
732 1.1 christos DOMAINNAME and CATEGORY. */
733 1.1 christos domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
734 1.1 christos
735 1.1 christos if (domain != NULL)
736 1.1 christos {
737 1.1 christos #if defined IN_LIBGLOCALE
738 1.1 christos retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
739 1.1 christos #else
740 1.1 christos retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
741 1.1 christos #endif
742 1.1 christos
743 1.1 christos if (retval == NULL)
744 1.1 christos {
745 1.1 christos int cnt;
746 1.1 christos
747 1.1 christos for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
748 1.1 christos {
749 1.1 christos #if defined IN_LIBGLOCALE
750 1.1 christos retval = _nl_find_msg (domain->successor[cnt], binding,
751 1.1 christos encoding, msgid1, &retlen);
752 1.1 christos #else
753 1.1 christos retval = _nl_find_msg (domain->successor[cnt], binding,
754 1.1 christos msgid1, 1, &retlen);
755 1.1 christos #endif
756 1.1 christos
757 1.1 christos if (retval != NULL)
758 1.1 christos {
759 1.1 christos domain = domain->successor[cnt];
760 1.1 christos break;
761 1.1 christos }
762 1.1 christos }
763 1.1 christos }
764 1.1 christos
765 1.1 christos /* Returning -1 means that some resource problem exists
766 1.1 christos (likely memory) and that the strings could not be
767 1.1 christos converted. Return the original strings. */
768 1.1 christos if (__builtin_expect (retval == (char *) -1, 0))
769 1.1 christos break;
770 1.1 christos
771 1.1 christos if (retval != NULL)
772 1.1 christos {
773 1.1 christos /* Found the translation of MSGID1 in domain DOMAIN:
774 1.1 christos starting at RETVAL, RETLEN bytes. */
775 1.1 christos FREE_BLOCKS (block_list);
776 1.1 christos #if defined HAVE_TSEARCH || defined _LIBC
777 1.1 christos if (foundp == NULL)
778 1.1 christos {
779 1.1 christos /* Create a new entry and add it to the search tree. */
780 1.1 christos size_t size;
781 1.1 christos struct known_translation_t *newp;
782 1.1 christos
783 1.1 christos size = offsetof (struct known_translation_t, msgid)
784 1.1 christos + msgid_len + domainname_len + 1;
785 1.1 christos # ifdef HAVE_PER_THREAD_LOCALE
786 1.1 christos size += strlen (localename) + 1;
787 1.1 christos # endif
788 1.1 christos newp = (struct known_translation_t *) malloc (size);
789 1.1 christos if (newp != NULL)
790 1.1 christos {
791 1.1 christos char *new_domainname;
792 1.1 christos # ifdef HAVE_PER_THREAD_LOCALE
793 1.1 christos char *new_localename;
794 1.1 christos # endif
795 1.1 christos
796 1.1 christos new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
797 1.1 christos memcpy (new_domainname, domainname, domainname_len + 1);
798 1.1 christos # ifdef HAVE_PER_THREAD_LOCALE
799 1.1 christos new_localename = new_domainname + domainname_len + 1;
800 1.1 christos strcpy (new_localename, localename);
801 1.1 christos # endif
802 1.1 christos newp->domainname = new_domainname;
803 1.1 christos newp->category = category;
804 1.1 christos # ifdef HAVE_PER_THREAD_LOCALE
805 1.1 christos newp->localename = new_localename;
806 1.1 christos # endif
807 1.1 christos # ifdef IN_LIBGLOCALE
808 1.1 christos newp->encoding = encoding;
809 1.1 christos # endif
810 1.1 christos newp->counter = _nl_msg_cat_cntr;
811 1.1 christos newp->domain = domain;
812 1.1 christos newp->translation = retval;
813 1.1 christos newp->translation_length = retlen;
814 1.1 christos
815 1.1 christos gl_rwlock_wrlock (tree_lock);
816 1.1 christos
817 1.1 christos /* Insert the entry in the search tree. */
818 1.1 christos foundp = (struct known_translation_t **)
819 1.1 christos tsearch (newp, &root, transcmp);
820 1.1 christos
821 1.1 christos gl_rwlock_unlock (tree_lock);
822 1.1 christos
823 1.1 christos if (foundp == NULL
824 1.1 christos || __builtin_expect (*foundp != newp, 0))
825 1.1 christos /* The insert failed. */
826 1.1 christos free (newp);
827 1.1 christos }
828 1.1 christos }
829 1.1 christos else
830 1.1 christos {
831 1.1 christos /* We can update the existing entry. */
832 1.1 christos (*foundp)->counter = _nl_msg_cat_cntr;
833 1.1 christos (*foundp)->domain = domain;
834 1.1 christos (*foundp)->translation = retval;
835 1.1 christos (*foundp)->translation_length = retlen;
836 1.1 christos }
837 1.1 christos #endif
838 1.1 christos __set_errno (saved_errno);
839 1.1 christos
840 1.1 christos /* Now deal with plural. */
841 1.1 christos if (plural)
842 1.1 christos retval = plural_lookup (domain, n, retval, retlen);
843 1.1 christos
844 1.1 christos gl_rwlock_unlock (_nl_state_lock);
845 1.1 christos return retval;
846 1.1 christos }
847 1.1 christos }
848 1.1 christos }
849 1.1 christos
850 1.1 christos return_untranslated:
851 1.1 christos /* Return the untranslated MSGID. */
852 1.1 christos FREE_BLOCKS (block_list);
853 1.1 christos gl_rwlock_unlock (_nl_state_lock);
854 1.1 christos #ifndef _LIBC
855 1.1 christos if (!ENABLE_SECURE)
856 1.1 christos {
857 1.1 christos extern void _nl_log_untranslated (const char *logfilename,
858 1.1 christos const char *domainname,
859 1.1 christos const char *msgid1, const char *msgid2,
860 1.1 christos int plural);
861 1.1 christos const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
862 1.1 christos
863 1.1 christos if (logfilename != NULL && logfilename[0] != '\0')
864 1.1 christos _nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
865 1.1 christos }
866 1.1 christos #endif
867 1.1 christos __set_errno (saved_errno);
868 1.1 christos return (plural == 0
869 1.1 christos ? (char *) msgid1
870 1.1 christos /* Use the Germanic plural rule. */
871 1.1 christos : n == 1 ? (char *) msgid1 : (char *) msgid2);
872 1.1 christos }
873 1.1 christos
874 1.1 christos
875 1.1 christos /* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
876 1.1 christos Return it if found. Return NULL if not found or in case of a conversion
877 1.1 christos failure (problem in the particular message catalog). Return (char *) -1
878 1.1 christos in case of a memory allocation failure during conversion (only if
879 1.1 christos ENCODING != NULL resp. CONVERT == true). */
880 1.1 christos char *
881 1.1 christos internal_function
882 1.1 christos #ifdef IN_LIBGLOCALE
883 1.1 christos _nl_find_msg (struct loaded_l10nfile *domain_file,
884 1.1 christos struct binding *domainbinding, const char *encoding,
885 1.1 christos const char *msgid,
886 1.1 christos size_t *lengthp)
887 1.1 christos #else
888 1.1 christos _nl_find_msg (struct loaded_l10nfile *domain_file,
889 1.1 christos struct binding *domainbinding,
890 1.1 christos const char *msgid, int convert,
891 1.1 christos size_t *lengthp)
892 1.1 christos #endif
893 1.1 christos {
894 1.1 christos struct loaded_domain *domain;
895 1.1 christos nls_uint32 nstrings;
896 1.1 christos size_t act;
897 1.1 christos char *result;
898 1.1 christos size_t resultlen;
899 1.1 christos
900 1.1 christos if (domain_file->decided <= 0)
901 1.1 christos _nl_load_domain (domain_file, domainbinding);
902 1.1 christos
903 1.1 christos if (domain_file->data == NULL)
904 1.1 christos return NULL;
905 1.1 christos
906 1.1 christos domain = (struct loaded_domain *) domain_file->data;
907 1.1 christos
908 1.1 christos nstrings = domain->nstrings;
909 1.1 christos
910 1.1 christos /* Locate the MSGID and its translation. */
911 1.1 christos if (domain->hash_tab != NULL)
912 1.1 christos {
913 1.1 christos /* Use the hashing table. */
914 1.1 christos nls_uint32 len = strlen (msgid);
915 1.1 christos nls_uint32 hash_val = __hash_string (msgid);
916 1.1 christos nls_uint32 idx = hash_val % domain->hash_size;
917 1.1 christos nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
918 1.1 christos
919 1.1 christos while (1)
920 1.1 christos {
921 1.1 christos nls_uint32 nstr =
922 1.1 christos W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
923 1.1 christos
924 1.1 christos if (nstr == 0)
925 1.1 christos /* Hash table entry is empty. */
926 1.1 christos return NULL;
927 1.1 christos
928 1.1 christos nstr--;
929 1.1 christos
930 1.1 christos /* Compare msgid with the original string at index nstr.
931 1.1 christos We compare the lengths with >=, not ==, because plural entries
932 1.1 christos are represented by strings with an embedded NUL. */
933 1.1 christos if (nstr < nstrings
934 1.1 christos ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
935 1.1 christos && (strcmp (msgid,
936 1.1 christos domain->data + W (domain->must_swap,
937 1.1 christos domain->orig_tab[nstr].offset))
938 1.1 christos == 0)
939 1.1 christos : domain->orig_sysdep_tab[nstr - nstrings].length > len
940 1.1 christos && (strcmp (msgid,
941 1.1 christos domain->orig_sysdep_tab[nstr - nstrings].pointer)
942 1.1 christos == 0))
943 1.1 christos {
944 1.1 christos act = nstr;
945 1.1 christos goto found;
946 1.1 christos }
947 1.1 christos
948 1.1 christos if (idx >= domain->hash_size - incr)
949 1.1 christos idx -= domain->hash_size - incr;
950 1.1 christos else
951 1.1 christos idx += incr;
952 1.1 christos }
953 1.1 christos /* NOTREACHED */
954 1.1 christos }
955 1.1 christos else
956 1.1 christos {
957 1.1 christos /* Try the default method: binary search in the sorted array of
958 1.1 christos messages. */
959 1.1 christos size_t top, bottom;
960 1.1 christos
961 1.1 christos bottom = 0;
962 1.1 christos top = nstrings;
963 1.1 christos while (bottom < top)
964 1.1 christos {
965 1.1 christos int cmp_val;
966 1.1 christos
967 1.1 christos act = (bottom + top) / 2;
968 1.1 christos cmp_val = strcmp (msgid, (domain->data
969 1.1 christos + W (domain->must_swap,
970 1.1 christos domain->orig_tab[act].offset)));
971 1.1 christos if (cmp_val < 0)
972 1.1 christos top = act;
973 1.1 christos else if (cmp_val > 0)
974 1.1 christos bottom = act + 1;
975 1.1 christos else
976 1.1 christos goto found;
977 1.1 christos }
978 1.1 christos /* No translation was found. */
979 1.1 christos return NULL;
980 1.1 christos }
981 1.1 christos
982 1.1 christos found:
983 1.1 christos /* The translation was found at index ACT. If we have to convert the
984 1.1 christos string to use a different character set, this is the time. */
985 1.1 christos if (act < nstrings)
986 1.1 christos {
987 1.1 christos result = (char *)
988 1.1 christos (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
989 1.1 christos resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
990 1.1 christos }
991 1.1 christos else
992 1.1 christos {
993 1.1 christos result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
994 1.1 christos resultlen = domain->trans_sysdep_tab[act - nstrings].length;
995 1.1 christos }
996 1.1 christos
997 1.1 christos #if defined _LIBC || HAVE_ICONV
998 1.1 christos # ifdef IN_LIBGLOCALE
999 1.1 christos if (encoding != NULL)
1000 1.1 christos # else
1001 1.1 christos if (convert)
1002 1.1 christos # endif
1003 1.1 christos {
1004 1.1 christos /* We are supposed to do a conversion. */
1005 1.1 christos # ifndef IN_LIBGLOCALE
1006 1.1 christos const char *encoding = get_output_charset (domainbinding);
1007 1.1 christos # endif
1008 1.1 christos
1009 1.1 christos /* Search whether a table with converted translations for this
1010 1.1 christos encoding has already been allocated. */
1011 1.1 christos size_t nconversions = domain->nconversions;
1012 1.1 christos struct converted_domain *convd = NULL;
1013 1.1 christos size_t i;
1014 1.1 christos
1015 1.1 christos for (i = nconversions; i > 0; )
1016 1.1 christos {
1017 1.1 christos i--;
1018 1.1 christos if (strcmp (domain->conversions[i].encoding, encoding) == 0)
1019 1.1 christos {
1020 1.1 christos convd = &domain->conversions[i];
1021 1.1 christos break;
1022 1.1 christos }
1023 1.1 christos }
1024 1.1 christos
1025 1.1 christos if (convd == NULL)
1026 1.1 christos {
1027 1.1 christos /* Allocate a table for the converted translations for this
1028 1.1 christos encoding. */
1029 1.1 christos struct converted_domain *new_conversions =
1030 1.1 christos (struct converted_domain *)
1031 1.1 christos (domain->conversions != NULL
1032 1.1 christos ? realloc (domain->conversions,
1033 1.1 christos (nconversions + 1) * sizeof (struct converted_domain))
1034 1.1 christos : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
1035 1.1 christos
1036 1.1 christos if (__builtin_expect (new_conversions == NULL, 0))
1037 1.1 christos /* Nothing we can do, no more memory. We cannot use the
1038 1.1 christos translation because it might be encoded incorrectly. */
1039 1.1 christos return (char *) -1;
1040 1.1 christos
1041 1.1 christos domain->conversions = new_conversions;
1042 1.1 christos
1043 1.1 christos /* Copy the 'encoding' string to permanent storage. */
1044 1.1 christos encoding = strdup (encoding);
1045 1.1 christos if (__builtin_expect (encoding == NULL, 0))
1046 1.1 christos /* Nothing we can do, no more memory. We cannot use the
1047 1.1 christos translation because it might be encoded incorrectly. */
1048 1.1 christos return (char *) -1;
1049 1.1 christos
1050 1.1 christos convd = &new_conversions[nconversions];
1051 1.1 christos convd->encoding = encoding;
1052 1.1 christos
1053 1.1 christos /* Find out about the character set the file is encoded with.
1054 1.1 christos This can be found (in textual form) in the entry "". If this
1055 1.1 christos entry does not exist or if this does not contain the 'charset='
1056 1.1 christos information, we will assume the charset matches the one the
1057 1.1 christos current locale and we don't have to perform any conversion. */
1058 1.1 christos # ifdef _LIBC
1059 1.1 christos convd->conv = (__gconv_t) -1;
1060 1.1 christos # else
1061 1.1 christos # if HAVE_ICONV
1062 1.1 christos convd->conv = (iconv_t) -1;
1063 1.1 christos # endif
1064 1.1 christos # endif
1065 1.1 christos {
1066 1.1 christos char *nullentry;
1067 1.1 christos size_t nullentrylen;
1068 1.1 christos
1069 1.1 christos /* Get the header entry. This is a recursion, but it doesn't
1070 1.1 christos reallocate domain->conversions because we pass
1071 1.1 christos encoding = NULL or convert = 0, respectively. */
1072 1.1 christos nullentry =
1073 1.1 christos # ifdef IN_LIBGLOCALE
1074 1.1 christos _nl_find_msg (domain_file, domainbinding, NULL, "",
1075 1.1 christos &nullentrylen);
1076 1.1 christos # else
1077 1.1 christos _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
1078 1.1 christos # endif
1079 1.1 christos
1080 1.1 christos if (nullentry != NULL)
1081 1.1 christos {
1082 1.1 christos const char *charsetstr;
1083 1.1 christos
1084 1.1 christos charsetstr = strstr (nullentry, "charset=");
1085 1.1 christos if (charsetstr != NULL)
1086 1.1 christos {
1087 1.1 christos size_t len;
1088 1.1 christos char *charset;
1089 1.1 christos const char *outcharset;
1090 1.1 christos
1091 1.1 christos charsetstr += strlen ("charset=");
1092 1.1 christos len = strcspn (charsetstr, " \t\n");
1093 1.1 christos
1094 1.1 christos charset = (char *) alloca (len + 1);
1095 1.1 christos # if defined _LIBC || HAVE_MEMPCPY
1096 1.1 christos *((char *) mempcpy (charset, charsetstr, len)) = '\0';
1097 1.1 christos # else
1098 1.1 christos memcpy (charset, charsetstr, len);
1099 1.1 christos charset[len] = '\0';
1100 1.1 christos # endif
1101 1.1 christos
1102 1.1 christos outcharset = encoding;
1103 1.1 christos
1104 1.1 christos # ifdef _LIBC
1105 1.1 christos /* We always want to use transliteration. */
1106 1.1 christos outcharset = norm_add_slashes (outcharset, "TRANSLIT");
1107 1.1 christos charset = norm_add_slashes (charset, "");
1108 1.1 christos int r = __gconv_open (outcharset, charset, &convd->conv,
1109 1.1 christos GCONV_AVOID_NOCONV);
1110 1.1 christos if (__builtin_expect (r != __GCONV_OK, 0))
1111 1.1 christos {
1112 1.1 christos /* If the output encoding is the same there is
1113 1.1 christos nothing to do. Otherwise do not use the
1114 1.1 christos translation at all. */
1115 1.1 christos if (__builtin_expect (r != __GCONV_NOCONV, 1))
1116 1.1 christos return NULL;
1117 1.1 christos
1118 1.1 christos convd->conv = (__gconv_t) -1;
1119 1.1 christos }
1120 1.1 christos # else
1121 1.1 christos # if HAVE_ICONV
1122 1.1 christos /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
1123 1.1 christos we want to use transliteration. */
1124 1.1 christos # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
1125 1.1 christos || _LIBICONV_VERSION >= 0x0105
1126 1.1 christos if (strchr (outcharset, '/') == NULL)
1127 1.1 christos {
1128 1.1 christos char *tmp;
1129 1.1 christos
1130 1.1 christos len = strlen (outcharset);
1131 1.1 christos tmp = (char *) alloca (len + 10 + 1);
1132 1.1 christos memcpy (tmp, outcharset, len);
1133 1.1 christos memcpy (tmp + len, "//TRANSLIT", 10 + 1);
1134 1.1 christos outcharset = tmp;
1135 1.1 christos
1136 1.1 christos convd->conv = iconv_open (outcharset, charset);
1137 1.1 christos
1138 1.1 christos freea (outcharset);
1139 1.1 christos }
1140 1.1 christos else
1141 1.1 christos # endif
1142 1.1 christos convd->conv = iconv_open (outcharset, charset);
1143 1.1 christos # endif
1144 1.1 christos # endif
1145 1.1 christos
1146 1.1 christos freea (charset);
1147 1.1 christos }
1148 1.1 christos }
1149 1.1 christos }
1150 1.1 christos convd->conv_tab = NULL;
1151 1.1 christos /* Here domain->conversions is still == new_conversions. */
1152 1.1 christos domain->nconversions++;
1153 1.1 christos }
1154 1.1 christos
1155 1.1 christos if (
1156 1.1 christos # ifdef _LIBC
1157 1.1 christos convd->conv != (__gconv_t) -1
1158 1.1 christos # else
1159 1.1 christos # if HAVE_ICONV
1160 1.1 christos convd->conv != (iconv_t) -1
1161 1.1 christos # endif
1162 1.1 christos # endif
1163 1.1 christos )
1164 1.1 christos {
1165 1.1 christos /* We are supposed to do a conversion. First allocate an
1166 1.1 christos appropriate table with the same structure as the table
1167 1.1 christos of translations in the file, where we can put the pointers
1168 1.1 christos to the converted strings in.
1169 1.1 christos There is a slight complication with plural entries. They
1170 1.1 christos are represented by consecutive NUL terminated strings. We
1171 1.1 christos handle this case by converting RESULTLEN bytes, including
1172 1.1 christos NULs. */
1173 1.1 christos
1174 1.1 christos if (convd->conv_tab == NULL
1175 1.1 christos && ((convd->conv_tab =
1176 1.1 christos (char **) calloc (nstrings + domain->n_sysdep_strings,
1177 1.1 christos sizeof (char *)))
1178 1.1 christos == NULL))
1179 1.1 christos /* Mark that we didn't succeed allocating a table. */
1180 1.1 christos convd->conv_tab = (char **) -1;
1181 1.1 christos
1182 1.1 christos if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
1183 1.1 christos /* Nothing we can do, no more memory. We cannot use the
1184 1.1 christos translation because it might be encoded incorrectly. */
1185 1.1 christos return (char *) -1;
1186 1.1 christos
1187 1.1 christos if (convd->conv_tab[act] == NULL)
1188 1.1 christos {
1189 1.1 christos /* We haven't used this string so far, so it is not
1190 1.1 christos translated yet. Do this now. */
1191 1.1 christos /* We use a bit more efficient memory handling.
1192 1.1 christos We allocate always larger blocks which get used over
1193 1.1 christos time. This is faster than many small allocations. */
1194 1.1 christos __libc_lock_define_initialized (static, lock)
1195 1.1 christos # define INITIAL_BLOCK_SIZE 4080
1196 1.1 christos static unsigned char *freemem;
1197 1.1 christos static size_t freemem_size;
1198 1.1 christos
1199 1.1 christos const unsigned char *inbuf;
1200 1.1 christos unsigned char *outbuf;
1201 1.1 christos int malloc_count;
1202 1.1 christos # ifndef _LIBC
1203 1.1 christos transmem_block_t *transmem_list = NULL;
1204 1.1 christos # endif
1205 1.1 christos
1206 1.1 christos __libc_lock_lock (lock);
1207 1.1 christos
1208 1.1 christos inbuf = (const unsigned char *) result;
1209 1.1 christos outbuf = freemem + sizeof (size_t);
1210 1.1 christos
1211 1.1 christos malloc_count = 0;
1212 1.1 christos while (1)
1213 1.1 christos {
1214 1.1 christos transmem_block_t *newmem;
1215 1.1 christos # ifdef _LIBC
1216 1.1 christos size_t non_reversible;
1217 1.1 christos int res;
1218 1.1 christos
1219 1.1 christos if (freemem_size < sizeof (size_t))
1220 1.1 christos goto resize_freemem;
1221 1.1 christos
1222 1.1 christos res = __gconv (convd->conv,
1223 1.1 christos &inbuf, inbuf + resultlen,
1224 1.1 christos &outbuf,
1225 1.1 christos outbuf + freemem_size - sizeof (size_t),
1226 1.1 christos &non_reversible);
1227 1.1 christos
1228 1.1 christos if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
1229 1.1 christos break;
1230 1.1 christos
1231 1.1 christos if (res != __GCONV_FULL_OUTPUT)
1232 1.1 christos {
1233 1.1 christos /* We should not use the translation at all, it
1234 1.1 christos is incorrectly encoded. */
1235 1.1 christos __libc_lock_unlock (lock);
1236 1.1 christos return NULL;
1237 1.1 christos }
1238 1.1 christos
1239 1.1 christos inbuf = (const unsigned char *) result;
1240 1.1 christos # else
1241 1.1 christos # if HAVE_ICONV
1242 1.1 christos const char *inptr = (const char *) inbuf;
1243 1.1 christos size_t inleft = resultlen;
1244 1.1 christos char *outptr = (char *) outbuf;
1245 1.1 christos size_t outleft;
1246 1.1 christos
1247 1.1 christos if (freemem_size < sizeof (size_t))
1248 1.1 christos goto resize_freemem;
1249 1.1 christos
1250 1.1 christos outleft = freemem_size - sizeof (size_t);
1251 1.1 christos if (iconv (convd->conv,
1252 1.1 christos (ICONV_CONST char **) &inptr, &inleft,
1253 1.1 christos &outptr, &outleft)
1254 1.1 christos != (size_t) (-1))
1255 1.1 christos {
1256 1.1 christos outbuf = (unsigned char *) outptr;
1257 1.1 christos break;
1258 1.1 christos }
1259 1.1 christos if (errno != E2BIG)
1260 1.1 christos {
1261 1.1 christos __libc_lock_unlock (lock);
1262 1.1 christos return NULL;
1263 1.1 christos }
1264 1.1 christos # endif
1265 1.1 christos # endif
1266 1.1 christos
1267 1.1 christos resize_freemem:
1268 1.1 christos /* We must allocate a new buffer or resize the old one. */
1269 1.1 christos if (malloc_count > 0)
1270 1.1 christos {
1271 1.1 christos ++malloc_count;
1272 1.1 christos freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
1273 1.1 christos newmem = (transmem_block_t *) realloc (transmem_list,
1274 1.1 christos freemem_size);
1275 1.1 christos # ifdef _LIBC
1276 1.1 christos if (newmem != NULL)
1277 1.1 christos transmem_list = transmem_list->next;
1278 1.1 christos else
1279 1.1 christos {
1280 1.1 christos struct transmem_list *old = transmem_list;
1281 1.1 christos
1282 1.1 christos transmem_list = transmem_list->next;
1283 1.1 christos free (old);
1284 1.1 christos }
1285 1.1 christos # endif
1286 1.1 christos }
1287 1.1 christos else
1288 1.1 christos {
1289 1.1 christos malloc_count = 1;
1290 1.1 christos freemem_size = INITIAL_BLOCK_SIZE;
1291 1.1 christos newmem = (transmem_block_t *) malloc (freemem_size);
1292 1.1 christos }
1293 1.1 christos if (__builtin_expect (newmem == NULL, 0))
1294 1.1 christos {
1295 1.1 christos freemem = NULL;
1296 1.1 christos freemem_size = 0;
1297 1.1 christos __libc_lock_unlock (lock);
1298 1.1 christos return (char *) -1;
1299 1.1 christos }
1300 1.1 christos
1301 1.1 christos # ifdef _LIBC
1302 1.1 christos /* Add the block to the list of blocks we have to free
1303 1.1 christos at some point. */
1304 1.1 christos newmem->next = transmem_list;
1305 1.1 christos transmem_list = newmem;
1306 1.1 christos
1307 1.1 christos freemem = (unsigned char *) newmem->data;
1308 1.1 christos freemem_size -= offsetof (struct transmem_list, data);
1309 1.1 christos # else
1310 1.1 christos transmem_list = newmem;
1311 1.1 christos freemem = newmem;
1312 1.1 christos # endif
1313 1.1 christos
1314 1.1 christos outbuf = freemem + sizeof (size_t);
1315 1.1 christos }
1316 1.1 christos
1317 1.1 christos /* We have now in our buffer a converted string. Put this
1318 1.1 christos into the table of conversions. */
1319 1.1 christos *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1320 1.1 christos convd->conv_tab[act] = (char *) freemem;
1321 1.1 christos /* Shrink freemem, but keep it aligned. */
1322 1.1 christos freemem_size -= outbuf - freemem;
1323 1.1 christos freemem = outbuf;
1324 1.1 christos freemem += freemem_size & (alignof (size_t) - 1);
1325 1.1 christos freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1326 1.1 christos
1327 1.1 christos __libc_lock_unlock (lock);
1328 1.1 christos }
1329 1.1 christos
1330 1.1 christos /* Now convd->conv_tab[act] contains the translation of all
1331 1.1 christos the plural variants. */
1332 1.1 christos result = convd->conv_tab[act] + sizeof (size_t);
1333 1.1 christos resultlen = *(size_t *) convd->conv_tab[act];
1334 1.1 christos }
1335 1.1 christos }
1336 1.1 christos
1337 1.1 christos /* The result string is converted. */
1338 1.1 christos
1339 1.1 christos #endif /* _LIBC || HAVE_ICONV */
1340 1.1 christos
1341 1.1 christos *lengthp = resultlen;
1342 1.1 christos return result;
1343 1.1 christos }
1344 1.1 christos
1345 1.1 christos
1346 1.1 christos /* Look up a plural variant. */
1347 1.1 christos static char *
1348 1.1 christos internal_function
1349 1.1 christos plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
1350 1.1 christos const char *translation, size_t translation_len)
1351 1.1 christos {
1352 1.1 christos struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1353 1.1 christos unsigned long int index;
1354 1.1 christos const char *p;
1355 1.1 christos
1356 1.1 christos index = plural_eval (domaindata->plural, n);
1357 1.1 christos if (index >= domaindata->nplurals)
1358 1.1 christos /* This should never happen. It means the plural expression and the
1359 1.1 christos given maximum value do not match. */
1360 1.1 christos index = 0;
1361 1.1 christos
1362 1.1 christos /* Skip INDEX strings at TRANSLATION. */
1363 1.1 christos p = translation;
1364 1.1 christos while (index-- > 0)
1365 1.1 christos {
1366 1.1 christos #ifdef _LIBC
1367 1.1 christos p = __rawmemchr (p, '\0');
1368 1.1 christos #else
1369 1.1 christos p = strchr (p, '\0');
1370 1.1 christos #endif
1371 1.1 christos /* And skip over the NUL byte. */
1372 1.1 christos p++;
1373 1.1 christos
1374 1.1 christos if (p >= translation + translation_len)
1375 1.1 christos /* This should never happen. It means the plural expression
1376 1.1 christos evaluated to a value larger than the number of variants
1377 1.1 christos available for MSGID1. */
1378 1.1 christos return (char *) translation;
1379 1.1 christos }
1380 1.1 christos return (char *) p;
1381 1.1 christos }
1382 1.1 christos
1383 1.1 christos #ifndef _LIBC
1384 1.1 christos /* Return string representation of locale CATEGORY. */
1385 1.1 christos static const char *
1386 1.1 christos internal_function
1387 1.1 christos category_to_name (int category)
1388 1.1 christos {
1389 1.1 christos const char *retval;
1390 1.1 christos
1391 1.1 christos switch (category)
1392 1.1 christos {
1393 1.1 christos #ifdef LC_COLLATE
1394 1.1 christos case LC_COLLATE:
1395 1.1 christos retval = "LC_COLLATE";
1396 1.1 christos break;
1397 1.1 christos #endif
1398 1.1 christos #ifdef LC_CTYPE
1399 1.1 christos case LC_CTYPE:
1400 1.1 christos retval = "LC_CTYPE";
1401 1.1 christos break;
1402 1.1 christos #endif
1403 1.1 christos #ifdef LC_MONETARY
1404 1.1 christos case LC_MONETARY:
1405 1.1 christos retval = "LC_MONETARY";
1406 1.1 christos break;
1407 1.1 christos #endif
1408 1.1 christos #ifdef LC_NUMERIC
1409 1.1 christos case LC_NUMERIC:
1410 1.1 christos retval = "LC_NUMERIC";
1411 1.1 christos break;
1412 1.1 christos #endif
1413 1.1 christos #ifdef LC_TIME
1414 1.1 christos case LC_TIME:
1415 1.1 christos retval = "LC_TIME";
1416 1.1 christos break;
1417 1.1 christos #endif
1418 1.1 christos #ifdef LC_MESSAGES
1419 1.1 christos case LC_MESSAGES:
1420 1.1 christos retval = "LC_MESSAGES";
1421 1.1 christos break;
1422 1.1 christos #endif
1423 1.1 christos #ifdef LC_RESPONSE
1424 1.1 christos case LC_RESPONSE:
1425 1.1 christos retval = "LC_RESPONSE";
1426 1.1 christos break;
1427 1.1 christos #endif
1428 1.1 christos #ifdef LC_ALL
1429 1.1 christos case LC_ALL:
1430 1.1 christos /* This might not make sense but is perhaps better than any other
1431 1.1 christos value. */
1432 1.1 christos retval = "LC_ALL";
1433 1.1 christos break;
1434 1.1 christos #endif
1435 1.1 christos default:
1436 1.1 christos /* If you have a better idea for a default value let me know. */
1437 1.1 christos retval = "LC_XXX";
1438 1.1 christos }
1439 1.1 christos
1440 1.1 christos return retval;
1441 1.1 christos }
1442 1.1 christos #endif
1443 1.1 christos
1444 1.1 christos /* Guess value of current locale from value of the environment variables
1445 1.1 christos or system-dependent defaults. */
1446 1.1 christos static const char *
1447 1.1 christos internal_function
1448 1.1 christos #ifdef IN_LIBGLOCALE
1449 1.1 christos guess_category_value (int category, const char *categoryname,
1450 1.1 christos const char *locale)
1451 1.1 christos
1452 1.1 christos #else
1453 1.1 christos guess_category_value (int category, const char *categoryname)
1454 1.1 christos #endif
1455 1.1 christos {
1456 1.1 christos const char *language;
1457 1.1 christos #ifndef IN_LIBGLOCALE
1458 1.1 christos const char *locale;
1459 1.1 christos # ifndef _LIBC
1460 1.1 christos const char *language_default;
1461 1.1 christos int locale_defaulted;
1462 1.1 christos # endif
1463 1.1 christos #endif
1464 1.1 christos
1465 1.1 christos /* We use the settings in the following order:
1466 1.1 christos 1. The value of the environment variable 'LANGUAGE'. This is a GNU
1467 1.1 christos extension. Its value can be a colon-separated list of locale names.
1468 1.1 christos 2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
1469 1.1 christos More precisely, the first among these that is set to a non-empty value.
1470 1.1 christos This is how POSIX specifies it. The value is a single locale name.
1471 1.1 christos 3. A system-dependent preference list of languages. Its value can be a
1472 1.1 christos colon-separated list of locale names.
1473 1.1 christos 4. A system-dependent default locale name.
1474 1.1 christos This way:
1475 1.1 christos - System-dependent settings can be overridden by environment variables.
1476 1.1 christos - If the system provides both a list of languages and a default locale,
1477 1.1 christos the former is used. */
1478 1.1 christos
1479 1.1 christos #ifndef IN_LIBGLOCALE
1480 1.1 christos /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
1481 1.1 christos `LC_xxx', and `LANG'. On some systems this can be done by the
1482 1.1 christos `setlocale' function itself. */
1483 1.1 christos # ifdef _LIBC
1484 1.1 christos locale = __current_locale_name (category);
1485 1.1 christos # else
1486 1.1 christos # if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
1487 1.1 christos /* The __names field is not public glibc API and must therefore not be used
1488 1.1 christos in code that is installed in public locations. */
1489 1.1 christos locale_t thread_locale = uselocale (NULL);
1490 1.1 christos if (thread_locale != LC_GLOBAL_LOCALE)
1491 1.1 christos {
1492 1.1 christos locale = thread_locale->__names[category];
1493 1.1 christos locale_defaulted = 0;
1494 1.1 christos }
1495 1.1 christos else
1496 1.1 christos # endif
1497 1.1 christos {
1498 1.1 christos locale = _nl_locale_name_posix (category, categoryname);
1499 1.1 christos locale_defaulted = 0;
1500 1.1 christos if (locale == NULL)
1501 1.1 christos {
1502 1.1 christos locale = _nl_locale_name_default ();
1503 1.1 christos locale_defaulted = 1;
1504 1.1 christos }
1505 1.1 christos }
1506 1.1 christos # endif
1507 1.1 christos #endif
1508 1.1 christos
1509 1.1 christos /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
1510 1.1 christos to "C" because
1511 1.1 christos 1. "C" locale usually uses the ASCII encoding, and most international
1512 1.1 christos messages use non-ASCII characters. These characters get displayed
1513 1.1 christos as question marks (if using glibc's iconv()) or as invalid 8-bit
1514 1.1 christos characters (because other iconv()s refuse to convert most non-ASCII
1515 1.1 christos characters to ASCII). In any case, the output is ugly.
1516 1.1 christos 2. The precise output of some programs in the "C" locale is specified
1517 1.1 christos by POSIX and should not depend on environment variables like
1518 1.1 christos "LANGUAGE" or system-dependent information. We allow such programs
1519 1.1 christos to use gettext(). */
1520 1.1 christos if (strcmp (locale, "C") == 0)
1521 1.1 christos return locale;
1522 1.1 christos
1523 1.1 christos /* The highest priority value is the value of the 'LANGUAGE' environment
1524 1.1 christos variable. */
1525 1.1 christos language = getenv ("LANGUAGE");
1526 1.1 christos if (language != NULL && language[0] != '\0')
1527 1.1 christos return language;
1528 1.1 christos #if !defined IN_LIBGLOCALE && !defined _LIBC
1529 1.1 christos /* The next priority value is the locale name, if not defaulted. */
1530 1.1 christos if (locale_defaulted)
1531 1.1 christos {
1532 1.1 christos /* The next priority value is the default language preferences list. */
1533 1.1 christos language_default = _nl_language_preferences_default ();
1534 1.1 christos if (language_default != NULL)
1535 1.1 christos return language_default;
1536 1.1 christos }
1537 1.1 christos /* The least priority value is the locale name, if defaulted. */
1538 1.1 christos #endif
1539 1.1 christos return locale;
1540 1.1 christos }
1541 1.1 christos
1542 1.1 christos #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
1543 1.1 christos /* Returns the output charset. */
1544 1.1 christos static const char *
1545 1.1 christos internal_function
1546 1.1 christos get_output_charset (struct binding *domainbinding)
1547 1.1 christos {
1548 1.1 christos /* The output charset should normally be determined by the locale. But
1549 1.1 christos sometimes the locale is not used or not correctly set up, so we provide
1550 1.1 christos a possibility for the user to override this: the OUTPUT_CHARSET
1551 1.1 christos environment variable. Moreover, the value specified through
1552 1.1 christos bind_textdomain_codeset overrides both. */
1553 1.1 christos if (domainbinding != NULL && domainbinding->codeset != NULL)
1554 1.1 christos return domainbinding->codeset;
1555 1.1 christos else
1556 1.1 christos {
1557 1.1 christos /* For speed reasons, we look at the value of OUTPUT_CHARSET only
1558 1.1 christos once. This is a user variable that is not supposed to change
1559 1.1 christos during a program run. */
1560 1.1 christos static char *output_charset_cache;
1561 1.1 christos static int output_charset_cached;
1562 1.1 christos
1563 1.1 christos if (!output_charset_cached)
1564 1.1 christos {
1565 1.1 christos const char *value = getenv ("OUTPUT_CHARSET");
1566 1.1 christos
1567 1.1 christos if (value != NULL && value[0] != '\0')
1568 1.1 christos {
1569 1.1 christos size_t len = strlen (value) + 1;
1570 1.1 christos char *value_copy = (char *) malloc (len);
1571 1.1 christos
1572 1.1 christos if (value_copy != NULL)
1573 1.1 christos memcpy (value_copy, value, len);
1574 1.1 christos output_charset_cache = value_copy;
1575 1.1 christos }
1576 1.1 christos output_charset_cached = 1;
1577 1.1 christos }
1578 1.1 christos
1579 1.1 christos if (output_charset_cache != NULL)
1580 1.1 christos return output_charset_cache;
1581 1.1 christos else
1582 1.1 christos {
1583 1.1 christos # ifdef _LIBC
1584 1.1 christos return _NL_CURRENT (LC_CTYPE, CODESET);
1585 1.1 christos # else
1586 1.1 christos # if HAVE_ICONV
1587 1.1 christos extern const char *locale_charset (void);
1588 1.1 christos return locale_charset ();
1589 1.1 christos # endif
1590 1.1 christos # endif
1591 1.1 christos }
1592 1.1 christos }
1593 1.1 christos }
1594 1.1 christos #endif
1595 1.1 christos
1596 1.1 christos /* @@ begin of epilog @@ */
1597 1.1 christos
1598 1.1 christos /* We don't want libintl.a to depend on any other library. So we
1599 1.1 christos avoid the non-standard function stpcpy. In GNU C Library this
1600 1.1 christos function is available, though. Also allow the symbol HAVE_STPCPY
1601 1.1 christos to be defined. */
1602 1.1 christos #if !_LIBC && !HAVE_STPCPY
1603 1.1 christos static char *
1604 1.1 christos stpcpy (char *dest, const char *src)
1605 1.1 christos {
1606 1.1 christos while ((*dest++ = *src++) != '\0')
1607 1.1 christos /* Do nothing. */ ;
1608 1.1 christos return dest - 1;
1609 1.1 christos }
1610 1.1 christos #endif
1611 1.1 christos
1612 1.1 christos #if !_LIBC && !HAVE_MEMPCPY
1613 1.1 christos static void *
1614 1.1 christos mempcpy (void *dest, const void *src, size_t n)
1615 1.1 christos {
1616 1.1 christos return (void *) ((char *) memcpy (dest, src, n) + n);
1617 1.1 christos }
1618 1.1 christos #endif
1619 1.1 christos
1620 1.1 christos
1621 1.1 christos #ifdef _LIBC
1622 1.1 christos /* If we want to free all resources we have to do some work at
1623 1.1 christos program's end. */
1624 1.1 christos libc_freeres_fn (free_mem)
1625 1.1 christos {
1626 1.1 christos void *old;
1627 1.1 christos
1628 1.1 christos while (_nl_domain_bindings != NULL)
1629 1.1 christos {
1630 1.1 christos struct binding *oldp = _nl_domain_bindings;
1631 1.1 christos _nl_domain_bindings = _nl_domain_bindings->next;
1632 1.1 christos if (oldp->dirname != _nl_default_dirname)
1633 1.1 christos /* Yes, this is a pointer comparison. */
1634 1.1 christos free (oldp->dirname);
1635 1.1 christos free (oldp->codeset);
1636 1.1 christos free (oldp);
1637 1.1 christos }
1638 1.1 christos
1639 1.1 christos if (_nl_current_default_domain != _nl_default_default_domain)
1640 1.1 christos /* Yes, again a pointer comparison. */
1641 1.1 christos free ((char *) _nl_current_default_domain);
1642 1.1 christos
1643 1.1 christos /* Remove the search tree with the known translations. */
1644 1.1 christos __tdestroy (root, free);
1645 1.1 christos root = NULL;
1646 1.1 christos
1647 1.1 christos while (transmem_list != NULL)
1648 1.1 christos {
1649 1.1 christos old = transmem_list;
1650 1.1 christos transmem_list = transmem_list->next;
1651 1.1 christos free (old);
1652 1.1 christos }
1653 1.1 christos }
1654 1.1 christos #endif
1655