1 /* Load needed message catalogs.
2 Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library 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 the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, 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. */
23 # define _GNU_SOURCE 1
33 #include <sys/types.h>
36 #if defined STDC_HEADERS || defined _LIBC
40 #if defined HAVE_STRING_H || defined _LIBC
46 #if defined HAVE_UNISTD_H || defined _LIBC
51 # include <langinfo.h>
54 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
55 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
56 # include <sys/mman.h>
67 # include "../locale/localeinfo.h"
70 /* @@ end of prolog @@ */
73 /* Rename the non ISO C functions. This is required by the standard
74 because some ISO C functions will require linking with this object
75 file and the name space must not be polluted. */
77 # define close __close
80 # define munmap __munmap
83 /* We need a sign, whether a new catalog was loaded, which can be associated
84 with all translations. This is important if the translations are
85 cached by one of GCC's features. */
88 /* These structs are the constant expression for the germanic plural
89 form determination. */
90 static const struct expression plvar =
94 static const struct expression plone =
102 static struct expression germanic_plural =
104 .operation = not_equal,
108 .left = (struct expression *) &plvar,
109 .right = (struct expression *) &plone
115 /* Load the message catalogs specified by FILENAME. If it is no valid
116 message catalog do nothing. */
119 _nl_load_domain (domain_file)
120 struct loaded_l10nfile *domain_file;
125 struct mo_file_header *data = (struct mo_file_header *) -1;
127 struct loaded_domain *domain;
130 domain_file->decided = 1;
131 domain_file->data = NULL;
133 /* If the record does not represent a valid locale the FILENAME
134 might be NULL. This can happen when according to the given
135 specification the locale file name is different for XPG and CEN
137 if (domain_file->filename == NULL)
140 /* Try to open the addressed file. */
141 fd = open (domain_file->filename, O_RDONLY);
145 /* We must know about the size of the file. */
146 if (__builtin_expect (fstat (fd, &st) != 0, 0)
147 || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
148 || __builtin_expect (size < sizeof (struct mo_file_header), 0))
150 /* Something went wrong. */
156 /* Now we are ready to load the file. If mmap() is available we try
157 this first. If not available or it failed we try to load it. */
158 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
161 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
163 /* mmap() call was successful. */
169 /* If the data is not yet available (i.e. mmap'ed) we try to load
171 if (data == (struct mo_file_header *) -1)
176 data = (struct mo_file_header *) malloc (size);
181 read_ptr = (char *) data;
184 long int nb = (long int) read (fd, read_ptr, to_read);
188 if (nb == -1 && errno == EINTR)
202 /* Using the magic number we can test whether it really is a message
204 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
207 /* The magic number is wrong: not a message catalog file. */
210 munmap ((caddr_t) data, size);
218 = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
219 if (domain_file->data == NULL)
222 domain = (struct loaded_domain *) domain_file->data;
223 domain->data = (char *) data;
224 domain->use_mmap = use_mmap;
225 domain->mmap_size = size;
226 domain->must_swap = data->magic != _MAGIC;
228 /* Fill in the information about the available tables. */
229 switch (W (domain->must_swap, data->revision))
232 domain->nstrings = W (domain->must_swap, data->nstrings);
233 domain->orig_tab = (struct string_desc *)
234 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
235 domain->trans_tab = (struct string_desc *)
236 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
237 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
238 domain->hash_tab = (nls_uint32 *)
239 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
242 /* This is an invalid revision. */
245 munmap ((caddr_t) data, size);
250 domain_file->data = NULL;
254 /* Now find out about the character set the file is encoded with.
255 This can be found (in textual form) in the entry "". If this
256 entry does not exist or if this does not contain the `charset='
257 information, we will assume the charset matches the one the
258 current locale and we don't have to perform any conversion. */
260 domain->conv = (__gconv_t) -1;
263 domain->conv = (iconv_t) -1;
266 domain->conv_tab = NULL;
267 nullentry = _nl_find_msg (domain_file, "", 0);
268 if (nullentry != NULL)
270 #if defined _LIBC || HAVE_ICONV
271 const char *charsetstr;
273 charsetstr = strstr (nullentry, "charset=");
274 if (charsetstr != NULL)
278 const char *outcharset;
280 charsetstr += strlen ("charset=");
281 len = strcspn (charsetstr, " \t\n");
283 charset = (char *) alloca (len + 1);
284 # if defined _LIBC || HAVE_MEMPCPY
285 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
287 memcpy (charset, charsetstr, len);
291 /* The output charset should normally be determined by the
292 locale. But sometimes the locale is not used or not correctly
293 set up, so we provide a possibility for the user to override
294 this. Moreover, the value specified through
295 bind_textdomain_codeset overrides both. */
296 if (domain_file->domainbinding != NULL
297 && domain_file->domainbinding->codeset != NULL)
298 outcharset = domain_file->domainbinding->codeset;
301 outcharset = getenv ("OUTPUT_CHARSET");
302 if (outcharset == NULL || outcharset[0] == '\0')
305 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
308 extern const char *locale_charset (void);
309 outcharset = locale_charset ();
310 if (outcharset == NULL)
318 /* We always want to use transliteration. */
319 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
320 charset = norm_add_slashes (charset, NULL);
321 if (__gconv_open (outcharset, charset, &domain->conv,
324 domain->conv = (__gconv_t) -1;
327 domain->conv = iconv_open (outcharset, charset);
331 #endif /* _LIBC || HAVE_ICONV */
334 /* Also look for a plural specification. */
335 if (nullentry != NULL)
338 const char *nplurals;
340 plural = strstr (nullentry, "plural=");
341 nplurals = strstr (nullentry, "nplurals=");
342 if (plural == NULL || nplurals == NULL)
346 /* First get the number. */
348 struct parse_args args;
351 while (*nplurals != '\0' && isspace (*nplurals))
353 domain->nplurals = strtoul (nplurals, &endp, 10);
354 if (nplurals == endp)
357 /* Due to the restrictions bison imposes onto the interface of the
358 scanner function we have to put the input string and the result
359 passed up from the parser into the same structure which address
360 is passed down to the parser. */
363 if (__gettextparse (&args) != 0)
365 domain->plural = args.res;
370 /* By default we are using the Germanic form: singular form only
371 for `one', the plural form otherwise. Yes, this is also what
372 English is using since English is a Germanic language. */
374 domain->plural = &germanic_plural;
375 domain->nplurals = 2;
383 _nl_unload_domain (domain)
384 struct loaded_domain *domain;
386 if (domain->plural != &germanic_plural)
387 __gettext_free_exp (domain->plural);
390 if (domain->conv != (__gconv_t) -1)
391 __gconv_close (domain->conv);
394 if (domain->conv != (iconv_t) -1)
395 iconv_close (domain->conv);
399 #ifdef _POSIX_MAPPED_FILES
400 if (domain->use_mmap)
401 munmap ((caddr_t) domain->data, domain->mmap_size);
403 #endif /* _POSIX_MAPPED_FILES */
404 free ((void *) domain->data);