FSF GCC merge 02/23/03
[official-gcc.git] / gcc / intl / loadmsgcat.c
blobbf444f6ddd48192e81dc7510444ae959fc2e6393
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 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)
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 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,
17 USA. */
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
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
36 #ifdef __GNUC__
37 # define alloca __builtin_alloca
38 # define HAVE_ALLOCA 1
39 #else
40 # if defined HAVE_ALLOCA_H || defined _LIBC
41 # include <alloca.h>
42 # else
43 # ifdef _AIX
44 #pragma alloca
45 # else
46 # ifndef alloca
47 char *alloca ();
48 # endif
49 # endif
50 # endif
51 #endif
53 #include <stdlib.h>
54 #include <string.h>
56 #if defined HAVE_UNISTD_H || defined _LIBC
57 # include <unistd.h>
58 #endif
60 #ifdef _LIBC
61 # include <langinfo.h>
62 # include <locale.h>
63 #endif
65 #if (defined HAVE_MMAP_FILE && !defined DISALLOW_MMAP) \
66 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
67 # include <sys/mman.h>
68 # undef HAVE_MMAP
69 # define HAVE_MMAP 1
70 #else
71 # undef HAVE_MMAP
72 #endif
74 #include "gettext.h"
75 #include "gettextP.h"
77 #ifdef _LIBC
78 # include "../locale/localeinfo.h"
79 #endif
81 /* GCC LOCAL: These macros are used below. */
82 /* The extra casts work around common compiler bugs. */
83 #define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1))
84 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
85 It is necessary at least when t == time_t. */
86 #define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \
87 ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0))
88 #define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t)))
90 /* @@ end of prolog @@ */
92 #ifdef _LIBC
93 /* Rename the non ISO C functions. This is required by the standard
94 because some ISO C functions will require linking with this object
95 file and the name space must not be polluted. */
96 # define open __open
97 # define close __close
98 # define read __read
99 # define mmap __mmap
100 # define munmap __munmap
101 #endif
103 /* Names for the libintl functions are a problem. They must not clash
104 with existing names and they should follow ANSI C. But this source
105 code is also used in GNU C Library where the names have a __
106 prefix. So we have to make a difference here. */
107 #ifdef _LIBC
108 # define PLURAL_PARSE __gettextparse
109 #else
110 # define PLURAL_PARSE gettextparse__
111 #endif
113 /* For those losing systems which don't have `alloca' we have to add
114 some additional code emulating it. */
115 #ifdef HAVE_ALLOCA
116 # define freea(p) /* nothing */
117 #else
118 # define alloca(n) malloc (n)
119 # define freea(p) free (p)
120 #endif
122 /* For systems that distinguish between text and binary I/O.
123 O_BINARY is usually declared in <fcntl.h>. */
124 #if !defined O_BINARY && defined _O_BINARY
125 /* For MSC-compatible compilers. */
126 # define O_BINARY _O_BINARY
127 # define O_TEXT _O_TEXT
128 #endif
129 #ifdef __BEOS__
130 /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
131 # undef O_BINARY
132 # undef O_TEXT
133 #endif
134 /* On reasonable systems, binary I/O is the default. */
135 #ifndef O_BINARY
136 # define O_BINARY 0
137 #endif
139 /* We need a sign, whether a new catalog was loaded, which can be associated
140 with all translations. This is important if the translations are
141 cached by one of GCC's features. */
142 int _nl_msg_cat_cntr;
144 #if (defined __GNUC__ && !defined __APPLE_CC__) \
145 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
147 /* These structs are the constant expression for the germanic plural
148 form determination. It represents the expression "n != 1".
149 GCC LOCAL: Use __extension__ to suppress -Wtraditional warnings. */
150 __extension__ static const struct expression plvar =
152 .nargs = 0,
153 .operation = var,
155 __extension__ static const struct expression plone =
157 .nargs = 0,
158 .operation = num,
159 .val =
161 .num = 1
164 __extension__ static struct expression germanic_plural =
166 .nargs = 2,
167 .operation = not_equal,
168 .val =
170 .args =
172 [0] = (struct expression *) &plvar,
173 [1] = (struct expression *) &plone
178 # define INIT_GERMANIC_PLURAL()
180 #else
182 /* For compilers without support for ISO C 99 struct/union initializers:
183 Initialization at run-time. */
185 static struct expression plvar;
186 static struct expression plone;
187 static struct expression germanic_plural;
189 static void
190 init_germanic_plural ()
192 if (plone.val.num == 0)
194 plvar.nargs = 0;
195 plvar.operation = var;
197 plone.nargs = 0;
198 plone.operation = num;
199 plone.val.num = 1;
201 germanic_plural.nargs = 2;
202 germanic_plural.operation = not_equal;
203 germanic_plural.val.args[0] = &plvar;
204 germanic_plural.val.args[1] = &plone;
208 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
210 #endif
213 /* Initialize the codeset dependent parts of an opened message catalog.
214 Return the header entry. */
215 const char *
216 internal_function
217 _nl_init_domain_conv (domain_file, domain, domainbinding)
218 struct loaded_l10nfile *domain_file;
219 struct loaded_domain *domain;
220 struct binding *domainbinding;
222 /* Find out about the character set the file is encoded with.
223 This can be found (in textual form) in the entry "". If this
224 entry does not exist or if this does not contain the `charset='
225 information, we will assume the charset matches the one the
226 current locale and we don't have to perform any conversion. */
227 char *nullentry;
228 size_t nullentrylen;
230 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
231 domain->codeset_cntr =
232 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
233 #ifdef _LIBC
234 domain->conv = (__gconv_t) -1;
235 #else
236 # if HAVE_ICONV
237 domain->conv = (iconv_t) -1;
238 # endif
239 #endif
240 domain->conv_tab = NULL;
242 /* Get the header entry. */
243 nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
245 if (nullentry != NULL)
247 #if defined _LIBC || HAVE_ICONV
248 const char *charsetstr;
250 charsetstr = strstr (nullentry, "charset=");
251 if (charsetstr != NULL)
253 size_t len;
254 char *charset;
255 const char *outcharset;
257 charsetstr += strlen ("charset=");
258 len = strcspn (charsetstr, " \t\n");
260 charset = (char *) alloca (len + 1);
261 # if defined _LIBC || HAVE_MEMPCPY
262 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
263 # else
264 memcpy (charset, charsetstr, len);
265 charset[len] = '\0';
266 # endif
268 /* The output charset should normally be determined by the
269 locale. But sometimes the locale is not used or not correctly
270 set up, so we provide a possibility for the user to override
271 this. Moreover, the value specified through
272 bind_textdomain_codeset overrides both. */
273 if (domainbinding != NULL && domainbinding->codeset != NULL)
274 outcharset = domainbinding->codeset;
275 else
277 outcharset = getenv ("OUTPUT_CHARSET");
278 if (outcharset == NULL || outcharset[0] == '\0')
280 # ifdef _LIBC
281 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
282 # else
283 # if HAVE_ICONV
284 outcharset = locale_charset ();
285 # endif
286 # endif
290 # ifdef _LIBC
291 /* We always want to use transliteration. */
292 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
293 charset = norm_add_slashes (charset, NULL);
294 if (__gconv_open (outcharset, charset, &domain->conv,
295 GCONV_AVOID_NOCONV)
296 != __GCONV_OK)
297 domain->conv = (__gconv_t) -1;
298 # else
299 # if HAVE_ICONV
300 /* When using GNU libiconv, we want to use transliteration. */
301 # if _LIBICONV_VERSION >= 0x0105
302 len = strlen (outcharset);
304 char *tmp = (char *) alloca (len + 10 + 1);
305 memcpy (tmp, outcharset, len);
306 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
307 outcharset = tmp;
309 # endif
310 domain->conv = iconv_open (outcharset, charset);
311 # if _LIBICONV_VERSION >= 0x0105
312 freea (outcharset);
313 # endif
314 # endif
315 # endif
317 freea (charset);
319 #endif /* _LIBC || HAVE_ICONV */
322 return nullentry;
325 /* Frees the codeset dependent parts of an opened message catalog. */
326 void
327 internal_function
328 _nl_free_domain_conv (domain)
329 struct loaded_domain *domain;
331 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
332 free (domain->conv_tab);
334 #ifdef _LIBC
335 if (domain->conv != (__gconv_t) -1)
336 __gconv_close (domain->conv);
337 #else
338 # if HAVE_ICONV
339 if (domain->conv != (iconv_t) -1)
340 iconv_close (domain->conv);
341 # endif
342 #endif
345 /* Load the message catalogs specified by FILENAME. If it is no valid
346 message catalog do nothing. */
347 void
348 internal_function
349 _nl_load_domain (domain_file, domainbinding)
350 struct loaded_l10nfile *domain_file;
351 struct binding *domainbinding;
353 int fd;
354 size_t size;
355 #ifdef _LIBC
356 struct stat64 st;
357 #else
358 struct stat st;
359 #endif
360 struct mo_file_header *data = (struct mo_file_header *) -1;
361 int use_mmap = 0;
362 struct loaded_domain *domain;
363 const char *nullentry;
365 domain_file->decided = 1;
366 domain_file->data = NULL;
368 /* Note that it would be useless to store domainbinding in domain_file
369 because domainbinding might be == NULL now but != NULL later (after
370 a call to bind_textdomain_codeset). */
372 /* If the record does not represent a valid locale the FILENAME
373 might be NULL. This can happen when according to the given
374 specification the locale file name is different for XPG and CEN
375 syntax. */
376 if (domain_file->filename == NULL)
377 return;
379 /* Try to open the addressed file. */
380 fd = open (domain_file->filename, O_RDONLY | O_BINARY);
381 if (fd == -1)
382 return;
384 /* We must know about the size of the file. */
385 /* GCC_LOCAL: Use INTTYPE_MAXIMUM for overflow check, cast sizeof to
386 off_t, move set of size below if. */
387 if (
388 #ifdef _LIBC
389 __builtin_expect (fstat64 (fd, &st) != 0, 0)
390 #else
391 __builtin_expect (fstat (fd, &st) != 0, 0)
392 #endif
393 || __builtin_expect (st.st_size > INTTYPE_MAXIMUM (ssize_t), 0)
394 || __builtin_expect (st.st_size < (off_t) sizeof (struct mo_file_header),
397 /* Something went wrong. */
398 close (fd);
399 return;
401 size = (size_t) st.st_size;
403 #ifdef HAVE_MMAP
404 /* Now we are ready to load the file. If mmap() is available we try
405 this first. If not available or it failed we try to load it. */
406 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
407 MAP_PRIVATE, fd, 0);
409 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
411 /* mmap() call was successful. */
412 close (fd);
413 use_mmap = 1;
415 #endif
417 /* If the data is not yet available (i.e. mmap'ed) we try to load
418 it manually. */
419 if (data == (struct mo_file_header *) -1)
421 size_t to_read;
422 char *read_ptr;
424 data = (struct mo_file_header *) malloc (size);
425 if (data == NULL)
426 return;
428 to_read = size;
429 read_ptr = (char *) data;
432 long int nb = (long int) read (fd, read_ptr, to_read);
433 if (nb <= 0)
435 #ifdef EINTR
436 if (nb == -1 && errno == EINTR)
437 continue;
438 #endif
439 close (fd);
440 return;
442 read_ptr += nb;
443 to_read -= nb;
445 while (to_read > 0);
447 close (fd);
450 /* Using the magic number we can test whether it really is a message
451 catalog file. */
452 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
455 /* The magic number is wrong: not a message catalog file. */
456 #ifdef HAVE_MMAP
457 if (use_mmap)
458 munmap ((caddr_t) data, size);
459 else
460 #endif
461 free (data);
462 return;
465 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
466 if (domain == NULL)
467 return;
468 domain_file->data = domain;
470 domain->data = (char *) data;
471 domain->use_mmap = use_mmap;
472 domain->mmap_size = size;
473 domain->must_swap = data->magic != _MAGIC;
475 /* Fill in the information about the available tables. */
476 switch (W (domain->must_swap, data->revision))
478 case 0:
479 domain->nstrings = W (domain->must_swap, data->nstrings);
480 domain->orig_tab = (struct string_desc *)
481 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
482 domain->trans_tab = (struct string_desc *)
483 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
484 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
485 domain->hash_tab = (nls_uint32 *)
486 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
487 break;
488 default:
489 /* This is an invalid revision. */
490 #ifdef HAVE_MMAP
491 if (use_mmap)
492 munmap ((caddr_t) data, size);
493 else
494 #endif
495 free (data);
496 free (domain);
497 domain_file->data = NULL;
498 return;
501 /* Now initialize the character set converter from the character set
502 the file is encoded with (found in the header entry) to the domain's
503 specified character set or the locale's character set. */
504 nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
506 /* Also look for a plural specification. */
507 if (nullentry != NULL)
509 const char *plural;
510 const char *nplurals;
512 plural = strstr (nullentry, "plural=");
513 nplurals = strstr (nullentry, "nplurals=");
514 if (plural == NULL || nplurals == NULL)
515 goto no_plural;
516 else
518 /* First get the number. */
519 char *endp;
520 unsigned long int n;
521 struct parse_args args;
523 nplurals += 9;
524 while (*nplurals != '\0' && isspace ((unsigned char)*nplurals))
525 ++nplurals;
526 #if defined HAVE_STRTOUL || defined _LIBC
527 n = strtoul (nplurals, &endp, 10);
528 #else
529 for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
530 n = n * 10 + (*endp - '0');
531 #endif
532 domain->nplurals = n;
533 if (nplurals == endp)
534 goto no_plural;
536 /* Due to the restrictions bison imposes onto the interface of the
537 scanner function we have to put the input string and the result
538 passed up from the parser into the same structure which address
539 is passed down to the parser. */
540 plural += 7;
541 args.cp = plural;
542 if (PLURAL_PARSE (&args) != 0)
543 goto no_plural;
544 domain->plural = args.res;
547 else
549 /* By default we are using the Germanic form: singular form only
550 for `one', the plural form otherwise. Yes, this is also what
551 English is using since English is a Germanic language. */
552 no_plural:
553 INIT_GERMANIC_PLURAL ();
554 domain->plural = &germanic_plural;
555 domain->nplurals = 2;
560 #ifdef _LIBC
561 void
562 internal_function
563 _nl_unload_domain (domain)
564 struct loaded_domain *domain;
566 if (domain->plural != &germanic_plural)
567 __gettext_free_exp (domain->plural);
569 _nl_free_domain_conv (domain);
571 # ifdef _POSIX_MAPPED_FILES
572 if (domain->use_mmap)
573 munmap ((caddr_t) domain->data, domain->mmap_size);
574 else
575 # endif /* _POSIX_MAPPED_FILES */
576 free ((void *) domain->data);
578 free (domain);
580 #endif