Update.
[glibc.git] / intl / loadmsgcat.c
blob8520f7d20c7eee4a0871fa479ca01d05d719ebf8
1 /* Load needed message catalogs.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
21 This must come before <config.h> because <config.h> may include
22 <features.h>, and once <features.h> has been included, it's too late. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #ifdef __GNUC__
38 # define alloca __builtin_alloca
39 # define HAVE_ALLOCA 1
40 #else
41 # if defined HAVE_ALLOCA_H || defined _LIBC
42 # include <alloca.h>
43 # else
44 # ifdef _AIX
45 #pragma alloca
46 # else
47 # ifndef alloca
48 char *alloca ();
49 # endif
50 # endif
51 # endif
52 #endif
54 #if defined STDC_HEADERS || defined _LIBC
55 # include <stdlib.h>
56 #endif
58 #if defined HAVE_STRING_H || defined _LIBC
59 # include <string.h>
60 #else
61 # include <strings.h>
62 #endif
64 #if defined HAVE_UNISTD_H || defined _LIBC
65 # include <unistd.h>
66 #endif
68 #ifdef _LIBC
69 # include <langinfo.h>
70 # include <locale.h>
71 #endif
73 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
74 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
75 # include <sys/mman.h>
76 # undef HAVE_MMAP
77 # define HAVE_MMAP 1
78 #else
79 # undef HAVE_MMAP
80 #endif
82 #include "gettext.h"
83 #include "gettextP.h"
85 #ifdef _LIBC
86 # include "../locale/localeinfo.h"
87 #endif
89 /* @@ end of prolog @@ */
91 #ifdef _LIBC
92 /* Rename the non ISO C functions. This is required by the standard
93 because some ISO C functions will require linking with this object
94 file and the name space must not be polluted. */
95 # define open __open
96 # define close __close
97 # define read __read
98 # define mmap __mmap
99 # define munmap __munmap
100 #endif
102 /* Names for the libintl functions are a problem. They must not clash
103 with existing names and they should follow ANSI C. But this source
104 code is also used in GNU C Library where the names have a __
105 prefix. So we have to make a difference here. */
106 #ifdef _LIBC
107 # define PLURAL_PARSE __gettextparse
108 #else
109 # define PLURAL_PARSE gettextparse__
110 #endif
112 /* For those losing systems which don't have `alloca' we have to add
113 some additional code emulating it. */
114 #ifdef HAVE_ALLOCA
115 # define freea(p) /* nothing */
116 #else
117 # define alloca(n) malloc (n)
118 # define freea(p) free (p)
119 #endif
121 /* We need a sign, whether a new catalog was loaded, which can be associated
122 with all translations. This is important if the translations are
123 cached by one of GCC's features. */
124 int _nl_msg_cat_cntr;
126 #if defined __GNUC__ \
127 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
129 /* These structs are the constant expression for the germanic plural
130 form determination. It represents the expression "n != 1". */
131 static const struct expression plvar =
133 .nargs = 0,
134 .operation = var,
136 static const struct expression plone =
138 .nargs = 0,
139 .operation = num,
140 .val =
142 .num = 1
145 static struct expression germanic_plural =
147 .nargs = 2,
148 .operation = not_equal,
149 .val =
151 .args =
153 [0] = (struct expression *) &plvar,
154 [1] = (struct expression *) &plone
159 # define INIT_GERMANIC_PLURAL()
161 #else
163 /* For compilers without support for ISO C 99 struct/union initializers:
164 Initialization at run-time. */
166 static struct expression plvar;
167 static struct expression plone;
168 static struct expression germanic_plural;
170 static void
171 init_germanic_plural ()
173 if (plone.val.num == 0)
175 plvar.nargs = 0;
176 plvar.operation = var;
178 plone.nargs = 0;
179 plone.operation = num;
180 plone.val.num = 1;
182 germanic_plural.nargs = 2;
183 germanic_plural.operation = not_equal;
184 germanic_plural.val.args[0] = &plvar;
185 germanic_plural.val.args[1] = &plone;
189 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
191 #endif
194 /* Initialize the codeset dependent parts of an opened message catalog.
195 Return the header entry. */
196 const char *
197 internal_function
198 _nl_init_domain_conv (domain_file, domain, domainbinding)
199 struct loaded_l10nfile *domain_file;
200 struct loaded_domain *domain;
201 struct binding *domainbinding;
203 /* Find out about the character set the file is encoded with.
204 This can be found (in textual form) in the entry "". If this
205 entry does not exist or if this does not contain the `charset='
206 information, we will assume the charset matches the one the
207 current locale and we don't have to perform any conversion. */
208 char *nullentry;
209 size_t nullentrylen;
211 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
212 domain->codeset_cntr =
213 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
214 #ifdef _LIBC
215 domain->conv = (__gconv_t) -1;
216 #else
217 # if HAVE_ICONV
218 domain->conv = (iconv_t) -1;
219 # endif
220 #endif
221 domain->conv_tab = NULL;
223 /* Get the header entry. */
224 nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
226 if (nullentry != NULL)
228 #if defined _LIBC || HAVE_ICONV
229 const char *charsetstr;
231 charsetstr = strstr (nullentry, "charset=");
232 if (charsetstr != NULL)
234 size_t len;
235 char *charset;
236 const char *outcharset;
238 charsetstr += strlen ("charset=");
239 len = strcspn (charsetstr, " \t\n");
241 charset = (char *) alloca (len + 1);
242 # if defined _LIBC || HAVE_MEMPCPY
243 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
244 # else
245 memcpy (charset, charsetstr, len);
246 charset[len] = '\0';
247 # endif
249 /* The output charset should normally be determined by the
250 locale. But sometimes the locale is not used or not correctly
251 set up, so we provide a possibility for the user to override
252 this. Moreover, the value specified through
253 bind_textdomain_codeset overrides both. */
254 if (domainbinding != NULL && domainbinding->codeset != NULL)
255 outcharset = domainbinding->codeset;
256 else
258 outcharset = getenv ("OUTPUT_CHARSET");
259 if (outcharset == NULL || outcharset[0] == '\0')
261 # ifdef _LIBC
262 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
263 # else
264 # if HAVE_ICONV
265 extern const char *locale_charset (void);
266 outcharset = locale_charset ();
267 # endif
268 # endif
272 # ifdef _LIBC
273 /* We always want to use transliteration. */
274 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
275 charset = norm_add_slashes (charset, NULL);
276 if (__gconv_open (outcharset, charset, &domain->conv,
277 GCONV_AVOID_NOCONV)
278 != __GCONV_OK)
279 domain->conv = (__gconv_t) -1;
280 # else
281 # if HAVE_ICONV
282 /* When using GNU libiconv, we want to use transliteration. */
283 # if _LIBICONV_VERSION
284 len = strlen (outcharset);
286 char *tmp = (char *) alloca (len + 10 + 1);
287 memcpy (tmp, outcharset, len);
288 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
289 outcharset = tmp;
291 # endif
292 domain->conv = iconv_open (outcharset, charset);
293 # if _LIBICONV_VERSION
294 freea (outcharset);
295 # endif
296 # endif
297 # endif
299 freea (charset);
301 #endif /* _LIBC || HAVE_ICONV */
304 return nullentry;
307 /* Frees the codeset dependent parts of an opened message catalog. */
308 void
309 internal_function
310 _nl_free_domain_conv (domain)
311 struct loaded_domain *domain;
313 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
314 free (domain->conv_tab);
316 #ifdef _LIBC
317 if (domain->conv != (__gconv_t) -1)
318 __gconv_close (domain->conv);
319 #else
320 # if HAVE_ICONV
321 if (domain->conv != (iconv_t) -1)
322 iconv_close (domain->conv);
323 # endif
324 #endif
327 /* Load the message catalogs specified by FILENAME. If it is no valid
328 message catalog do nothing. */
329 void
330 internal_function
331 _nl_load_domain (domain_file, domainbinding)
332 struct loaded_l10nfile *domain_file;
333 struct binding *domainbinding;
335 int fd;
336 size_t size;
337 #ifdef _LIBC
338 struct stat64 st;
339 #else
340 struct stat st;
341 #endif
342 struct mo_file_header *data = (struct mo_file_header *) -1;
343 int use_mmap = 0;
344 struct loaded_domain *domain;
345 const char *nullentry;
347 domain_file->decided = 1;
348 domain_file->data = NULL;
350 /* Note that it would be useless to store domainbinding in domain_file
351 because domainbinding might be == NULL now but != NULL later (after
352 a call to bind_textdomain_codeset). */
354 /* If the record does not represent a valid locale the FILENAME
355 might be NULL. This can happen when according to the given
356 specification the locale file name is different for XPG and CEN
357 syntax. */
358 if (domain_file->filename == NULL)
359 return;
361 /* Try to open the addressed file. */
362 fd = open (domain_file->filename, O_RDONLY);
363 if (fd == -1)
364 return;
366 /* We must know about the size of the file. */
367 if (
368 #ifdef _LIBC
369 __builtin_expect (fstat64 (fd, &st) != 0, 0)
370 #else
371 __builtin_expect (fstat (fd, &st) != 0, 0)
372 #endif
373 || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
374 || __builtin_expect (size < sizeof (struct mo_file_header), 0))
376 /* Something went wrong. */
377 close (fd);
378 return;
381 #ifdef HAVE_MMAP
382 /* Now we are ready to load the file. If mmap() is available we try
383 this first. If not available or it failed we try to load it. */
384 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
385 MAP_PRIVATE, fd, 0);
387 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
389 /* mmap() call was successful. */
390 close (fd);
391 use_mmap = 1;
393 #endif
395 /* If the data is not yet available (i.e. mmap'ed) we try to load
396 it manually. */
397 if (data == (struct mo_file_header *) -1)
399 size_t to_read;
400 char *read_ptr;
402 data = (struct mo_file_header *) malloc (size);
403 if (data == NULL)
404 return;
406 to_read = size;
407 read_ptr = (char *) data;
410 long int nb = (long int) read (fd, read_ptr, to_read);
411 if (nb <= 0)
413 #ifdef EINTR
414 if (nb == -1 && errno == EINTR)
415 continue;
416 #endif
417 close (fd);
418 return;
420 read_ptr += nb;
421 to_read -= nb;
423 while (to_read > 0);
425 close (fd);
428 /* Using the magic number we can test whether it really is a message
429 catalog file. */
430 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
433 /* The magic number is wrong: not a message catalog file. */
434 #ifdef HAVE_MMAP
435 if (use_mmap)
436 munmap ((caddr_t) data, size);
437 else
438 #endif
439 free (data);
440 return;
443 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
444 if (domain == NULL)
445 return;
446 domain_file->data = domain;
448 domain->data = (char *) data;
449 domain->use_mmap = use_mmap;
450 domain->mmap_size = size;
451 domain->must_swap = data->magic != _MAGIC;
453 /* Fill in the information about the available tables. */
454 switch (W (domain->must_swap, data->revision))
456 case 0:
457 domain->nstrings = W (domain->must_swap, data->nstrings);
458 domain->orig_tab = (struct string_desc *)
459 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
460 domain->trans_tab = (struct string_desc *)
461 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
462 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
463 domain->hash_tab = (nls_uint32 *)
464 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
465 break;
466 default:
467 /* This is an invalid revision. */
468 #ifdef HAVE_MMAP
469 if (use_mmap)
470 munmap ((caddr_t) data, size);
471 else
472 #endif
473 free (data);
474 free (domain);
475 domain_file->data = NULL;
476 return;
479 /* Now initialize the character set converter from the character set
480 the file is encoded with (found in the header entry) to the domain's
481 specified character set or the locale's character set. */
482 nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
484 /* Also look for a plural specification. */
485 if (nullentry != NULL)
487 const char *plural;
488 const char *nplurals;
490 plural = strstr (nullentry, "plural=");
491 nplurals = strstr (nullentry, "nplurals=");
492 if (plural == NULL || nplurals == NULL)
493 goto no_plural;
494 else
496 /* First get the number. */
497 char *endp;
498 unsigned long int n;
499 struct parse_args args;
501 nplurals += 9;
502 while (*nplurals != '\0' && isspace (*nplurals))
503 ++nplurals;
504 #if defined HAVE_STRTOUL || defined _LIBC
505 n = strtoul (nplurals, &endp, 10);
506 #else
507 for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
508 n = n * 10 + (*endp - '0');
509 #endif
510 domain->nplurals = n;
511 if (nplurals == endp)
512 goto no_plural;
514 /* Due to the restrictions bison imposes onto the interface of the
515 scanner function we have to put the input string and the result
516 passed up from the parser into the same structure which address
517 is passed down to the parser. */
518 plural += 7;
519 args.cp = plural;
520 if (PLURAL_PARSE (&args) != 0)
521 goto no_plural;
522 domain->plural = args.res;
525 else
527 /* By default we are using the Germanic form: singular form only
528 for `one', the plural form otherwise. Yes, this is also what
529 English is using since English is a Germanic language. */
530 no_plural:
531 INIT_GERMANIC_PLURAL ();
532 domain->plural = &germanic_plural;
533 domain->nplurals = 2;
538 #ifdef _LIBC
539 void
540 internal_function
541 _nl_unload_domain (domain)
542 struct loaded_domain *domain;
544 if (domain->plural != &germanic_plural)
545 __gettext_free_exp (domain->plural);
547 _nl_free_domain_conv (domain);
549 # ifdef _POSIX_MAPPED_FILES
550 if (domain->use_mmap)
551 munmap ((caddr_t) domain->data, domain->mmap_size);
552 else
553 # endif /* _POSIX_MAPPED_FILES */
554 free ((void *) domain->data);
556 free (domain);
558 #endif