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