Add test case for FNM_PERIOD handling with FNM_EXTMATCH.
[kopensolaris-gnu/glibc.git] / intl / loadmsgcat.c
1 /* Load needed message catalogs.
2    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3
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.
8
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.
13
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.  */
18
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
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #if defined STDC_HEADERS || defined _LIBC
37 # include <stdlib.h>
38 #endif
39
40 #if defined HAVE_STRING_H || defined _LIBC
41 # include <string.h>
42 #else
43 # include <strings.h>
44 #endif
45
46 #if defined HAVE_UNISTD_H || defined _LIBC
47 # include <unistd.h>
48 #endif
49
50 #ifdef _LIBC
51 # include <langinfo.h>
52 # include <locale.h>
53 #endif
54
55 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
56     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
57 # include <sys/mman.h>
58 # undef HAVE_MMAP
59 # define HAVE_MMAP      1
60 #else
61 # undef HAVE_MMAP
62 #endif
63
64 #include "gettext.h"
65 #include "gettextP.h"
66
67 #ifdef _LIBC
68 # include "../locale/localeinfo.h"
69 #endif
70
71 /* @@ end of prolog @@ */
72
73 #ifdef _LIBC
74 /* Rename the non ISO C functions.  This is required by the standard
75    because some ISO C functions will require linking with this object
76    file and the name space must not be polluted.  */
77 # define open   __open
78 # define close  __close
79 # define read   __read
80 # define mmap   __mmap
81 # define munmap __munmap
82 #endif
83
84 /* We need a sign, whether a new catalog was loaded, which can be associated
85    with all translations.  This is important if the translations are
86    cached by one of GCC's features.  */
87 int _nl_msg_cat_cntr;
88
89 #if defined __GNUC__ \
90     || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
91
92 /* These structs are the constant expression for the germanic plural
93    form determination.  It represents the expression  "n != 1".  */
94 static const struct expression plvar =
95 {
96   .operation = var,
97 };
98 static const struct expression plone =
99 {
100   .operation = num,
101   .val =
102   {
103     .num = 1
104   }
105 };
106 static struct expression germanic_plural =
107 {
108   .operation = not_equal,
109   .val =
110   {
111     .args2 =
112     {
113       .left = (struct expression *) &plvar,
114       .right = (struct expression *) &plone
115     }
116   }
117 };
118
119 # define INIT_GERMANIC_PLURAL()
120
121 #else
122
123 /* For compilers without support for ISO C 99 struct/union initializers:
124    Initialization at run-time.  */
125
126 static struct expression plvar;
127 static struct expression plone;
128 static struct expression germanic_plural;
129
130 static void
131 init_germanic_plural ()
132 {
133   if (plone.val.num == 0)
134     {
135       plvar.operation = var;
136
137       plone.operation = num;
138       plone.val.num = 1;
139
140       germanic_plural.operation = not_equal;
141       germanic_plural.val.args2.left = &plvar;
142       germanic_plural.val.args2.right = &plone;
143     }
144 }
145
146 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
147
148 #endif
149
150
151 /* Load the message catalogs specified by FILENAME.  If it is no valid
152    message catalog do nothing.  */
153 void
154 internal_function
155 _nl_load_domain (domain_file)
156      struct loaded_l10nfile *domain_file;
157 {
158   int fd;
159   size_t size;
160   struct stat64 st;
161   struct mo_file_header *data = (struct mo_file_header *) -1;
162   int use_mmap = 0;
163   struct loaded_domain *domain;
164   char *nullentry;
165   size_t nullentrylen;
166
167   domain_file->decided = 1;
168   domain_file->data = NULL;
169
170   /* If the record does not represent a valid locale the FILENAME
171      might be NULL.  This can happen when according to the given
172      specification the locale file name is different for XPG and CEN
173      syntax.  */
174   if (domain_file->filename == NULL)
175     return;
176
177   /* Try to open the addressed file.  */
178   fd = open (domain_file->filename, O_RDONLY);
179   if (fd == -1)
180     return;
181
182   /* We must know about the size of the file.  */
183   if (__builtin_expect (fstat64 (fd, &st) != 0, 0)
184       || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
185       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
186     {
187       /* Something went wrong.  */
188       close (fd);
189       return;
190     }
191
192 #ifdef HAVE_MMAP
193   /* Now we are ready to load the file.  If mmap() is available we try
194      this first.  If not available or it failed we try to load it.  */
195   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
196                                          MAP_PRIVATE, fd, 0);
197
198   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
199     {
200       /* mmap() call was successful.  */
201       close (fd);
202       use_mmap = 1;
203     }
204 #endif
205
206   /* If the data is not yet available (i.e. mmap'ed) we try to load
207      it manually.  */
208   if (data == (struct mo_file_header *) -1)
209     {
210       size_t to_read;
211       char *read_ptr;
212
213       data = (struct mo_file_header *) malloc (size);
214       if (data == NULL)
215         return;
216
217       to_read = size;
218       read_ptr = (char *) data;
219       do
220         {
221           long int nb = (long int) read (fd, read_ptr, to_read);
222           if (nb <= 0)
223             {
224 #ifdef EINTR
225               if (nb == -1 && errno == EINTR)
226                 continue;
227 #endif
228               close (fd);
229               return;
230             }
231           read_ptr += nb;
232           to_read -= nb;
233         }
234       while (to_read > 0);
235
236       close (fd);
237     }
238
239   /* Using the magic number we can test whether it really is a message
240      catalog file.  */
241   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
242                         0))
243     {
244       /* The magic number is wrong: not a message catalog file.  */
245 #ifdef HAVE_MMAP
246       if (use_mmap)
247         munmap ((caddr_t) data, size);
248       else
249 #endif
250         free (data);
251       return;
252     }
253
254   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
255   if (domain == NULL)
256     return;
257   domain_file->data = domain;
258
259   domain->data = (char *) data;
260   domain->use_mmap = use_mmap;
261   domain->mmap_size = size;
262   domain->must_swap = data->magic != _MAGIC;
263
264   /* Fill in the information about the available tables.  */
265   switch (W (domain->must_swap, data->revision))
266     {
267     case 0:
268       domain->nstrings = W (domain->must_swap, data->nstrings);
269       domain->orig_tab = (struct string_desc *)
270         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
271       domain->trans_tab = (struct string_desc *)
272         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
273       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
274       domain->hash_tab = (nls_uint32 *)
275         ((char *) data + W (domain->must_swap, data->hash_tab_offset));
276       break;
277     default:
278       /* This is an invalid revision.  */
279 #ifdef HAVE_MMAP
280       if (use_mmap)
281         munmap ((caddr_t) data, size);
282       else
283 #endif
284         free (data);
285       free (domain);
286       domain_file->data = NULL;
287       return;
288     }
289
290   /* Now find out about the character set the file is encoded with.
291      This can be found (in textual form) in the entry "".  If this
292      entry does not exist or if this does not contain the `charset='
293      information, we will assume the charset matches the one the
294      current locale and we don't have to perform any conversion.  */
295 #ifdef _LIBC
296   domain->conv = (__gconv_t) -1;
297 #else
298 # if HAVE_ICONV
299   domain->conv = (iconv_t) -1;
300 # endif
301 #endif
302   domain->conv_tab = NULL;
303   nullentry = _nl_find_msg (domain_file, "", &nullentrylen);
304   if (nullentry != NULL)
305     {
306 #if defined _LIBC || HAVE_ICONV
307       const char *charsetstr;
308
309       charsetstr = strstr (nullentry, "charset=");
310       if (charsetstr != NULL)
311         {
312           size_t len;
313           char *charset;
314           const char *outcharset;
315
316           charsetstr += strlen ("charset=");
317           len = strcspn (charsetstr, " \t\n");
318
319           charset = (char *) alloca (len + 1);
320 # if defined _LIBC || HAVE_MEMPCPY
321           *((char *) mempcpy (charset, charsetstr, len)) = '\0';
322 # else
323           memcpy (charset, charsetstr, len);
324           charset[len] = '\0';
325 # endif
326
327           /* The output charset should normally be determined by the
328              locale.  But sometimes the locale is not used or not correctly
329              set up, so we provide a possibility for the user to override
330              this.  Moreover, the value specified through
331              bind_textdomain_codeset overrides both.  */
332           if (domain_file->domainbinding != NULL
333               && domain_file->domainbinding->codeset != NULL)
334             outcharset = domain_file->domainbinding->codeset;
335           else
336             {
337               outcharset = getenv ("OUTPUT_CHARSET");
338               if (outcharset == NULL || outcharset[0] == '\0')
339                 {
340 # ifdef _LIBC
341                   outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
342 # else
343 #  if HAVE_ICONV
344                   extern const char *locale_charset (void);
345                   outcharset = locale_charset ();
346                   if (outcharset == NULL)
347                     outcharset = "";
348 #  endif
349 # endif
350                 }
351             }
352
353 # ifdef _LIBC
354           /* We always want to use transliteration.  */
355           outcharset = norm_add_slashes (outcharset, "TRANSLIT");
356           charset = norm_add_slashes (charset, NULL);
357           if (__gconv_open (outcharset, charset, &domain->conv,
358                             GCONV_AVOID_NOCONV)
359               != __GCONV_OK)
360             domain->conv = (__gconv_t) -1;
361 # else
362 #  if HAVE_ICONV
363           domain->conv = iconv_open (outcharset, charset);
364 #  endif
365 # endif
366         }
367 #endif /* _LIBC || HAVE_ICONV */
368     }
369
370   /* Also look for a plural specification.  */
371   if (nullentry != NULL)
372     {
373       const char *plural;
374       const char *nplurals;
375
376       plural = strstr (nullentry, "plural=");
377       nplurals = strstr (nullentry, "nplurals=");
378       if (plural == NULL || nplurals == NULL)
379         goto no_plural;
380       else
381         {
382           /* First get the number.  */
383           char *endp;
384           struct parse_args args;
385
386           nplurals += 9;
387           while (*nplurals != '\0' && isspace (*nplurals))
388             ++nplurals;
389           domain->nplurals = strtoul (nplurals, &endp, 10);
390           if (nplurals == endp)
391             goto no_plural;
392
393           /* Due to the restrictions bison imposes onto the interface of the
394              scanner function we have to put the input string and the result
395              passed up from the parser into the same structure which address
396              is passed down to the parser.  */
397           plural += 7;
398           args.cp = plural;
399           if (__gettextparse (&args) != 0)
400             goto no_plural;
401           domain->plural = args.res;
402         }
403     }
404   else
405     {
406       /* By default we are using the Germanic form: singular form only
407          for `one', the plural form otherwise.  Yes, this is also what
408          English is using since English is a Germanic language.  */
409     no_plural:
410       INIT_GERMANIC_PLURAL ();
411       domain->plural = &germanic_plural;
412       domain->nplurals = 2;
413     }
414 }
415
416
417 #ifdef _LIBC
418 void
419 internal_function
420 _nl_unload_domain (domain)
421      struct loaded_domain *domain;
422 {
423   if (domain->plural != &germanic_plural)
424     __gettext_free_exp (domain->plural);
425
426   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
427     free (domain->conv_tab);
428
429   if (domain->conv != (__gconv_t) -1)
430     __gconv_close (domain->conv);
431
432 # ifdef _POSIX_MAPPED_FILES
433   if (domain->use_mmap)
434     munmap ((caddr_t) domain->data, domain->mmap_size);
435   else
436 # endif /* _POSIX_MAPPED_FILES */
437     free ((void *) domain->data);
438
439   free (domain);
440 }
441 #endif