Merged changes made for version 4.1.20 onto the trunk
[findutils.git] / intl / loadmsgcat.c
blob8e420772bd343659b656fbfc12ba67dd06851ea5
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)
7 any later version.
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. */
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE 1
23 #endif
25 #ifdef HAVE_CONFIG_H
26 # include <gnulib/config.h>
27 # undef VERSION
28 # undef PACKAGE_VERSION
29 # undef PACKAGE_TARNAME
30 # undef PACKAGE_STRING
31 # include <config.h>
32 #endif
34 #include <ctype.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
40 #ifdef __GNUC__
41 # define alloca __builtin_alloca
42 # define HAVE_ALLOCA 1
43 #else
44 # if defined HAVE_ALLOCA_H || defined _LIBC
45 # include <alloca.h>
46 # else
47 # ifdef _AIX
48 #pragma alloca
49 # else
50 # ifndef alloca
51 char *alloca ();
52 # endif
53 # endif
54 # endif
55 #endif
57 #include <stdlib.h>
58 #include <string.h>
60 #if defined HAVE_UNISTD_H || defined _LIBC
61 # include <unistd.h>
62 #endif
64 #ifdef _LIBC
65 # include <langinfo.h>
66 # include <locale.h>
67 #endif
69 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
70 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
71 # include <sys/mman.h>
72 # undef HAVE_MMAP
73 # define HAVE_MMAP 1
74 #else
75 # undef HAVE_MMAP
76 #endif
78 #include "gettext.h"
79 #include "gettextP.h"
81 #ifdef _LIBC
82 # include "../locale/localeinfo.h"
83 #endif
85 /* @@ end of prolog @@ */
87 #ifdef _LIBC
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. */
91 # define open __open
92 # define close __close
93 # define read __read
94 # define mmap __mmap
95 # define munmap __munmap
96 #endif
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. */
102 #ifdef _LIBC
103 # define PLURAL_PARSE __gettextparse
104 #else
105 # define PLURAL_PARSE gettextparse__
106 #endif
108 /* For those losing systems which don't have `alloca' we have to add
109 some additional code emulating it. */
110 #ifdef HAVE_ALLOCA
111 # define freea(p) /* nothing */
112 #else
113 # define alloca(n) malloc (n)
114 # define freea(p) free (p)
115 #endif
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
123 #endif
124 #ifdef __BEOS__
125 /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
126 # undef O_BINARY
127 # undef O_TEXT
128 #endif
129 /* On reasonable systems, binary I/O is the default. */
130 #ifndef O_BINARY
131 # define O_BINARY 0
132 #endif
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 =
146 .nargs = 0,
147 .operation = var,
149 static const struct expression plone =
151 .nargs = 0,
152 .operation = num,
153 .val =
155 .num = 1
158 static struct expression germanic_plural =
160 .nargs = 2,
161 .operation = not_equal,
162 .val =
164 .args =
166 [0] = (struct expression *) &plvar,
167 [1] = (struct expression *) &plone
172 # define INIT_GERMANIC_PLURAL()
174 #else
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;
183 static void
184 init_germanic_plural ()
186 if (plone.val.num == 0)
188 plvar.nargs = 0;
189 plvar.operation = var;
191 plone.nargs = 0;
192 plone.operation = num;
193 plone.val.num = 1;
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 ()
204 #endif
207 /* Initialize the codeset dependent parts of an opened message catalog.
208 Return the header entry. */
209 const char *
210 internal_function
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. */
221 char *nullentry;
222 size_t nullentrylen;
224 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
225 domain->codeset_cntr =
226 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
227 #ifdef _LIBC
228 domain->conv = (__gconv_t) -1;
229 #else
230 # if HAVE_ICONV
231 domain->conv = (iconv_t) -1;
232 # endif
233 #endif
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)
247 size_t len;
248 char *charset;
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';
257 # else
258 memcpy (charset, charsetstr, len);
259 charset[len] = '\0';
260 # endif
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;
269 else
271 outcharset = getenv ("OUTPUT_CHARSET");
272 if (outcharset == NULL || outcharset[0] == '\0')
274 # ifdef _LIBC
275 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
276 # else
277 # if HAVE_ICONV
278 extern const char *locale_charset (void);
279 outcharset = locale_charset ();
280 # endif
281 # endif
285 # ifdef _LIBC
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,
290 GCONV_AVOID_NOCONV)
291 != __GCONV_OK)
292 domain->conv = (__gconv_t) -1;
293 # else
294 # if HAVE_ICONV
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);
302 outcharset = tmp;
304 # endif
305 domain->conv = iconv_open (outcharset, charset);
306 # if _LIBICONV_VERSION >= 0x0105
307 freea (outcharset);
308 # endif
309 # endif
310 # endif
312 freea (charset);
314 #endif /* _LIBC || HAVE_ICONV */
317 return nullentry;
320 /* Frees the codeset dependent parts of an opened message catalog. */
321 void
322 internal_function
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);
329 #ifdef _LIBC
330 if (domain->conv != (__gconv_t) -1)
331 __gconv_close (domain->conv);
332 #else
333 # if HAVE_ICONV
334 if (domain->conv != (iconv_t) -1)
335 iconv_close (domain->conv);
336 # endif
337 #endif
340 /* Load the message catalogs specified by FILENAME. If it is no valid
341 message catalog do nothing. */
342 void
343 internal_function
344 _nl_load_domain (domain_file, domainbinding)
345 struct loaded_l10nfile *domain_file;
346 struct binding *domainbinding;
348 int fd;
349 size_t size;
350 #ifdef _LIBC
351 struct stat64 st;
352 #else
353 struct stat st;
354 #endif
355 struct mo_file_header *data = (struct mo_file_header *) -1;
356 int use_mmap = 0;
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
370 syntax. */
371 if (domain_file->filename == NULL)
372 return;
374 /* Try to open the addressed file. */
375 fd = open (domain_file->filename, O_RDONLY | O_BINARY);
376 if (fd == -1)
377 return;
379 /* We must know about the size of the file. */
380 if (
381 #ifdef _LIBC
382 __builtin_expect (fstat64 (fd, &st) != 0, 0)
383 #else
384 __builtin_expect (fstat (fd, &st) != 0, 0)
385 #endif
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. */
390 close (fd);
391 return;
394 #ifdef HAVE_MMAP
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,
398 MAP_PRIVATE, fd, 0);
400 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
402 /* mmap() call was successful. */
403 close (fd);
404 use_mmap = 1;
406 #endif
408 /* If the data is not yet available (i.e. mmap'ed) we try to load
409 it manually. */
410 if (data == (struct mo_file_header *) -1)
412 size_t to_read;
413 char *read_ptr;
415 data = (struct mo_file_header *) malloc (size);
416 if (data == NULL)
417 return;
419 to_read = size;
420 read_ptr = (char *) data;
423 long int nb = (long int) read (fd, read_ptr, to_read);
424 if (nb <= 0)
426 #ifdef EINTR
427 if (nb == -1 && errno == EINTR)
428 continue;
429 #endif
430 close (fd);
431 return;
433 read_ptr += nb;
434 to_read -= nb;
436 while (to_read > 0);
438 close (fd);
441 /* Using the magic number we can test whether it really is a message
442 catalog file. */
443 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
446 /* The magic number is wrong: not a message catalog file. */
447 #ifdef HAVE_MMAP
448 if (use_mmap)
449 munmap ((caddr_t) data, size);
450 else
451 #endif
452 free (data);
453 return;
456 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
457 if (domain == NULL)
458 return;
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))
469 case 0:
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));
478 break;
479 default:
480 /* This is an invalid revision. */
481 #ifdef HAVE_MMAP
482 if (use_mmap)
483 munmap ((caddr_t) data, size);
484 else
485 #endif
486 free (data);
487 free (domain);
488 domain_file->data = NULL;
489 return;
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)
500 const char *plural;
501 const char *nplurals;
503 plural = strstr (nullentry, "plural=");
504 nplurals = strstr (nullentry, "nplurals=");
505 if (plural == NULL || nplurals == NULL)
506 goto no_plural;
507 else
509 /* First get the number. */
510 char *endp;
511 unsigned long int n;
512 struct parse_args args;
514 nplurals += 9;
515 while (*nplurals != '\0' && isspace (*nplurals))
516 ++nplurals;
517 #if defined HAVE_STRTOUL || defined _LIBC
518 n = strtoul (nplurals, &endp, 10);
519 #else
520 for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
521 n = n * 10 + (*endp - '0');
522 #endif
523 domain->nplurals = n;
524 if (nplurals == endp)
525 goto no_plural;
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. */
531 plural += 7;
532 args.cp = plural;
533 if (PLURAL_PARSE (&args) != 0)
534 goto no_plural;
535 domain->plural = args.res;
538 else
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. */
543 no_plural:
544 INIT_GERMANIC_PLURAL ();
545 domain->plural = &germanic_plural;
546 domain->nplurals = 2;
551 #ifdef _LIBC
552 void
553 internal_function
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);
565 else
566 # endif /* _POSIX_MAPPED_FILES */
567 free ((void *) domain->data);
569 free (domain);
571 #endif