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
57 #if defined HAVE_UNISTD_H || defined _LIBC
62 # include <langinfo.h>
66 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
67 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
68 # include <sys/mman.h>
77 #include "plural-exp.h"
80 # include "../locale/localeinfo.h"
83 /* @@ end of prolog @@ */
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. */
90 # define close __close
93 # define munmap __munmap
96 /* For those losing systems which don't have `alloca' we have to add
97 some additional code emulating it. */
99 # define freea(p) /* nothing */
101 # define alloca(n) malloc (n)
102 # define freea(p) free (p)
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. */
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. */
128 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
129 domain
->codeset_cntr
=
130 (domainbinding
!= NULL
? domainbinding
->codeset_cntr
: 0);
132 domain
->conv
= (__gconv_t
) -1;
135 domain
->conv
= (iconv_t
) -1;
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
)
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';
162 memcpy (charset
, charsetstr
, len
);
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
;
175 outcharset
= getenv ("OUTPUT_CHARSET");
176 if (outcharset
== NULL
|| outcharset
[0] == '\0')
179 outcharset
= (*_nl_current
[LC_CTYPE
])->values
[_NL_ITEM_INDEX (CODESET
)].string
;
182 extern const char *locale_charset (void);
183 outcharset
= locale_charset ();
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
,
196 domain
->conv
= (__gconv_t
) -1;
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);
211 domain
->conv
= iconv_open (outcharset
, charset
);
212 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
213 || _LIBICONV_VERSION >= 0x0105
221 #endif /* _LIBC || HAVE_ICONV */
227 /* Frees the codeset dependent parts of an opened message catalog. */
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
);
237 if (domain
->conv
!= (__gconv_t
) -1)
238 __gconv_close (domain
->conv
);
241 if (domain
->conv
!= (iconv_t
) -1)
242 iconv_close (domain
->conv
);
247 /* Load the message catalogs specified by FILENAME. If it is no valid
248 message catalog do nothing. */
251 _nl_load_domain (domain_file
, domainbinding
)
252 struct loaded_l10nfile
*domain_file
;
253 struct binding
*domainbinding
;
262 struct mo_file_header
*data
= (struct mo_file_header
*) -1;
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
278 if (domain_file
->filename
== NULL
)
281 /* Try to open the addressed file. */
282 fd
= open (domain_file
->filename
, O_RDONLY
);
286 /* We must know about the size of the file. */
289 __builtin_expect (fstat64 (fd
, &st
) != 0, 0)
291 __builtin_expect (fstat (fd
, &st
) != 0, 0)
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. */
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
,
307 if (__builtin_expect (data
!= (struct mo_file_header
*) -1, 1))
309 /* mmap() call was successful. */
315 /* If the data is not yet available (i.e. mmap'ed) we try to load
317 if (data
== (struct mo_file_header
*) -1)
322 data
= (struct mo_file_header
*) malloc (size
);
327 read_ptr
= (char *) data
;
330 long int nb
= (long int) read (fd
, read_ptr
, to_read
);
334 if (nb
== -1 && errno
== EINTR
)
348 /* Using the magic number we can test whether it really is a message
350 if (__builtin_expect (data
->magic
!= _MAGIC
&& data
->magic
!= _MAGIC_SWAPPED
,
353 /* The magic number is wrong: not a message catalog file. */
356 munmap ((caddr_t
) data
, size
);
363 domain
= (struct loaded_domain
*) malloc (sizeof (struct loaded_domain
));
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
))
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
));
387 /* This is an invalid revision. */
390 munmap ((caddr_t
) data
, size
);
395 domain_file
->data
= NULL
;
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
);
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
);
424 # endif /* _POSIX_MAPPED_FILES */
425 free ((void *) domain
->data
);