Update.
[platform/upstream/glibc.git] / intl / loadmsgcat.c
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.
4
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.
9
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.
14
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.  */
19
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
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
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
53
54 #include <stdlib.h>
55 #include <string.h>
56
57 #if defined HAVE_UNISTD_H || defined _LIBC
58 # include <unistd.h>
59 #endif
60
61 #ifdef _LIBC
62 # include <langinfo.h>
63 # include <locale.h>
64 #endif
65
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
74
75 #include "gettext.h"
76 #include "gettextP.h"
77 #include "plural-exp.h"
78
79 #ifdef _LIBC
80 # include "../locale/localeinfo.h"
81 #endif
82
83 /* @@ end of prolog @@ */
84
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
95
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
104
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;
109
110
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;
119 {
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;
127
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;
139
140   /* Get the header entry.  */
141   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
142
143   if (nullentry != NULL)
144     {
145 #if defined _LIBC || HAVE_ICONV
146       const char *charsetstr;
147
148       charsetstr = strstr (nullentry, "charset=");
149       if (charsetstr != NULL)
150         {
151           size_t len;
152           char *charset;
153           const char *outcharset;
154
155           charsetstr += strlen ("charset=");
156           len = strcspn (charsetstr, " \t\n");
157
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
165
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
174             {
175               outcharset = getenv ("OUTPUT_CHARSET");
176               if (outcharset == NULL || outcharset[0] == '\0')
177                 {
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
186                 }
187             }
188
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);
204           {
205             char *tmp = (char *) alloca (len + 10 + 1);
206             memcpy (tmp, outcharset, len);
207             memcpy (tmp + len, "//TRANSLIT", 10 + 1);
208             outcharset = tmp;
209           }
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
218
219           freea (charset);
220         }
221 #endif /* _LIBC || HAVE_ICONV */
222     }
223
224   return nullentry;
225 }
226
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;
232 {
233   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
234     free (domain->conv_tab);
235
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
245 }
246
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;
254 {
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;
266
267   domain_file->decided = 1;
268   domain_file->data = NULL;
269
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).  */
273
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;
280
281   /* Try to open the addressed file.  */
282   fd = open (domain_file->filename, O_RDONLY);
283   if (fd == -1)
284     return;
285
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))
295     {
296       /* Something went wrong.  */
297       close (fd);
298       return;
299     }
300
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);
306
307   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
308     {
309       /* mmap() call was successful.  */
310       close (fd);
311       use_mmap = 1;
312     }
313 #endif
314
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)
318     {
319       size_t to_read;
320       char *read_ptr;
321
322       data = (struct mo_file_header *) malloc (size);
323       if (data == NULL)
324         return;
325
326       to_read = size;
327       read_ptr = (char *) data;
328       do
329         {
330           long int nb = (long int) read (fd, read_ptr, to_read);
331           if (nb <= 0)
332             {
333 #ifdef EINTR
334               if (nb == -1 && errno == EINTR)
335                 continue;
336 #endif
337               close (fd);
338               return;
339             }
340           read_ptr += nb;
341           to_read -= nb;
342         }
343       while (to_read > 0);
344
345       close (fd);
346     }
347
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,
351                         0))
352     {
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;
361     }
362
363   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
364   if (domain == NULL)
365     return;
366   domain_file->data = domain;
367
368   domain->data = (char *) data;
369   domain->use_mmap = use_mmap;
370   domain->mmap_size = size;
371   domain->must_swap = data->magic != _MAGIC;
372
373   /* Fill in the information about the available tables.  */
374   switch (W (domain->must_swap, data->revision))
375     {
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;
397     }
398
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);
403
404   /* Also look for a plural specification.  */
405   EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
406 }
407
408
409 #ifdef _LIBC
410 void
411 internal_function
412 _nl_unload_domain (domain)
413      struct loaded_domain *domain;
414 {
415   if (domain->plural != &__gettext_germanic_plural)
416     __gettext_free_exp (domain->plural);
417
418   _nl_free_domain_conv (domain);
419
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);
426
427   free (domain);
428 }
429 #endif