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