source: vendor/bash/3.1-p17/lib/intl/dcigettext.c

Last change on this file was 3231, checked in by bird, 18 years ago

eol style.

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