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