Update.
[glibc.git] / intl / loadmsgcat.c
blob6eed73930b01d7a10f0ca3342061336973e923d1
1 /* Load needed message catalogs.
2 Copyright (C) 1995-1999, 2000, 2001 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. */
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 #if defined STDC_HEADERS || defined _LIBC
37 # include <stdlib.h>
38 #endif
40 #if defined HAVE_STRING_H || defined _LIBC
41 # include <string.h>
42 #else
43 # include <strings.h>
44 #endif
46 #if defined HAVE_UNISTD_H || defined _LIBC
47 # include <unistd.h>
48 #endif
50 #ifdef _LIBC
51 # include <langinfo.h>
52 # include <locale.h>
53 #endif
55 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
56 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
57 # include <sys/mman.h>
58 # undef HAVE_MMAP
59 # define HAVE_MMAP 1
60 #else
61 # undef HAVE_MMAP
62 #endif
64 #include "gettext.h"
65 #include "gettextP.h"
67 #ifdef _LIBC
68 # include "../locale/localeinfo.h"
69 #endif
71 /* @@ end of prolog @@ */
73 #ifdef _LIBC
74 /* Rename the non ISO C functions. This is required by the standard
75 because some ISO C functions will require linking with this object
76 file and the name space must not be polluted. */
77 # define open __open
78 # define close __close
79 # define read __read
80 # define mmap __mmap
81 # define munmap __munmap
82 #endif
84 /* We need a sign, whether a new catalog was loaded, which can be associated
85 with all translations. This is important if the translations are
86 cached by one of GCC's features. */
87 int _nl_msg_cat_cntr;
89 #if defined __GNUC__ \
90 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
92 /* These structs are the constant expression for the germanic plural
93 form determination. It represents the expression "n != 1". */
94 static const struct expression plvar =
96 .operation = var,
98 static const struct expression plone =
100 .operation = num,
101 .val =
103 .num = 1
106 static struct expression germanic_plural =
108 .operation = not_equal,
109 .val =
111 .args2 =
113 .left = (struct expression *) &plvar,
114 .right = (struct expression *) &plone
119 # define INIT_GERMANIC_PLURAL()
121 #else
123 /* For compilers without support for ISO C 99 struct/union initializers:
124 Initialization at run-time. */
126 static struct expression plvar;
127 static struct expression plone;
128 static struct expression germanic_plural;
130 static void
131 init_germanic_plural ()
133 if (plone.val.num == 0)
135 plvar.operation = var;
137 plone.operation = num;
138 plone.val.num = 1;
140 germanic_plural.operation = not_equal;
141 germanic_plural.val.args2.left = &plvar;
142 germanic_plural.val.args2.right = &plone;
146 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
148 #endif
151 /* Load the message catalogs specified by FILENAME. If it is no valid
152 message catalog do nothing. */
153 void
154 internal_function
155 _nl_load_domain (domain_file)
156 struct loaded_l10nfile *domain_file;
158 int fd;
159 size_t size;
160 struct stat64 st;
161 struct mo_file_header *data = (struct mo_file_header *) -1;
162 int use_mmap = 0;
163 struct loaded_domain *domain;
164 char *nullentry;
165 size_t nullentrylen;
167 domain_file->decided = 1;
168 domain_file->data = NULL;
170 /* If the record does not represent a valid locale the FILENAME
171 might be NULL. This can happen when according to the given
172 specification the locale file name is different for XPG and CEN
173 syntax. */
174 if (domain_file->filename == NULL)
175 return;
177 /* Try to open the addressed file. */
178 fd = open (domain_file->filename, O_RDONLY);
179 if (fd == -1)
180 return;
182 /* We must know about the size of the file. */
183 if (__builtin_expect (fstat64 (fd, &st) != 0, 0)
184 || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
185 || __builtin_expect (size < sizeof (struct mo_file_header), 0))
187 /* Something went wrong. */
188 close (fd);
189 return;
192 #ifdef HAVE_MMAP
193 /* Now we are ready to load the file. If mmap() is available we try
194 this first. If not available or it failed we try to load it. */
195 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
196 MAP_PRIVATE, fd, 0);
198 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
200 /* mmap() call was successful. */
201 close (fd);
202 use_mmap = 1;
204 #endif
206 /* If the data is not yet available (i.e. mmap'ed) we try to load
207 it manually. */
208 if (data == (struct mo_file_header *) -1)
210 size_t to_read;
211 char *read_ptr;
213 data = (struct mo_file_header *) malloc (size);
214 if (data == NULL)
215 return;
217 to_read = size;
218 read_ptr = (char *) data;
221 long int nb = (long int) read (fd, read_ptr, to_read);
222 if (nb <= 0)
224 #ifdef EINTR
225 if (nb == -1 && errno == EINTR)
226 continue;
227 #endif
228 close (fd);
229 return;
231 read_ptr += nb;
232 to_read -= nb;
234 while (to_read > 0);
236 close (fd);
239 /* Using the magic number we can test whether it really is a message
240 catalog file. */
241 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
244 /* The magic number is wrong: not a message catalog file. */
245 #ifdef HAVE_MMAP
246 if (use_mmap)
247 munmap ((caddr_t) data, size);
248 else
249 #endif
250 free (data);
251 return;
254 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
255 if (domain == NULL)
256 return;
257 domain_file->data = domain;
259 domain->data = (char *) data;
260 domain->use_mmap = use_mmap;
261 domain->mmap_size = size;
262 domain->must_swap = data->magic != _MAGIC;
264 /* Fill in the information about the available tables. */
265 switch (W (domain->must_swap, data->revision))
267 case 0:
268 domain->nstrings = W (domain->must_swap, data->nstrings);
269 domain->orig_tab = (struct string_desc *)
270 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
271 domain->trans_tab = (struct string_desc *)
272 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
273 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
274 domain->hash_tab = (nls_uint32 *)
275 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
276 break;
277 default:
278 /* This is an invalid revision. */
279 #ifdef HAVE_MMAP
280 if (use_mmap)
281 munmap ((caddr_t) data, size);
282 else
283 #endif
284 free (data);
285 free (domain);
286 domain_file->data = NULL;
287 return;
290 /* Now find out about the character set the file is encoded with.
291 This can be found (in textual form) in the entry "". If this
292 entry does not exist or if this does not contain the `charset='
293 information, we will assume the charset matches the one the
294 current locale and we don't have to perform any conversion. */
295 #ifdef _LIBC
296 domain->conv = (__gconv_t) -1;
297 #else
298 # if HAVE_ICONV
299 domain->conv = (iconv_t) -1;
300 # endif
301 #endif
302 domain->conv_tab = NULL;
303 nullentry = _nl_find_msg (domain_file, "", &nullentrylen);
304 if (nullentry != NULL)
306 #if defined _LIBC || HAVE_ICONV
307 const char *charsetstr;
309 charsetstr = strstr (nullentry, "charset=");
310 if (charsetstr != NULL)
312 size_t len;
313 char *charset;
314 const char *outcharset;
316 charsetstr += strlen ("charset=");
317 len = strcspn (charsetstr, " \t\n");
319 charset = (char *) alloca (len + 1);
320 # if defined _LIBC || HAVE_MEMPCPY
321 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
322 # else
323 memcpy (charset, charsetstr, len);
324 charset[len] = '\0';
325 # endif
327 /* The output charset should normally be determined by the
328 locale. But sometimes the locale is not used or not correctly
329 set up, so we provide a possibility for the user to override
330 this. Moreover, the value specified through
331 bind_textdomain_codeset overrides both. */
332 if (domain_file->domainbinding != NULL
333 && domain_file->domainbinding->codeset != NULL)
334 outcharset = domain_file->domainbinding->codeset;
335 else
337 outcharset = getenv ("OUTPUT_CHARSET");
338 if (outcharset == NULL || outcharset[0] == '\0')
340 # ifdef _LIBC
341 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
342 # else
343 # if HAVE_ICONV
344 extern const char *locale_charset (void);
345 outcharset = locale_charset ();
346 if (outcharset == NULL)
347 outcharset = "";
348 # endif
349 # endif
353 # ifdef _LIBC
354 /* We always want to use transliteration. */
355 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
356 charset = norm_add_slashes (charset, NULL);
357 if (__gconv_open (outcharset, charset, &domain->conv,
358 GCONV_AVOID_NOCONV)
359 != __GCONV_OK)
360 domain->conv = (__gconv_t) -1;
361 # else
362 # if HAVE_ICONV
363 domain->conv = iconv_open (outcharset, charset);
364 # endif
365 # endif
367 #endif /* _LIBC || HAVE_ICONV */
370 /* Also look for a plural specification. */
371 if (nullentry != NULL)
373 const char *plural;
374 const char *nplurals;
376 plural = strstr (nullentry, "plural=");
377 nplurals = strstr (nullentry, "nplurals=");
378 if (plural == NULL || nplurals == NULL)
379 goto no_plural;
380 else
382 /* First get the number. */
383 char *endp;
384 struct parse_args args;
386 nplurals += 9;
387 while (*nplurals != '\0' && isspace (*nplurals))
388 ++nplurals;
389 domain->nplurals = strtoul (nplurals, &endp, 10);
390 if (nplurals == endp)
391 goto no_plural;
393 /* Due to the restrictions bison imposes onto the interface of the
394 scanner function we have to put the input string and the result
395 passed up from the parser into the same structure which address
396 is passed down to the parser. */
397 plural += 7;
398 args.cp = plural;
399 if (__gettextparse (&args) != 0)
400 goto no_plural;
401 domain->plural = args.res;
404 else
406 /* By default we are using the Germanic form: singular form only
407 for `one', the plural form otherwise. Yes, this is also what
408 English is using since English is a Germanic language. */
409 no_plural:
410 INIT_GERMANIC_PLURAL ();
411 domain->plural = &germanic_plural;
412 domain->nplurals = 2;
417 #ifdef _LIBC
418 void
419 internal_function
420 _nl_unload_domain (domain)
421 struct loaded_domain *domain;
423 if (domain->plural != &germanic_plural)
424 __gettext_free_exp (domain->plural);
426 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
427 free (domain->conv_tab);
429 if (domain->conv != (__gconv_t) -1)
430 __gconv_close (domain->conv);
432 # ifdef _POSIX_MAPPED_FILES
433 if (domain->use_mmap)
434 munmap ((caddr_t) domain->data, domain->mmap_size);
435 else
436 # endif /* _POSIX_MAPPED_FILES */
437 free ((void *) domain->data);
439 free (domain);
441 #endif