1 /* Load needed message catalogs.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program 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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
19 This must come before <config.h> because <config.h> may include
20 <features.h>, and once <features.h> has been included, it's too late. */
22 # define _GNU_SOURCE 1
32 #include <sys/types.h>
36 # define alloca __builtin_alloca
37 # define HAVE_ALLOCA 1
39 # if defined HAVE_ALLOCA_H || defined _LIBC
55 #if defined HAVE_UNISTD_H || defined _LIBC
60 # include <langinfo.h>
64 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
65 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
66 # include <sys/mman.h>
77 # include "../locale/localeinfo.h"
80 /* @@ end of prolog @@ */
83 /* Rename the non ISO C functions. This is required by the standard
84 because some ISO C functions will require linking with this object
85 file and the name space must not be polluted. */
87 # define close __close
90 # define munmap __munmap
93 /* Names for the libintl functions are a problem. They must not clash
94 with existing names and they should follow ANSI C. But this source
95 code is also used in GNU C Library where the names have a __
96 prefix. So we have to make a difference here. */
98 # define PLURAL_PARSE __gettextparse
100 # define PLURAL_PARSE gettextparse__
103 /* For those losing systems which don't have `alloca' we have to add
104 some additional code emulating it. */
106 # define freea(p) /* nothing */
108 # define alloca(n) malloc (n)
109 # define freea(p) free (p)
112 /* For systems that distinguish between text and binary I/O.
113 O_BINARY is usually declared in <fcntl.h>. */
114 #if !defined O_BINARY && defined _O_BINARY
115 /* For MSC-compatible compilers. */
116 # define O_BINARY _O_BINARY
117 # define O_TEXT _O_TEXT
120 /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
124 /* On reasonable systems, binary I/O is the default. */
129 /* We need a sign, whether a new catalog was loaded, which can be associated
130 with all translations. This is important if the translations are
131 cached by one of GCC's features. */
132 int _nl_msg_cat_cntr
;
134 #if (defined __GNUC__ && !defined __APPLE_CC__) \
135 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
137 /* These structs are the constant expression for the germanic plural
138 form determination. It represents the expression "n != 1". */
139 static const struct expression plvar
=
144 static const struct expression plone
=
153 static struct expression germanic_plural
=
156 .operation
= not_equal
,
161 [0] = (struct expression
*) &plvar
,
162 [1] = (struct expression
*) &plone
167 # define INIT_GERMANIC_PLURAL()
171 /* For compilers without support for ISO C 99 struct/union initializers:
172 Initialization at run-time. */
174 static struct expression plvar
;
175 static struct expression plone
;
176 static struct expression germanic_plural
;
179 init_germanic_plural ()
181 if (plone
.val
.num
== 0)
184 plvar
.operation
= var
;
187 plone
.operation
= num
;
190 germanic_plural
.nargs
= 2;
191 germanic_plural
.operation
= not_equal
;
192 germanic_plural
.val
.args
[0] = &plvar
;
193 germanic_plural
.val
.args
[1] = &plone
;
197 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
202 /* Initialize the codeset dependent parts of an opened message catalog.
203 Return the header entry. */
206 _nl_init_domain_conv (domain_file
, domain
, domainbinding
)
207 struct loaded_l10nfile
*domain_file
;
208 struct loaded_domain
*domain
;
209 struct binding
*domainbinding
;
211 /* Find out about the character set the file is encoded with.
212 This can be found (in textual form) in the entry "". If this
213 entry does not exist or if this does not contain the `charset='
214 information, we will assume the charset matches the one the
215 current locale and we don't have to perform any conversion. */
219 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
220 domain
->codeset_cntr
=
221 (domainbinding
!= NULL
? domainbinding
->codeset_cntr
: 0);
223 domain
->conv
= (__gconv_t
) -1;
226 domain
->conv
= (iconv_t
) -1;
229 domain
->conv_tab
= NULL
;
231 /* Get the header entry. */
232 nullentry
= _nl_find_msg (domain_file
, domainbinding
, "", &nullentrylen
);
234 if (nullentry
!= NULL
)
236 #if defined _LIBC || HAVE_ICONV
237 const char *charsetstr
;
239 charsetstr
= strstr (nullentry
, "charset=");
240 if (charsetstr
!= NULL
)
244 const char *outcharset
;
246 charsetstr
+= strlen ("charset=");
247 len
= strcspn (charsetstr
, " \t\n");
249 charset
= (char *) alloca (len
+ 1);
250 # if defined _LIBC || HAVE_MEMPCPY
251 *((char *) mempcpy (charset
, charsetstr
, len
)) = '\0';
253 memcpy (charset
, charsetstr
, len
);
257 /* The output charset should normally be determined by the
258 locale. But sometimes the locale is not used or not correctly
259 set up, so we provide a possibility for the user to override
260 this. Moreover, the value specified through
261 bind_textdomain_codeset overrides both. */
262 if (domainbinding
!= NULL
&& domainbinding
->codeset
!= NULL
)
263 outcharset
= domainbinding
->codeset
;
266 outcharset
= getenv ("OUTPUT_CHARSET");
267 if (outcharset
== NULL
|| outcharset
[0] == '\0')
270 outcharset
= (*_nl_current
[LC_CTYPE
])->values
[_NL_ITEM_INDEX (CODESET
)].string
;
273 extern const char *locale_charset (void);
274 outcharset
= locale_charset ();
281 /* We always want to use transliteration. */
282 outcharset
= norm_add_slashes (outcharset
, "TRANSLIT");
283 charset
= norm_add_slashes (charset
, NULL
);
284 if (__gconv_open (outcharset
, charset
, &domain
->conv
,
287 domain
->conv
= (__gconv_t
) -1;
290 /* When using GNU libiconv, we want to use transliteration. */
291 # if _LIBICONV_VERSION >= 0x0105
292 len
= strlen (outcharset
);
294 char *tmp
= (char *) alloca (len
+ 10 + 1);
295 memcpy (tmp
, outcharset
, len
);
296 memcpy (tmp
+ len
, "//TRANSLIT", 10 + 1);
300 domain
->conv
= iconv_open (outcharset
, charset
);
301 # if _LIBICONV_VERSION >= 0x0105
309 #endif /* _LIBC || HAVE_ICONV */
315 /* Frees the codeset dependent parts of an opened message catalog. */
318 _nl_free_domain_conv (domain
)
319 struct loaded_domain
*domain
;
321 if (domain
->conv_tab
!= NULL
&& domain
->conv_tab
!= (char **) -1)
322 free (domain
->conv_tab
);
325 if (domain
->conv
!= (__gconv_t
) -1)
326 __gconv_close (domain
->conv
);
329 if (domain
->conv
!= (iconv_t
) -1)
330 iconv_close (domain
->conv
);
335 /* Load the message catalogs specified by FILENAME. If it is no valid
336 message catalog do nothing. */
339 _nl_load_domain (domain_file
, domainbinding
)
340 struct loaded_l10nfile
*domain_file
;
341 struct binding
*domainbinding
;
350 struct mo_file_header
*data
= (struct mo_file_header
*) -1;
352 struct loaded_domain
*domain
;
353 const char *nullentry
;
355 domain_file
->decided
= 1;
356 domain_file
->data
= NULL
;
358 /* Note that it would be useless to store domainbinding in domain_file
359 because domainbinding might be == NULL now but != NULL later (after
360 a call to bind_textdomain_codeset). */
362 /* If the record does not represent a valid locale the FILENAME
363 might be NULL. This can happen when according to the given
364 specification the locale file name is different for XPG and CEN
366 if (domain_file
->filename
== NULL
)
369 /* Try to open the addressed file. */
370 fd
= open (domain_file
->filename
, O_RDONLY
| O_BINARY
);
374 /* We must know about the size of the file. */
377 __builtin_expect (fstat64 (fd
, &st
) != 0, 0)
379 __builtin_expect (fstat (fd
, &st
) != 0, 0)
381 || __builtin_expect ((size
= (size_t) st
.st_size
) != st
.st_size
, 0)
382 || __builtin_expect (size
< sizeof (struct mo_file_header
), 0))
384 /* Something went wrong. */
390 /* Now we are ready to load the file. If mmap() is available we try
391 this first. If not available or it failed we try to load it. */
392 data
= (struct mo_file_header
*) mmap (NULL
, size
, PROT_READ
,
395 if (__builtin_expect (data
!= (struct mo_file_header
*) -1, 1))
397 /* mmap() call was successful. */
403 /* If the data is not yet available (i.e. mmap'ed) we try to load
405 if (data
== (struct mo_file_header
*) -1)
410 data
= (struct mo_file_header
*) malloc (size
);
415 read_ptr
= (char *) data
;
418 long int nb
= (long int) read (fd
, read_ptr
, to_read
);
422 if (nb
== -1 && errno
== EINTR
)
436 /* Using the magic number we can test whether it really is a message
438 if (__builtin_expect (data
->magic
!= _MAGIC
&& data
->magic
!= _MAGIC_SWAPPED
,
441 /* The magic number is wrong: not a message catalog file. */
444 munmap ((caddr_t
) data
, size
);
451 domain
= (struct loaded_domain
*) malloc (sizeof (struct loaded_domain
));
454 domain_file
->data
= domain
;
456 domain
->data
= (char *) data
;
457 domain
->use_mmap
= use_mmap
;
458 domain
->mmap_size
= size
;
459 domain
->must_swap
= data
->magic
!= _MAGIC
;
461 /* Fill in the information about the available tables. */
462 switch (W (domain
->must_swap
, data
->revision
))
465 domain
->nstrings
= W (domain
->must_swap
, data
->nstrings
);
466 domain
->orig_tab
= (struct string_desc
*)
467 ((char *) data
+ W (domain
->must_swap
, data
->orig_tab_offset
));
468 domain
->trans_tab
= (struct string_desc
*)
469 ((char *) data
+ W (domain
->must_swap
, data
->trans_tab_offset
));
470 domain
->hash_size
= W (domain
->must_swap
, data
->hash_tab_size
);
471 domain
->hash_tab
= (nls_uint32
*)
472 ((char *) data
+ W (domain
->must_swap
, data
->hash_tab_offset
));
475 /* This is an invalid revision. */
478 munmap ((caddr_t
) data
, size
);
483 domain_file
->data
= NULL
;
487 /* Now initialize the character set converter from the character set
488 the file is encoded with (found in the header entry) to the domain's
489 specified character set or the locale's character set. */
490 nullentry
= _nl_init_domain_conv (domain_file
, domain
, domainbinding
);
492 /* Also look for a plural specification. */
493 if (nullentry
!= NULL
)
496 const char *nplurals
;
498 plural
= strstr (nullentry
, "plural=");
499 nplurals
= strstr (nullentry
, "nplurals=");
500 if (plural
== NULL
|| nplurals
== NULL
)
504 /* First get the number. */
507 struct parse_args args
;
510 while (*nplurals
!= '\0' && isspace (*nplurals
))
512 #if defined HAVE_STRTOUL || defined _LIBC
513 n
= strtoul (nplurals
, &endp
, 10);
515 for (endp
= nplurals
, n
= 0; *endp
>= '0' && *endp
<= '9'; endp
++)
516 n
= n
* 10 + (*endp
- '0');
518 domain
->nplurals
= n
;
519 if (nplurals
== endp
)
522 /* Due to the restrictions bison imposes onto the interface of the
523 scanner function we have to put the input string and the result
524 passed up from the parser into the same structure which address
525 is passed down to the parser. */
528 if (PLURAL_PARSE (&args
) != 0)
530 domain
->plural
= args
.res
;
535 /* By default we are using the Germanic form: singular form only
536 for `one', the plural form otherwise. Yes, this is also what
537 English is using since English is a Germanic language. */
539 INIT_GERMANIC_PLURAL ();
540 domain
->plural
= &germanic_plural
;
541 domain
->nplurals
= 2;
549 _nl_unload_domain (domain
)
550 struct loaded_domain
*domain
;
552 if (domain
->plural
!= &germanic_plural
)
553 __gettext_free_exp (domain
->plural
);
555 _nl_free_domain_conv (domain
);
557 # ifdef _POSIX_MAPPED_FILES
558 if (domain
->use_mmap
)
559 munmap ((caddr_t
) domain
->data
, domain
->mmap_size
);
561 # endif /* _POSIX_MAPPED_FILES */
562 free ((void *) domain
->data
);