Update.
[glibc.git] / intl / loadmsgcat.c
blob4009525fe861dfce521b4ef49830fb3510475cd4
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. */
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 #endif
54 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
55 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
56 # include <sys/mman.h>
57 # undef HAVE_MMAP
58 # define HAVE_MMAP 1
59 #else
60 # undef HAVE_MMAP
61 #endif
63 #include "gettext.h"
64 #include "gettextP.h"
66 #ifdef _LIBC
67 # include "../locale/localeinfo.h"
68 #endif
70 /* @@ end of prolog @@ */
72 #ifdef _LIBC
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. */
76 # define open __open
77 # define close __close
78 # define read __read
79 # define mmap __mmap
80 # define munmap __munmap
81 #endif
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. */
86 int _nl_msg_cat_cntr;
88 /* These structs are the constant expression for the germanic plural
89 form determination. */
90 static const struct expression plvar =
92 .operation = var,
94 static const struct expression plone =
96 .operation = num,
97 .val =
99 .num = 1
102 static struct expression germanic_plural =
104 .operation = not_equal,
105 .val =
107 .args2 = {
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. */
117 void
118 internal_function
119 _nl_load_domain (domain_file)
120 struct loaded_l10nfile *domain_file;
122 int fd;
123 size_t size;
124 struct stat st;
125 struct mo_file_header *data = (struct mo_file_header *) -1;
126 int use_mmap = 0;
127 struct loaded_domain *domain;
128 char *nullentry;
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
136 syntax. */
137 if (domain_file->filename == NULL)
138 return;
140 /* Try to open the addressed file. */
141 fd = open (domain_file->filename, O_RDONLY);
142 if (fd == -1)
143 return;
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. */
151 close (fd);
152 return;
155 #ifdef HAVE_MMAP
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,
159 MAP_PRIVATE, fd, 0);
161 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
163 /* mmap() call was successful. */
164 close (fd);
165 use_mmap = 1;
167 #endif
169 /* If the data is not yet available (i.e. mmap'ed) we try to load
170 it manually. */
171 if (data == (struct mo_file_header *) -1)
173 size_t to_read;
174 char *read_ptr;
176 data = (struct mo_file_header *) malloc (size);
177 if (data == NULL)
178 return;
180 to_read = size;
181 read_ptr = (char *) data;
184 long int nb = (long int) read (fd, read_ptr, to_read);
185 if (nb <= 0)
187 #ifdef EINTR
188 if (nb == -1 && errno == EINTR)
189 continue;
190 #endif
191 close (fd);
192 return;
194 read_ptr += nb;
195 to_read -= nb;
197 while (to_read > 0);
199 close (fd);
202 /* Using the magic number we can test whether it really is a message
203 catalog file. */
204 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
207 /* The magic number is wrong: not a message catalog file. */
208 #ifdef HAVE_MMAP
209 if (use_mmap)
210 munmap ((caddr_t) data, size);
211 else
212 #endif
213 free (data);
214 return;
217 domain_file->data
218 = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
219 if (domain_file->data == NULL)
220 return;
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))
231 case 0:
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));
240 break;
241 default:
242 /* This is an invalid revision. */
243 #ifdef HAVE_MMAP
244 if (use_mmap)
245 munmap ((caddr_t) data, size);
246 else
247 #endif
248 free (data);
249 free (domain);
250 domain_file->data = NULL;
251 return;
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. */
259 #ifdef _LIBC
260 domain->conv = (__gconv_t) -1;
261 #else
262 # if HAVE_ICONV
263 domain->conv = (iconv_t) -1;
264 # endif
265 #endif
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)
276 size_t len;
277 char *charset;
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';
286 # else
287 memcpy (charset, charsetstr, len);
288 charset[len] = '\0';
289 # endif
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;
299 else
301 outcharset = getenv ("OUTPUT_CHARSET");
302 if (outcharset == NULL || outcharset[0] == '\0')
304 # ifdef _LIBC
305 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
306 # else
307 # if HAVE_ICONV
308 extern const char *locale_charset (void);
309 outcharset = locale_charset ();
310 if (outcharset == NULL)
311 outcharset = "";
312 # endif
313 # endif
317 # ifdef _LIBC
318 outcharset = norm_add_slashes (outcharset);
319 charset = norm_add_slashes (charset);
320 if (__gconv_open (outcharset, charset, &domain->conv,
321 GCONV_AVOID_NOCONV)
322 != __GCONV_OK)
323 domain->conv = (__gconv_t) -1;
324 # else
325 # if HAVE_ICONV
326 domain->conv = iconv_open (outcharset, charset);
327 # endif
328 # endif
330 #endif /* _LIBC || HAVE_ICONV */
333 /* Also look for a plural specification. */
334 if (nullentry != NULL)
336 const char *plural;
337 const char *nplurals;
339 plural = strstr (nullentry, "plural=");
340 nplurals = strstr (nullentry, "nplurals=");
341 if (plural == NULL || nplurals == NULL)
342 goto no_plural;
343 else
345 /* First get the number. */
346 char *endp;
347 struct parse_args args;
349 nplurals += 9;
350 while (*nplurals != '\0' && isspace (*nplurals))
351 ++nplurals;
352 domain->nplurals = strtoul (nplurals, &endp, 10);
353 if (nplurals == endp)
354 goto no_plural;
356 /* Due to the restrictions bison imposes onto the interface of the
357 scanner function we have to put the input string and the result
358 passed up from the parser into the same structure which address
359 is passed down to the parser. */
360 plural += 7;
361 args.cp = plural;
362 if (__gettextparse (&args) != 0)
363 goto no_plural;
364 domain->plural = args.res;
367 else
369 /* By default we are using the Germanic form: singular form only
370 for `one', the plural form otherwise. Yes, this is also what
371 English is using since English is a Germanic language. */
372 no_plural:
373 domain->plural = &germanic_plural;
374 domain->nplurals = 2;
379 #ifdef _LIBC
380 void
381 internal_function
382 _nl_unload_domain (domain)
383 struct loaded_domain *domain;
385 if (domain->plural != &germanic_plural)
386 __gettext_free_exp (domain->plural);
388 #ifdef _LIBC
389 if (domain->conv != (__gconv_t) -1)
390 __gconv_close (domain->conv);
391 #else
392 # if HAVE_ICONV
393 if (domain->conv != (iconv_t) -1)
394 iconv_close (domain->conv);
395 # endif
396 #endif
398 #ifdef _POSIX_MAPPED_FILES
399 if (domain->use_mmap)
400 munmap ((caddr_t) domain->data, domain->mmap_size);
401 else
402 #endif /* _POSIX_MAPPED_FILES */
403 free ((void *) domain->data);
405 free (domain);
407 #endif