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
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. */
24 # define _GNU_SOURCE 1
34 #include <sys/types.h>
38 # define alloca __builtin_alloca
39 # define HAVE_ALLOCA 1
41 # if defined HAVE_ALLOCA_H || defined _LIBC
54 #if defined STDC_HEADERS || defined _LIBC
58 #if defined HAVE_STRING_H || defined _LIBC
64 #if defined HAVE_UNISTD_H || defined _LIBC
69 # include <langinfo.h>
73 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
74 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
75 # include <sys/mman.h>
86 # include "../locale/localeinfo.h"
89 /* @@ end of prolog @@ */
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. */
96 # define close __close
99 # define munmap __munmap
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. */
107 # define PLURAL_PARSE __gettextparse
109 # define PLURAL_PARSE gettextparse__
112 /* For those losing systems which don't have `alloca' we have to add
113 some additional code emulating it. */
115 # define freea(p) /* nothing */
117 # define alloca(n) malloc (n)
118 # define freea(p) free (p)
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
=
136 static const struct expression plone
=
145 static struct expression germanic_plural
=
148 .operation
= not_equal
,
153 [0] = (struct expression
*) &plvar
,
154 [1] = (struct expression
*) &plone
159 # define INIT_GERMANIC_PLURAL()
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
;
171 init_germanic_plural ()
173 if (plone
.val
.num
== 0)
176 plvar
.operation
= var
;
179 plone
.operation
= num
;
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 ()
194 /* Initialize the codeset dependent parts of an opened message catalog.
195 Return the header entry. */
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. */
211 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
212 domain
->codeset_cntr
=
213 (domainbinding
!= NULL
? domainbinding
->codeset_cntr
: 0);
215 domain
->conv
= (__gconv_t
) -1;
218 domain
->conv
= (iconv_t
) -1;
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
)
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';
245 memcpy (charset
, charsetstr
, len
);
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
;
258 outcharset
= getenv ("OUTPUT_CHARSET");
259 if (outcharset
== NULL
|| outcharset
[0] == '\0')
262 outcharset
= (*_nl_current
[LC_CTYPE
])->values
[_NL_ITEM_INDEX (CODESET
)].string
;
265 extern const char *locale_charset (void);
266 outcharset
= locale_charset ();
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
,
279 domain
->conv
= (__gconv_t
) -1;
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);
292 domain
->conv
= iconv_open (outcharset
, charset
);
293 # if _LIBICONV_VERSION
301 #endif /* _LIBC || HAVE_ICONV */
307 /* Frees the codeset dependent parts of an opened message catalog. */
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
);
317 if (domain
->conv
!= (__gconv_t
) -1)
318 __gconv_close (domain
->conv
);
321 if (domain
->conv
!= (iconv_t
) -1)
322 iconv_close (domain
->conv
);
327 /* Load the message catalogs specified by FILENAME. If it is no valid
328 message catalog do nothing. */
331 _nl_load_domain (domain_file
, domainbinding
)
332 struct loaded_l10nfile
*domain_file
;
333 struct binding
*domainbinding
;
342 struct mo_file_header
*data
= (struct mo_file_header
*) -1;
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
358 if (domain_file
->filename
== NULL
)
361 /* Try to open the addressed file. */
362 fd
= open (domain_file
->filename
, O_RDONLY
);
366 /* We must know about the size of the file. */
369 __builtin_expect (fstat64 (fd
, &st
) != 0, 0)
371 __builtin_expect (fstat (fd
, &st
) != 0, 0)
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. */
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
,
387 if (__builtin_expect (data
!= (struct mo_file_header
*) -1, 1))
389 /* mmap() call was successful. */
395 /* If the data is not yet available (i.e. mmap'ed) we try to load
397 if (data
== (struct mo_file_header
*) -1)
402 data
= (struct mo_file_header
*) malloc (size
);
407 read_ptr
= (char *) data
;
410 long int nb
= (long int) read (fd
, read_ptr
, to_read
);
414 if (nb
== -1 && errno
== EINTR
)
428 /* Using the magic number we can test whether it really is a message
430 if (__builtin_expect (data
->magic
!= _MAGIC
&& data
->magic
!= _MAGIC_SWAPPED
,
433 /* The magic number is wrong: not a message catalog file. */
436 munmap ((caddr_t
) data
, size
);
443 domain
= (struct loaded_domain
*) malloc (sizeof (struct loaded_domain
));
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
))
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
));
467 /* This is an invalid revision. */
470 munmap ((caddr_t
) data
, size
);
475 domain_file
->data
= NULL
;
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
)
488 const char *nplurals
;
490 plural
= strstr (nullentry
, "plural=");
491 nplurals
= strstr (nullentry
, "nplurals=");
492 if (plural
== NULL
|| nplurals
== NULL
)
496 /* First get the number. */
499 struct parse_args args
;
502 while (*nplurals
!= '\0' && isspace (*nplurals
))
504 #if defined HAVE_STRTOUL || defined _LIBC
505 n
= strtoul (nplurals
, &endp
, 10);
507 for (endp
= nplurals
, n
= 0; *endp
>= '0' && *endp
<= '9'; endp
++)
508 n
= n
* 10 + (*endp
- '0');
510 domain
->nplurals
= n
;
511 if (nplurals
== endp
)
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. */
520 if (PLURAL_PARSE (&args
) != 0)
522 domain
->plural
= args
.res
;
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. */
531 INIT_GERMANIC_PLURAL ();
532 domain
->plural
= &germanic_plural
;
533 domain
->nplurals
= 2;
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
);
553 # endif /* _POSIX_MAPPED_FILES */
554 free ((void *) domain
->data
);