1
/* Load needed message catalogs.
2
Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2, or (at your option)
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software Foundation,
16
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
/* Tell glibc's <string.h> to provide a prototype for mempcpy().
19
This must come before <config.h> because <config.h> may include
20
<features.h>, and once <features.h> has been included, it's too late. */
22
# define _GNU_SOURCE 1
26
# include <gnulib/config.h>
28
# undef PACKAGE_VERSION
29
# undef PACKAGE_TARNAME
30
# undef PACKAGE_STRING
37
#include <sys/types.h>
41
# define alloca __builtin_alloca
42
# define HAVE_ALLOCA 1
44
# if defined HAVE_ALLOCA_H || defined _LIBC
60
#if defined HAVE_UNISTD_H || defined _LIBC
65
# include <langinfo.h>
69
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
70
|| (defined _LIBC && defined _POSIX_MAPPED_FILES)
71
# include <sys/mman.h>
82
# include "../locale/localeinfo.h"
85
/* @@ end of prolog @@ */
88
/* Rename the non ISO C functions. This is required by the standard
89
because some ISO C functions will require linking with this object
90
file and the name space must not be polluted. */
92
# define close __close
95
# define munmap __munmap
98
/* Names for the libintl functions are a problem. They must not clash
99
with existing names and they should follow ANSI C. But this source
100
code is also used in GNU C Library where the names have a __
101
prefix. So we have to make a difference here. */
103
# define PLURAL_PARSE __gettextparse
105
# define PLURAL_PARSE gettextparse__
108
/* For those losing systems which don't have `alloca' we have to add
109
some additional code emulating it. */
111
# define freea(p) /* nothing */
113
# define alloca(n) malloc (n)
114
# define freea(p) free (p)
117
/* For systems that distinguish between text and binary I/O.
118
O_BINARY is usually declared in <fcntl.h>. */
119
#if !defined O_BINARY && defined _O_BINARY
120
/* For MSC-compatible compilers. */
121
# define O_BINARY _O_BINARY
122
# define O_TEXT _O_TEXT
125
/* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
129
/* On reasonable systems, binary I/O is the default. */
134
/* We need a sign, whether a new catalog was loaded, which can be associated
135
with all translations. This is important if the translations are
136
cached by one of GCC's features. */
137
int _nl_msg_cat_cntr;
139
#if (defined __GNUC__ && !defined __APPLE_CC__) \
140
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
142
/* These structs are the constant expression for the germanic plural
143
form determination. It represents the expression "n != 1". */
144
static const struct expression plvar =
149
static const struct expression plone =
158
static struct expression germanic_plural =
161
.operation = not_equal,
166
[0] = (struct expression *) &plvar,
167
[1] = (struct expression *) &plone
172
# define INIT_GERMANIC_PLURAL()
176
/* For compilers without support for ISO C 99 struct/union initializers:
177
Initialization at run-time. */
179
static struct expression plvar;
180
static struct expression plone;
181
static struct expression germanic_plural;
184
init_germanic_plural ()
186
if (plone.val.num == 0)
189
plvar.operation = var;
192
plone.operation = num;
195
germanic_plural.nargs = 2;
196
germanic_plural.operation = not_equal;
197
germanic_plural.val.args[0] = &plvar;
198
germanic_plural.val.args[1] = &plone;
202
# define INIT_GERMANIC_PLURAL() init_germanic_plural ()
207
/* Initialize the codeset dependent parts of an opened message catalog.
208
Return the header entry. */
211
_nl_init_domain_conv (domain_file, domain, domainbinding)
212
struct loaded_l10nfile *domain_file;
213
struct loaded_domain *domain;
214
struct binding *domainbinding;
216
/* Find out about the character set the file is encoded with.
217
This can be found (in textual form) in the entry "". If this
218
entry does not exist or if this does not contain the `charset='
219
information, we will assume the charset matches the one the
220
current locale and we don't have to perform any conversion. */
224
/* Preinitialize fields, to avoid recursion during _nl_find_msg. */
225
domain->codeset_cntr =
226
(domainbinding != NULL ? domainbinding->codeset_cntr : 0);
228
domain->conv = (__gconv_t) -1;
231
domain->conv = (iconv_t) -1;
234
domain->conv_tab = NULL;
236
/* Get the header entry. */
237
nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
239
if (nullentry != NULL)
241
#if defined _LIBC || HAVE_ICONV
242
const char *charsetstr;
244
charsetstr = strstr (nullentry, "charset=");
245
if (charsetstr != NULL)
249
const char *outcharset;
251
charsetstr += strlen ("charset=");
252
len = strcspn (charsetstr, " \t\n");
254
charset = (char *) alloca (len + 1);
255
# if defined _LIBC || HAVE_MEMPCPY
256
*((char *) mempcpy (charset, charsetstr, len)) = '\0';
258
memcpy (charset, charsetstr, len);
262
/* The output charset should normally be determined by the
263
locale. But sometimes the locale is not used or not correctly
264
set up, so we provide a possibility for the user to override
265
this. Moreover, the value specified through
266
bind_textdomain_codeset overrides both. */
267
if (domainbinding != NULL && domainbinding->codeset != NULL)
268
outcharset = domainbinding->codeset;
271
outcharset = getenv ("OUTPUT_CHARSET");
272
if (outcharset == NULL || outcharset[0] == '\0')
275
outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
278
extern const char *locale_charset (void);
279
outcharset = locale_charset ();
286
/* We always want to use transliteration. */
287
outcharset = norm_add_slashes (outcharset, "TRANSLIT");
288
charset = norm_add_slashes (charset, NULL);
289
if (__gconv_open (outcharset, charset, &domain->conv,
292
domain->conv = (__gconv_t) -1;
295
/* When using GNU libiconv, we want to use transliteration. */
296
# if _LIBICONV_VERSION >= 0x0105
297
len = strlen (outcharset);
299
char *tmp = (char *) alloca (len + 10 + 1);
300
memcpy (tmp, outcharset, len);
301
memcpy (tmp + len, "//TRANSLIT", 10 + 1);
305
domain->conv = iconv_open (outcharset, charset);
306
# if _LIBICONV_VERSION >= 0x0105
314
#endif /* _LIBC || HAVE_ICONV */
320
/* Frees the codeset dependent parts of an opened message catalog. */
323
_nl_free_domain_conv (domain)
324
struct loaded_domain *domain;
326
if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
327
free (domain->conv_tab);
330
if (domain->conv != (__gconv_t) -1)
331
__gconv_close (domain->conv);
334
if (domain->conv != (iconv_t) -1)
335
iconv_close (domain->conv);
340
/* Load the message catalogs specified by FILENAME. If it is no valid
341
message catalog do nothing. */
344
_nl_load_domain (domain_file, domainbinding)
345
struct loaded_l10nfile *domain_file;
346
struct binding *domainbinding;
355
struct mo_file_header *data = (struct mo_file_header *) -1;
357
struct loaded_domain *domain;
358
const char *nullentry;
360
domain_file->decided = 1;
361
domain_file->data = NULL;
363
/* Note that it would be useless to store domainbinding in domain_file
364
because domainbinding might be == NULL now but != NULL later (after
365
a call to bind_textdomain_codeset). */
367
/* If the record does not represent a valid locale the FILENAME
368
might be NULL. This can happen when according to the given
369
specification the locale file name is different for XPG and CEN
371
if (domain_file->filename == NULL)
374
/* Try to open the addressed file. */
375
fd = open (domain_file->filename, O_RDONLY | O_BINARY);
379
/* We must know about the size of the file. */
382
__builtin_expect (fstat64 (fd, &st) != 0, 0)
384
__builtin_expect (fstat (fd, &st) != 0, 0)
386
|| __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
387
|| __builtin_expect (size < sizeof (struct mo_file_header), 0))
389
/* Something went wrong. */
395
/* Now we are ready to load the file. If mmap() is available we try
396
this first. If not available or it failed we try to load it. */
397
data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
400
if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
402
/* mmap() call was successful. */
408
/* If the data is not yet available (i.e. mmap'ed) we try to load
410
if (data == (struct mo_file_header *) -1)
415
data = (struct mo_file_header *) malloc (size);
420
read_ptr = (char *) data;
423
long int nb = (long int) read (fd, read_ptr, to_read);
427
if (nb == -1 && errno == EINTR)
441
/* Using the magic number we can test whether it really is a message
443
if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
446
/* The magic number is wrong: not a message catalog file. */
449
munmap ((caddr_t) data, size);
456
domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
459
domain_file->data = domain;
461
domain->data = (char *) data;
462
domain->use_mmap = use_mmap;
463
domain->mmap_size = size;
464
domain->must_swap = data->magic != _MAGIC;
466
/* Fill in the information about the available tables. */
467
switch (W (domain->must_swap, data->revision))
470
domain->nstrings = W (domain->must_swap, data->nstrings);
471
domain->orig_tab = (struct string_desc *)
472
((char *) data + W (domain->must_swap, data->orig_tab_offset));
473
domain->trans_tab = (struct string_desc *)
474
((char *) data + W (domain->must_swap, data->trans_tab_offset));
475
domain->hash_size = W (domain->must_swap, data->hash_tab_size);
476
domain->hash_tab = (nls_uint32 *)
477
((char *) data + W (domain->must_swap, data->hash_tab_offset));
480
/* This is an invalid revision. */
483
munmap ((caddr_t) data, size);
488
domain_file->data = NULL;
492
/* Now initialize the character set converter from the character set
493
the file is encoded with (found in the header entry) to the domain's
494
specified character set or the locale's character set. */
495
nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
497
/* Also look for a plural specification. */
498
if (nullentry != NULL)
501
const char *nplurals;
503
plural = strstr (nullentry, "plural=");
504
nplurals = strstr (nullentry, "nplurals=");
505
if (plural == NULL || nplurals == NULL)
509
/* First get the number. */
512
struct parse_args args;
515
while (*nplurals != '\0' && isspace (*nplurals))
517
#if defined HAVE_STRTOUL || defined _LIBC
518
n = strtoul (nplurals, &endp, 10);
520
for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
521
n = n * 10 + (*endp - '0');
523
domain->nplurals = n;
524
if (nplurals == endp)
527
/* Due to the restrictions bison imposes onto the interface of the
528
scanner function we have to put the input string and the result
529
passed up from the parser into the same structure which address
530
is passed down to the parser. */
533
if (PLURAL_PARSE (&args) != 0)
535
domain->plural = args.res;
540
/* By default we are using the Germanic form: singular form only
541
for `one', the plural form otherwise. Yes, this is also what
542
English is using since English is a Germanic language. */
544
INIT_GERMANIC_PLURAL ();
545
domain->plural = &germanic_plural;
546
domain->nplurals = 2;
554
_nl_unload_domain (domain)
555
struct loaded_domain *domain;
557
if (domain->plural != &germanic_plural)
558
__gettext_free_exp (domain->plural);
560
_nl_free_domain_conv (domain);
562
# ifdef _POSIX_MAPPED_FILES
563
if (domain->use_mmap)
564
munmap ((caddr_t) domain->data, domain->mmap_size);
566
# endif /* _POSIX_MAPPED_FILES */
567
free ((void *) domain->data);