1
/* Implementation of the internal dcigettext function.
2
Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
4
This program is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Library General Public License as published
6
by the Free Software Foundation; either version 2, or (at your option)
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public
15
License along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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. */
23
# define _GNU_SOURCE 1
30
#include <sys/types.h>
33
# define alloca __builtin_alloca
34
# define HAVE_ALLOCA 1
38
# define alloca _alloca
40
# if defined HAVE_ALLOCA_H || defined _LIBC
59
# define __set_errno(val) errno = (val)
66
#if defined HAVE_UNISTD_H || defined _LIBC
73
/* Guess whether integer division by zero raises signal SIGFPE.
74
Set to 1 only if you know for sure. In case of doubt, set to 0. */
75
# if defined __alpha__ || defined __arm__ || defined __i386__ \
76
|| defined __m68k__ || defined __s390__
77
# define INTDIV0_RAISES_SIGFPE 1
79
# define INTDIV0_RAISES_SIGFPE 0
82
#if !INTDIV0_RAISES_SIGFPE
86
#if defined HAVE_SYS_PARAM_H || defined _LIBC
87
# include <sys/param.h>
91
#include "plural-exp.h"
95
# include "libgnuintl.h"
97
#include "hash-string.h"
99
/* Thread safetyness. */
101
# include <bits/libc-lock.h>
103
/* Provide dummy implementation if this is outside glibc. */
104
# define __libc_lock_define_initialized(CLASS, NAME)
105
# define __libc_lock_lock(NAME)
106
# define __libc_lock_unlock(NAME)
107
# define __libc_rwlock_define_initialized(CLASS, NAME)
108
# define __libc_rwlock_rdlock(NAME)
109
# define __libc_rwlock_unlock(NAME)
112
/* Alignment of types. */
113
#if defined __GNUC__ && __GNUC__ >= 2
114
# define alignof(TYPE) __alignof__ (TYPE)
116
# define alignof(TYPE) \
117
((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
120
/* The internal variables in the standalone libintl.a must have different
121
names than the internal variables in GNU libc, otherwise programs
122
using libintl.a cannot be linked statically. */
124
# define _nl_default_default_domain libintl_nl_default_default_domain
125
# define _nl_current_default_domain libintl_nl_current_default_domain
126
# define _nl_default_dirname libintl_nl_default_dirname
127
# define _nl_domain_bindings libintl_nl_domain_bindings
130
/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
132
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
135
/* @@ end of prolog @@ */
138
/* Rename the non ANSI C functions. This is required by the standard
139
because some ANSI C functions will require linking with this object
140
file and the name space must not be polluted. */
141
# define getcwd __getcwd
143
# define stpcpy __stpcpy
145
# define tfind __tfind
147
# if !defined HAVE_GETCWD
149
# define getcwd(buf, max) getwd (buf)
152
# define getcwd(buf, max) (getcwd) (buf, max, 0)
158
static char *stpcpy (char *dest, const char *src);
160
# ifndef HAVE_MEMPCPY
161
static void *mempcpy (void *dest, const void *src, size_t n);
165
/* Amount to increase buffer size by in each try. */
168
/* The following is from pathmax.h. */
169
/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
170
PATH_MAX but might cause redefinition warnings when sys/param.h is
171
later included (as on MORE/BSD 4.3). */
172
#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
176
#ifndef _POSIX_PATH_MAX
177
# define _POSIX_PATH_MAX 255
180
#if !defined PATH_MAX && defined _PC_PATH_MAX
181
# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
184
/* Don't include sys/param.h if it already has been. */
185
#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
186
# include <sys/param.h>
189
#if !defined PATH_MAX && defined MAXPATHLEN
190
# define PATH_MAX MAXPATHLEN
194
# define PATH_MAX _POSIX_PATH_MAX
198
ISSLASH(C) tests whether C is a directory separator character.
199
IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
200
it may be concatenated to a directory pathname.
201
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
203
#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
204
/* Win32, OS/2, DOS */
205
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
206
# define HAS_DEVICE(P) \
207
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
209
# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
210
# define IS_PATH_WITH_DIR(P) \
211
(strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
214
# define ISSLASH(C) ((C) == '/')
215
# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
216
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
219
/* This is the type used for the search tree where known translations
221
struct known_translation_t
223
/* Domain in which to search. */
229
/* State of the catalog counter at the point the string was found. */
232
/* Catalog where the string was found. */
233
struct loaded_l10nfile *domain;
235
/* And finally the translation. */
236
const char *translation;
237
size_t translation_length;
239
/* Pointer to the string in question. */
243
/* Root of the search tree with known translations. We can use this
244
only if the system provides the `tsearch' function family. */
245
#if defined HAVE_TSEARCH || defined _LIBC
251
# define tsearch __tsearch
254
/* Function to compare two entries in the table of known translations. */
256
transcmp (const void *p1, const void *p2)
258
const struct known_translation_t *s1;
259
const struct known_translation_t *s2;
262
s1 = (const struct known_translation_t *) p1;
263
s2 = (const struct known_translation_t *) p2;
265
result = strcmp (s1->msgid, s2->msgid);
268
result = strcmp (s1->domainname, s2->domainname);
270
/* We compare the category last (though this is the cheapest
271
operation) since it is hopefully always the same (namely
273
result = s1->category - s2->category;
281
# define INTVARDEF(name)
284
# define INTUSE(name) name
287
/* Name of the default domain used for gettext(3) prior any call to
288
textdomain(3). The default value for this is "messages". */
289
const char _nl_default_default_domain[] attribute_hidden = "messages";
291
/* Value used as the default domain for gettext(3). */
292
const char *_nl_current_default_domain attribute_hidden
293
= _nl_default_default_domain;
295
/* Contains the default location of the message catalogs. */
297
extern const char _nl_default_dirname[];
299
const char _nl_default_dirname[] = LOCALEDIR;
300
INTVARDEF (_nl_default_dirname)
303
/* List with bindings of specific domains created by bindtextdomain()
305
struct binding *_nl_domain_bindings;
307
/* Prototypes for local functions. */
308
static char *plural_lookup (struct loaded_l10nfile *domain,
310
const char *translation, size_t translation_len)
312
static const char *guess_category_value (int category,
313
const char *categoryname)
316
# include "../locale/localeinfo.h"
317
# define category_to_name(category) _nl_category_names[category]
319
static const char *category_to_name (int category) internal_function;
323
/* For those loosing systems which don't have `alloca' we have to add
324
some additional code emulating it. */
326
/* Nothing has to be done. */
327
# define freea(p) /* nothing */
328
# define ADD_BLOCK(list, address) /* nothing */
329
# define FREE_BLOCKS(list) /* nothing */
334
struct block_list *next;
336
# define ADD_BLOCK(list, addr) \
338
struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
339
/* If we cannot get a free block we cannot add the new element to \
341
if (newp != NULL) { \
342
newp->address = (addr); \
343
newp->next = (list); \
347
# define FREE_BLOCKS(list) \
349
while (list != NULL) { \
350
struct block_list *old = list; \
352
free (old->address); \
357
# define alloca(size) (malloc (size))
358
# define freea(p) free (p)
359
#endif /* have alloca */
363
/* List of blocks allocated for translations. */
364
typedef struct transmem_list
366
struct transmem_list *next;
369
static struct transmem_list *transmem_list;
371
typedef unsigned char transmem_block_t;
375
/* Names for the libintl functions are a problem. They must not clash
376
with existing names and they should follow ANSI C. But this source
377
code is also used in GNU C Library where the names have a __
378
prefix. So we have to make a difference here. */
380
# define DCIGETTEXT __dcigettext
382
# define DCIGETTEXT libintl_dcigettext
385
/* Lock variable to protect the global data in the gettext implementation. */
387
__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
390
/* Checking whether the binaries runs SUID must be done and glibc provides
391
easier methods therefore we make a difference here. */
393
# define ENABLE_SECURE __libc_enable_secure
394
# define DETERMINE_SECURE
402
# ifndef HAVE_GETEUID
403
# define geteuid() getuid()
405
# ifndef HAVE_GETEGID
406
# define getegid() getgid()
408
static int enable_secure;
409
# define ENABLE_SECURE (enable_secure == 1)
410
# define DETERMINE_SECURE \
411
if (enable_secure == 0) \
413
if (getuid () != geteuid () || getgid () != getegid ()) \
416
enable_secure = -1; \
420
/* Get the function to evaluate the plural expression. */
421
#include "eval-plural.h"
423
/* Look up MSGID in the DOMAINNAME message catalog for the current
424
CATEGORY locale and, if PLURAL is nonzero, search over string
425
depending on the plural form determined by N. */
427
DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
428
int plural, unsigned long int n, int category)
431
struct block_list *block_list = NULL;
433
struct loaded_l10nfile *domain;
434
struct binding *binding;
435
const char *categoryname;
436
const char *categoryvalue;
437
char *dirname, *xdomainname;
442
#if defined HAVE_TSEARCH || defined _LIBC
443
struct known_translation_t *search;
444
struct known_translation_t **foundp = NULL;
447
size_t domainname_len;
449
/* If no real MSGID is given return NULL. */
454
if (category < 0 || category >= __LC_LAST || category == LC_ALL)
458
/* Use the Germanic plural rule. */
459
: n == 1 ? (char *) msgid1 : (char *) msgid2);
462
__libc_rwlock_rdlock (_nl_state_lock);
464
/* If DOMAINNAME is NULL, we are interested in the default domain. If
465
CATEGORY is not LC_MESSAGES this might not make much sense but the
466
definition left this undefined. */
467
if (domainname == NULL)
468
domainname = _nl_current_default_domain;
470
/* OS/2 specific: backward compatibility with older libintl versions */
471
#ifdef LC_MESSAGES_COMPAT
472
if (category == LC_MESSAGES_COMPAT)
473
category = LC_MESSAGES;
476
#if defined HAVE_TSEARCH || defined _LIBC
477
msgid_len = strlen (msgid1) + 1;
479
/* Try to find the translation among those which we found at
481
search = (struct known_translation_t *)
482
alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
483
memcpy (search->msgid, msgid1, msgid_len);
484
search->domainname = (char *) domainname;
485
search->category = category;
487
foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
489
if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
491
/* Now deal with plural. */
493
retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
494
(*foundp)->translation_length);
496
retval = (char *) (*foundp)->translation;
498
__libc_rwlock_unlock (_nl_state_lock);
503
/* Preserve the `errno' value. */
506
/* See whether this is a SUID binary or not. */
509
/* First find matching binding. */
510
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
512
int compare = strcmp (domainname, binding->domainname);
518
/* It is not in the list. */
525
dirname = (char *) INTUSE(_nl_default_dirname);
526
else if (IS_ABSOLUTE_PATH (binding->dirname))
527
dirname = binding->dirname;
530
/* We have a relative path. Make it absolute now. */
531
size_t dirname_len = strlen (binding->dirname) + 1;
535
path_max = (unsigned int) PATH_MAX;
536
path_max += 2; /* The getcwd docs say to do this. */
540
dirname = (char *) alloca (path_max + dirname_len);
541
ADD_BLOCK (block_list, dirname);
544
ret = getcwd (dirname, path_max);
545
if (ret != NULL || errno != ERANGE)
548
path_max += path_max / 2;
549
path_max += PATH_INCR;
553
/* We cannot get the current working directory. Don't signal an
554
error but simply return the default string. */
555
goto return_untranslated;
557
stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
560
/* Now determine the symbolic name of CATEGORY and its value. */
561
categoryname = category_to_name (category);
562
categoryvalue = guess_category_value (category, categoryname);
564
domainname_len = strlen (domainname);
565
xdomainname = (char *) alloca (strlen (categoryname)
566
+ domainname_len + 5);
567
ADD_BLOCK (block_list, xdomainname);
569
stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
570
domainname, domainname_len),
573
/* Creating working area. */
574
single_locale = (char *) alloca (strlen (categoryvalue) + 1);
575
ADD_BLOCK (block_list, single_locale);
578
/* Search for the given string. This is a loop because we perhaps
579
got an ordered list of languages to consider for the translation. */
582
/* Make CATEGORYVALUE point to the next element of the list. */
583
while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
585
if (categoryvalue[0] == '\0')
587
/* The whole contents of CATEGORYVALUE has been searched but
588
no valid entry has been found. We solve this situation
589
by implicitly appending a "C" entry, i.e. no translation
591
single_locale[0] = 'C';
592
single_locale[1] = '\0';
596
char *cp = single_locale;
597
while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
598
*cp++ = *categoryvalue++;
601
/* When this is a SUID binary we must not allow accessing files
602
outside the dedicated directories. */
603
if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
604
/* Ingore this entry. */
608
/* If the current locale value is C (or POSIX) we don't load a
609
domain. Return the MSGID. */
610
if (strcmp (single_locale, "C") == 0
611
|| strcmp (single_locale, "POSIX") == 0)
614
/* Find structure describing the message catalog matching the
615
DOMAINNAME and CATEGORY. */
616
domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
620
retval = _nl_find_msg (domain, binding, msgid1, &retlen);
626
for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
628
retval = _nl_find_msg (domain->successor[cnt], binding,
633
domain = domain->successor[cnt];
641
/* Found the translation of MSGID1 in domain DOMAIN:
642
starting at RETVAL, RETLEN bytes. */
643
FREE_BLOCKS (block_list);
644
#if defined HAVE_TSEARCH || defined _LIBC
647
/* Create a new entry and add it to the search tree. */
648
struct known_translation_t *newp;
650
newp = (struct known_translation_t *)
651
malloc (offsetof (struct known_translation_t, msgid)
652
+ msgid_len + domainname_len + 1);
656
mempcpy (newp->msgid, msgid1, msgid_len);
657
memcpy (newp->domainname, domainname, domainname_len + 1);
658
newp->category = category;
659
newp->counter = _nl_msg_cat_cntr;
660
newp->domain = domain;
661
newp->translation = retval;
662
newp->translation_length = retlen;
664
/* Insert the entry in the search tree. */
665
foundp = (struct known_translation_t **)
666
tsearch (newp, &root, transcmp);
668
|| __builtin_expect (*foundp != newp, 0))
669
/* The insert failed. */
675
/* We can update the existing entry. */
676
(*foundp)->counter = _nl_msg_cat_cntr;
677
(*foundp)->domain = domain;
678
(*foundp)->translation = retval;
679
(*foundp)->translation_length = retlen;
682
__set_errno (saved_errno);
684
/* Now deal with plural. */
686
retval = plural_lookup (domain, n, retval, retlen);
688
__libc_rwlock_unlock (_nl_state_lock);
695
/* Return the untranslated MSGID. */
696
FREE_BLOCKS (block_list);
697
__libc_rwlock_unlock (_nl_state_lock);
701
extern void _nl_log_untranslated (const char *logfilename,
702
const char *domainname,
703
const char *msgid1, const char *msgid2,
705
const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
707
if (logfilename != NULL && logfilename[0] != '\0')
708
_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
711
__set_errno (saved_errno);
714
/* Use the Germanic plural rule. */
715
: n == 1 ? (char *) msgid1 : (char *) msgid2);
721
_nl_find_msg (struct loaded_l10nfile *domain_file,
722
struct binding *domainbinding, const char *msgid,
725
struct loaded_domain *domain;
731
if (domain_file->decided == 0)
732
_nl_load_domain (domain_file, domainbinding);
734
if (domain_file->data == NULL)
737
domain = (struct loaded_domain *) domain_file->data;
739
nstrings = domain->nstrings;
741
/* Locate the MSGID and its translation. */
742
if (domain->hash_tab != NULL)
744
/* Use the hashing table. */
745
nls_uint32 len = strlen (msgid);
746
nls_uint32 hash_val = hash_string (msgid);
747
nls_uint32 idx = hash_val % domain->hash_size;
748
nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
753
W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
756
/* Hash table entry is empty. */
761
/* Compare msgid with the original string at index nstr.
762
We compare the lengths with >=, not ==, because plural entries
763
are represented by strings with an embedded NUL. */
765
? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
767
domain->data + W (domain->must_swap,
768
domain->orig_tab[nstr].offset))
770
: domain->orig_sysdep_tab[nstr - nstrings].length > len
772
domain->orig_sysdep_tab[nstr - nstrings].pointer)
779
if (idx >= domain->hash_size - incr)
780
idx -= domain->hash_size - incr;
788
/* Try the default method: binary search in the sorted array of
798
act = (bottom + top) / 2;
799
cmp_val = strcmp (msgid, (domain->data
800
+ W (domain->must_swap,
801
domain->orig_tab[act].offset)));
804
else if (cmp_val > 0)
809
/* No translation was found. */
814
/* The translation was found at index ACT. If we have to convert the
815
string to use a different character set, this is the time. */
819
(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
820
resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
824
result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
825
resultlen = domain->trans_sysdep_tab[act - nstrings].length;
828
#if defined _LIBC || HAVE_ICONV
829
if (domain->codeset_cntr
830
!= (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
832
/* The domain's codeset has changed through bind_textdomain_codeset()
833
since the message catalog was initialized or last accessed. We
834
have to reinitialize the converter. */
835
_nl_free_domain_conv (domain);
836
_nl_init_domain_conv (domain_file, domain, domainbinding);
841
domain->conv != (__gconv_t) -1
844
domain->conv != (iconv_t) -1
849
/* We are supposed to do a conversion. First allocate an
850
appropriate table with the same structure as the table
851
of translations in the file, where we can put the pointers
852
to the converted strings in.
853
There is a slight complication with plural entries. They
854
are represented by consecutive NUL terminated strings. We
855
handle this case by converting RESULTLEN bytes, including
858
if (domain->conv_tab == NULL
859
&& ((domain->conv_tab =
860
(char **) calloc (nstrings + domain->n_sysdep_strings,
863
/* Mark that we didn't succeed allocating a table. */
864
domain->conv_tab = (char **) -1;
866
if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
867
/* Nothing we can do, no more memory. */
870
if (domain->conv_tab[act] == NULL)
872
/* We haven't used this string so far, so it is not
873
translated yet. Do this now. */
874
/* We use a bit more efficient memory handling.
875
We allocate always larger blocks which get used over
876
time. This is faster than many small allocations. */
877
__libc_lock_define_initialized (static, lock)
878
# define INITIAL_BLOCK_SIZE 4080
879
static unsigned char *freemem;
880
static size_t freemem_size;
882
const unsigned char *inbuf;
883
unsigned char *outbuf;
886
transmem_block_t *transmem_list = NULL;
889
__libc_lock_lock (lock);
891
inbuf = (const unsigned char *) result;
892
outbuf = freemem + sizeof (size_t);
897
transmem_block_t *newmem;
899
size_t non_reversible;
902
if (freemem_size < sizeof (size_t))
905
res = __gconv (domain->conv,
906
&inbuf, inbuf + resultlen,
908
outbuf + freemem_size - sizeof (size_t),
911
if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
914
if (res != __GCONV_FULL_OUTPUT)
916
__libc_lock_unlock (lock);
923
const char *inptr = (const char *) inbuf;
924
size_t inleft = resultlen;
925
char *outptr = (char *) outbuf;
928
if (freemem_size < sizeof (size_t))
931
outleft = freemem_size - sizeof (size_t);
932
if (iconv (domain->conv,
933
(ICONV_CONST char **) &inptr, &inleft,
937
outbuf = (unsigned char *) outptr;
942
__libc_lock_unlock (lock);
949
/* We must allocate a new buffer or resize the old one. */
950
if (malloc_count > 0)
953
freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
954
newmem = (transmem_block_t *) realloc (transmem_list,
958
transmem_list = transmem_list->next;
961
struct transmem_list *old = transmem_list;
963
transmem_list = transmem_list->next;
971
freemem_size = INITIAL_BLOCK_SIZE;
972
newmem = (transmem_block_t *) malloc (freemem_size);
974
if (__builtin_expect (newmem == NULL, 0))
978
__libc_lock_unlock (lock);
983
/* Add the block to the list of blocks we have to free
985
newmem->next = transmem_list;
986
transmem_list = newmem;
988
freemem = newmem->data;
989
freemem_size -= offsetof (struct transmem_list, data);
991
transmem_list = newmem;
995
outbuf = freemem + sizeof (size_t);
998
/* We have now in our buffer a converted string. Put this
999
into the table of conversions. */
1000
*(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1001
domain->conv_tab[act] = (char *) freemem;
1002
/* Shrink freemem, but keep it aligned. */
1003
freemem_size -= outbuf - freemem;
1005
freemem += freemem_size & (alignof (size_t) - 1);
1006
freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1008
__libc_lock_unlock (lock);
1011
/* Now domain->conv_tab[act] contains the translation of all
1012
the plural variants. */
1013
result = domain->conv_tab[act] + sizeof (size_t);
1014
resultlen = *(size_t *) domain->conv_tab[act];
1018
/* The result string is converted. */
1020
#endif /* _LIBC || HAVE_ICONV */
1022
*lengthp = resultlen;
1027
/* Look up a plural variant. */
1030
plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
1031
const char *translation, size_t translation_len)
1033
struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1034
unsigned long int index;
1037
index = plural_eval (domaindata->plural, n);
1038
if (index >= domaindata->nplurals)
1039
/* This should never happen. It means the plural expression and the
1040
given maximum value do not match. */
1043
/* Skip INDEX strings at TRANSLATION. */
1048
p = __rawmemchr (p, '\0');
1050
p = strchr (p, '\0');
1052
/* And skip over the NUL byte. */
1055
if (p >= translation + translation_len)
1056
/* This should never happen. It means the plural expression
1057
evaluated to a value larger than the number of variants
1058
available for MSGID1. */
1059
return (char *) translation;
1065
/* Return string representation of locale CATEGORY. */
1068
category_to_name (int category)
1076
retval = "LC_COLLATE";
1081
retval = "LC_CTYPE";
1086
retval = "LC_MONETARY";
1091
retval = "LC_NUMERIC";
1101
retval = "LC_MESSAGES";
1106
retval = "LC_RESPONSE";
1111
/* This might not make sense but is perhaps better than any other
1117
/* If you have a better idea for a default value let me know. */
1125
/* Guess value of current locale from value of the environment variables. */
1128
guess_category_value (int category, const char *categoryname)
1130
const char *language;
1133
/* The highest priority value is the `LANGUAGE' environment
1134
variable. But we don't use the value if the currently selected
1135
locale is the C locale. This is a GNU extension. */
1136
language = getenv ("LANGUAGE");
1137
if (language != NULL && language[0] == '\0')
1140
/* We have to proceed with the POSIX methods of looking to `LC_ALL',
1141
`LC_xxx', and `LANG'. On some systems this can be done by the
1142
`setlocale' function itself. */
1144
retval = __current_locale_name (category);
1146
retval = _nl_locale_name (category, categoryname);
1149
/* Ignore LANGUAGE if the locale is set to "C" because
1150
1. "C" locale usually uses the ASCII encoding, and most international
1151
messages use non-ASCII characters. These characters get displayed
1152
as question marks (if using glibc's iconv()) or as invalid 8-bit
1153
characters (because other iconv()s refuse to convert most non-ASCII
1154
characters to ASCII). In any case, the output is ugly.
1155
2. The precise output of some programs in the "C" locale is specified
1156
by POSIX and should not depend on environment variables like
1157
"LANGUAGE". We allow such programs to use gettext(). */
1158
return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1161
/* @@ begin of epilog @@ */
1163
/* We don't want libintl.a to depend on any other library. So we
1164
avoid the non-standard function stpcpy. In GNU C Library this
1165
function is available, though. Also allow the symbol HAVE_STPCPY
1167
#if !_LIBC && !HAVE_STPCPY
1169
stpcpy (char *dest, const char *src)
1171
while ((*dest++ = *src++) != '\0')
1177
#if !_LIBC && !HAVE_MEMPCPY
1179
mempcpy (void *dest, const void *src, size_t n)
1181
return (void *) ((char *) memcpy (dest, src, n) + n);
1187
/* If we want to free all resources we have to do some work at
1189
libc_freeres_fn (free_mem)
1193
while (_nl_domain_bindings != NULL)
1195
struct binding *oldp = _nl_domain_bindings;
1196
_nl_domain_bindings = _nl_domain_bindings->next;
1197
if (oldp->dirname != INTUSE(_nl_default_dirname))
1198
/* Yes, this is a pointer comparison. */
1199
free (oldp->dirname);
1200
free (oldp->codeset);
1204
if (_nl_current_default_domain != _nl_default_default_domain)
1205
/* Yes, again a pointer comparison. */
1206
free ((char *) _nl_current_default_domain);
1208
/* Remove the search tree with the known translations. */
1209
__tdestroy (root, free);
1212
while (transmem_list != NULL)
1214
old = transmem_list;
1215
transmem_list = transmem_list->next;