Update.
[glibc.git] / intl / loadmsgcat.c
blob41f56500b8aafa4d197877e5c858228bc552a0aa
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
18 02111-1307 USA. */
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. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #ifdef __GNUC__
38 # define alloca __builtin_alloca
39 # define HAVE_ALLOCA 1
40 #else
41 # if defined HAVE_ALLOCA_H || defined _LIBC
42 # include <alloca.h>
43 # else
44 # ifdef _AIX
45 #pragma alloca
46 # else
47 # ifndef alloca
48 char *alloca ();
49 # endif
50 # endif
51 # endif
52 #endif
54 #include <stdlib.h>
55 #include <string.h>
57 #if defined HAVE_UNISTD_H || defined _LIBC
58 # include <unistd.h>
59 #endif
61 #ifdef _LIBC
62 # include <langinfo.h>
63 # include <locale.h>
64 #endif
66 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
67 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
68 # include <sys/mman.h>
69 # undef HAVE_MMAP
70 # define HAVE_MMAP 1
71 #else
72 # undef HAVE_MMAP
73 #endif
75 #include "gettext.h"
76 #include "gettextP.h"
77 #include "plural-exp.h"
79 #ifdef _LIBC
80 # include "../locale/localeinfo.h"
81 #endif
83 /* @@ end of prolog @@ */
85 #ifdef _LIBC
86 /* Rename the non ISO C functions. This is required by the standard
87 because some ISO C functions will require linking with this object
88 file and the name space must not be polluted. */
89 # define open __open
90 # define close __close
91 # define read __read
92 # define mmap __mmap
93 # define munmap __munmap
94 #endif
96 /* For those losing systems which don't have `alloca' we have to add
97 some additional code emulating it. */
98 #ifdef HAVE_ALLOCA
99 # define freea(p) /* nothing */
100 #else
101 # define alloca(n) malloc (n)
102 # define freea(p) free (p)
103 #endif
105 /* We need a sign, whether a new catalog was loaded, which can be associated
106 with all translations. This is important if the translations are
107 cached by one of GCC's features. */
108 int _nl_msg_cat_cntr;
111 /* Initialize the codeset dependent parts of an opened message catalog.
112 Return the header entry. */
113 const char *
114 internal_function
115 _nl_init_domain_conv (domain_file, domain, domainbinding)
116 struct loaded_l10nfile *domain_file;
117 struct loaded_domain *domain;
118 struct binding *domainbinding;
120 /* Find out about the character set the file is encoded with.
121 This can be found (in textual form) in the entry "". If this
122 entry does not exist or if this does not contain the `charset='
123 information, we will assume the charset matches the one the
124 current locale and we don't have to perform any conversion. */
125 char *nullentry;
126 size_t nullentrylen;
128 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
129 domain->codeset_cntr =
130 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
131 #ifdef _LIBC
132 domain->conv = (__gconv_t) -1;
133 #else
134 # if HAVE_ICONV
135 domain->conv = (iconv_t) -1;
136 # endif
137 #endif
138 domain->conv_tab = NULL;
140 /* Get the header entry. */
141 nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
143 if (nullentry != NULL)
145 #if defined _LIBC || HAVE_ICONV
146 const char *charsetstr;
148 charsetstr = strstr (nullentry, "charset=");
149 if (charsetstr != NULL)
151 size_t len;
152 char *charset;
153 const char *outcharset;
155 charsetstr += strlen ("charset=");
156 len = strcspn (charsetstr, " \t\n");
158 charset = (char *) alloca (len + 1);
159 # if defined _LIBC || HAVE_MEMPCPY
160 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
161 # else
162 memcpy (charset, charsetstr, len);
163 charset[len] = '\0';
164 # endif
166 /* The output charset should normally be determined by the
167 locale. But sometimes the locale is not used or not correctly
168 set up, so we provide a possibility for the user to override
169 this. Moreover, the value specified through
170 bind_textdomain_codeset overrides both. */
171 if (domainbinding != NULL && domainbinding->codeset != NULL)
172 outcharset = domainbinding->codeset;
173 else
175 outcharset = getenv ("OUTPUT_CHARSET");
176 if (outcharset == NULL || outcharset[0] == '\0')
178 # ifdef _LIBC
179 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
180 # else
181 # if HAVE_ICONV
182 extern const char *locale_charset (void);
183 outcharset = locale_charset ();
184 # endif
185 # endif
189 # ifdef _LIBC
190 /* We always want to use transliteration. */
191 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
192 charset = norm_add_slashes (charset, NULL);
193 if (__gconv_open (outcharset, charset, &domain->conv,
194 GCONV_AVOID_NOCONV)
195 != __GCONV_OK)
196 domain->conv = (__gconv_t) -1;
197 # else
198 # if HAVE_ICONV
199 /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
200 we want to use transliteration. */
201 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
202 || _LIBICONV_VERSION >= 0x0105
203 len = strlen (outcharset);
205 char *tmp = (char *) alloca (len + 10 + 1);
206 memcpy (tmp, outcharset, len);
207 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
208 outcharset = tmp;
210 # endif
211 domain->conv = iconv_open (outcharset, charset);
212 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
213 || _LIBICONV_VERSION >= 0x0105
214 freea (outcharset);
215 # endif
216 # endif
217 # endif
219 freea (charset);
221 #endif /* _LIBC || HAVE_ICONV */
224 return nullentry;
227 /* Frees the codeset dependent parts of an opened message catalog. */
228 void
229 internal_function
230 _nl_free_domain_conv (domain)
231 struct loaded_domain *domain;
233 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
234 free (domain->conv_tab);
236 #ifdef _LIBC
237 if (domain->conv != (__gconv_t) -1)
238 __gconv_close (domain->conv);
239 #else
240 # if HAVE_ICONV
241 if (domain->conv != (iconv_t) -1)
242 iconv_close (domain->conv);
243 # endif
244 #endif
247 /* Load the message catalogs specified by FILENAME. If it is no valid
248 message catalog do nothing. */
249 void
250 internal_function
251 _nl_load_domain (domain_file, domainbinding)
252 struct loaded_l10nfile *domain_file;
253 struct binding *domainbinding;
255 int fd;
256 size_t size;
257 #ifdef _LIBC
258 struct stat64 st;
259 #else
260 struct stat st;
261 #endif
262 struct mo_file_header *data = (struct mo_file_header *) -1;
263 int use_mmap = 0;
264 struct loaded_domain *domain;
265 const char *nullentry;
267 domain_file->decided = 1;
268 domain_file->data = NULL;
270 /* Note that it would be useless to store domainbinding in domain_file
271 because domainbinding might be == NULL now but != NULL later (after
272 a call to bind_textdomain_codeset). */
274 /* If the record does not represent a valid locale the FILENAME
275 might be NULL. This can happen when according to the given
276 specification the locale file name is different for XPG and CEN
277 syntax. */
278 if (domain_file->filename == NULL)
279 return;
281 /* Try to open the addressed file. */
282 fd = open (domain_file->filename, O_RDONLY);
283 if (fd == -1)
284 return;
286 /* We must know about the size of the file. */
287 if (
288 #ifdef _LIBC
289 __builtin_expect (fstat64 (fd, &st) != 0, 0)
290 #else
291 __builtin_expect (fstat (fd, &st) != 0, 0)
292 #endif
293 || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
294 || __builtin_expect (size < sizeof (struct mo_file_header), 0))
296 /* Something went wrong. */
297 close (fd);
298 return;
301 #ifdef HAVE_MMAP
302 /* Now we are ready to load the file. If mmap() is available we try
303 this first. If not available or it failed we try to load it. */
304 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
305 MAP_PRIVATE, fd, 0);
307 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
309 /* mmap() call was successful. */
310 close (fd);
311 use_mmap = 1;
313 #endif
315 /* If the data is not yet available (i.e. mmap'ed) we try to load
316 it manually. */
317 if (data == (struct mo_file_header *) -1)
319 size_t to_read;
320 char *read_ptr;
322 data = (struct mo_file_header *) malloc (size);
323 if (data == NULL)
324 return;
326 to_read = size;
327 read_ptr = (char *) data;
330 long int nb = (long int) read (fd, read_ptr, to_read);
331 if (nb <= 0)
333 #ifdef EINTR
334 if (nb == -1 && errno == EINTR)
335 continue;
336 #endif
337 close (fd);
338 return;
340 read_ptr += nb;
341 to_read -= nb;
343 while (to_read > 0);
345 close (fd);
348 /* Using the magic number we can test whether it really is a message
349 catalog file. */
350 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
353 /* The magic number is wrong: not a message catalog file. */
354 #ifdef HAVE_MMAP
355 if (use_mmap)
356 munmap ((caddr_t) data, size);
357 else
358 #endif
359 free (data);
360 return;
363 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
364 if (domain == NULL)
365 return;
366 domain_file->data = domain;
368 domain->data = (char *) data;
369 domain->use_mmap = use_mmap;
370 domain->mmap_size = size;
371 domain->must_swap = data->magic != _MAGIC;
373 /* Fill in the information about the available tables. */
374 switch (W (domain->must_swap, data->revision))
376 case 0:
377 domain->nstrings = W (domain->must_swap, data->nstrings);
378 domain->orig_tab = (struct string_desc *)
379 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
380 domain->trans_tab = (struct string_desc *)
381 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
382 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
383 domain->hash_tab = (nls_uint32 *)
384 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
385 break;
386 default:
387 /* This is an invalid revision. */
388 #ifdef HAVE_MMAP
389 if (use_mmap)
390 munmap ((caddr_t) data, size);
391 else
392 #endif
393 free (data);
394 free (domain);
395 domain_file->data = NULL;
396 return;
399 /* Now initialize the character set converter from the character set
400 the file is encoded with (found in the header entry) to the domain's
401 specified character set or the locale's character set. */
402 nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
404 /* Also look for a plural specification. */
405 EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
409 #ifdef _LIBC
410 void
411 internal_function
412 _nl_unload_domain (domain)
413 struct loaded_domain *domain;
415 if (domain->plural != &__gettext_germanic_plural)
416 __gettext_free_exp (domain->plural);
418 _nl_free_domain_conv (domain);
420 # ifdef _POSIX_MAPPED_FILES
421 if (domain->use_mmap)
422 munmap ((caddr_t) domain->data, domain->mmap_size);
423 else
424 # endif /* _POSIX_MAPPED_FILES */
425 free ((void *) domain->data);
427 free (domain);
429 #endif