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