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