1 /* Load needed message catalogs.
2    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8 
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 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 this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17    USA.  */
18 
19 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
20    This must come before <autoconf.h> because <autoconf.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 <autoconf.h>
28 #endif
29 
30 #undef freea
31 
32 /* see AC_FUNC_ALLOCA macro */
33 #ifdef __GNUC__
34 # define alloca __builtin_alloca
35 #else
36 # ifdef _MSC_VER
37 #  include <malloc.h>
38 #  define alloca _alloca
39 # else
40 #  if HAVE_ALLOCA_H
41 #   include <alloca.h>
42 #  else
43 #   ifdef _AIX
44  #pragma alloca
45 #   else
46 #    ifndef alloca /* predefined by HP cc +Olibcalls */
47 char *alloca ();
48 #    else
49 #     define freea(n) free(n)
50 #    endif
51 #   endif
52 #  endif
53 # endif
54 #endif
55 
56 #ifndef freea
57 #define freea(n) /* nothing */
58 #endif
59 
60 #include <ctype.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 
66 #include <stdlib.h>
67 #include <string.h>
68 
69 #if defined HAVE_UNISTD_H || defined _LIBC
70 # include <unistd.h>
71 #endif
72 
73 #ifdef _LIBC
74 # include <langinfo.h>
75 # include <locale.h>
76 #endif
77 
78 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
79     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
80 # include <sys/mman.h>
81 # undef HAVE_MMAP
82 # define HAVE_MMAP	1
83 #else
84 # undef HAVE_MMAP
85 #endif
86 
87 #include "gettext.h"
88 #include "gettextP.h"
89 
90 #ifdef _LIBC
91 # include "../locale/localeinfo.h"
92 #endif
93 
94 /* @@ end of prolog @@ */
95 
96 #ifdef _LIBC
97 /* Rename the non ISO C functions.  This is required by the standard
98    because some ISO C functions will require linking with this object
99    file and the name space must not be polluted.  */
100 # define open   __open
101 # define close  __close
102 # define read   __read
103 # define mmap   __mmap
104 # define munmap __munmap
105 #endif
106 
107 /* Names for the libintl functions are a problem.  They must not clash
108    with existing names and they should follow ANSI C.  But this source
109    code is also used in GNU C Library where the names have a __
110    prefix.  So we have to make a difference here.  */
111 #ifdef _LIBC
112 # define PLURAL_PARSE __gettextparse
113 #else
114 # define PLURAL_PARSE gettextparse__
115 #endif
116 
117 /* For systems that distinguish between text and binary I/O.
118    O_BINARY is usually declared in <fcntl.h>. */
119 #if !defined O_BINARY && defined _O_BINARY
120   /* For MSC-compatible compilers.  */
121 # define O_BINARY _O_BINARY
122 # define O_TEXT _O_TEXT
123 #endif
124 #ifdef __BEOS__
125   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
126 # undef O_BINARY
127 # undef O_TEXT
128 #endif
129 /* On reasonable systems, binary I/O is the default.  */
130 #ifndef O_BINARY
131 # define O_BINARY 0
132 #endif
133 
134 /* We need a sign, whether a new catalog was loaded, which can be associated
135    with all translations.  This is important if the translations are
136    cached by one of GCC's features.  */
137 int _nl_msg_cat_cntr;
138 
139 #if (defined __GNUC__ && !defined __APPLE_CC__) \
140     || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
141 
142 /* These structs are the constant expression for the germanic plural
143    form determination.  It represents the expression  "n != 1".  */
144 static const struct expression plvar =
145 {
146   .nargs = 0,
147   .operation = var,
148 };
149 static const struct expression plone =
150 {
151   .nargs = 0,
152   .operation = num,
153   .val =
154   {
155     .num = 1
156   }
157 };
158 static struct expression germanic_plural =
159 {
160   .nargs = 2,
161   .operation = not_equal,
162   .val =
163   {
164     .args =
165     {
166       [0] = (struct expression *) &plvar,
167       [1] = (struct expression *) &plone
168     }
169   }
170 };
171 
172 # define INIT_GERMANIC_PLURAL()
173 
174 #else
175 
176 /* For compilers without support for ISO C 99 struct/union initializers:
177    Initialization at run-time.  */
178 
179 static struct expression plvar;
180 static struct expression plone;
181 static struct expression germanic_plural;
182 
183 static void
init_germanic_plural()184 init_germanic_plural ()
185 {
186   if (plone.val.num == 0)
187     {
188       plvar.nargs = 0;
189       plvar.operation = var;
190 
191       plone.nargs = 0;
192       plone.operation = num;
193       plone.val.num = 1;
194 
195       germanic_plural.nargs = 2;
196       germanic_plural.operation = not_equal;
197       germanic_plural.val.args[0] = &plvar;
198       germanic_plural.val.args[1] = &plone;
199     }
200 }
201 
202 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
203 
204 #endif
205 
206 
207 /* Initialize the codeset dependent parts of an opened message catalog.
208    Return the header entry.  */
209 const char *
210 internal_function
_nl_init_domain_conv(domain_file,domain,domainbinding)211 _nl_init_domain_conv (domain_file, domain, domainbinding)
212      struct loaded_l10nfile *domain_file;
213      struct loaded_domain *domain;
214      struct binding *domainbinding;
215 {
216   /* Find out about the character set the file is encoded with.
217      This can be found (in textual form) in the entry "".  If this
218      entry does not exist or if this does not contain the `charset='
219      information, we will assume the charset matches the one the
220      current locale and we don't have to perform any conversion.  */
221   char *nullentry;
222   size_t nullentrylen;
223 
224   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
225   domain->codeset_cntr =
226     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
227 #ifdef _LIBC
228   domain->conv = (__gconv_t) -1;
229 #else
230 # ifdef HAVE_ICONV
231   domain->conv = (iconv_t) -1;
232 # endif
233 #endif
234   domain->conv_tab = NULL;
235 
236   /* Get the header entry.  */
237   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
238 
239   if (nullentry != NULL)
240     {
241 #if defined _LIBC || defined HAVE_ICONV
242       const char *charsetstr;
243 
244       charsetstr = strstr (nullentry, "charset=");
245       if (charsetstr != NULL)
246 	{
247 	  size_t len;
248 	  char *charset;
249 	  const char *outcharset;
250 
251 	  charsetstr += strlen ("charset=");
252 	  len = strcspn (charsetstr, " \t\n");
253 
254 	  charset = (char *) alloca (len + 1);
255 # if defined _LIBC || HAVE_MEMPCPY
256 	  *((char *) mempcpy (charset, charsetstr, len)) = '\0';
257 # else
258 	  memcpy (charset, charsetstr, len);
259 	  charset[len] = '\0';
260 # endif
261 
262 	  /* The output charset should normally be determined by the
263 	     locale.  But sometimes the locale is not used or not correctly
264 	     set up, so we provide a possibility for the user to override
265 	     this.  Moreover, the value specified through
266 	     bind_textdomain_codeset overrides both.  */
267 	  if (domainbinding != NULL && domainbinding->codeset != NULL)
268 	    outcharset = domainbinding->codeset;
269 	  else
270 	    {
271 	      outcharset = getenv ("OUTPUT_CHARSET");
272 	      if (outcharset == NULL || outcharset[0] == '\0')
273 		{
274 # ifdef _LIBC
275 		  outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
276 # else
277 #  if HAVE_ICONV
278 		  extern const char *locale_charset (void);
279 		  outcharset = locale_charset ();
280 #  endif
281 # endif
282 		}
283 	    }
284 
285 # ifdef _LIBC
286 	  /* We always want to use transliteration.  */
287 	  outcharset = norm_add_slashes (outcharset, "TRANSLIT");
288 	  charset = norm_add_slashes (charset, NULL);
289 	  if (__gconv_open (outcharset, charset, &domain->conv,
290 			    GCONV_AVOID_NOCONV)
291 	      != __GCONV_OK)
292 	    domain->conv = (__gconv_t) -1;
293 # else
294 #  if HAVE_ICONV
295 	  /* When using GNU libiconv, we want to use transliteration.  */
296 #   if _LIBICONV_VERSION >= 0x0105
297 	  len = strlen (outcharset);
298 	  {
299 	    char *tmp = (char *) alloca (len + 10 + 1);
300 	    memcpy (tmp, outcharset, len);
301 	    memcpy (tmp + len, "//TRANSLIT", 10 + 1);
302 	    outcharset = tmp;
303 	  }
304 #   endif
305 	  domain->conv = iconv_open (outcharset, charset);
306 #   if _LIBICONV_VERSION >= 0x0105
307 	  freea (outcharset);
308 #   endif
309 #  endif
310 # endif
311 
312 	  freea (charset);
313 	}
314 #endif /* _LIBC || HAVE_ICONV */
315     }
316 
317   return nullentry;
318 }
319 
320 /* Frees the codeset dependent parts of an opened message catalog.  */
321 void
322 internal_function
_nl_free_domain_conv(domain)323 _nl_free_domain_conv (domain)
324      struct loaded_domain *domain;
325 {
326   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
327     free (domain->conv_tab);
328 
329 #ifdef _LIBC
330   if (domain->conv != (__gconv_t) -1)
331     __gconv_close (domain->conv);
332 #else
333 # ifdef HAVE_ICONV
334   if (domain->conv != (iconv_t) -1)
335     iconv_close (domain->conv);
336 # endif
337 #endif
338 }
339 
340 /* Load the message catalogs specified by FILENAME.  If it is no valid
341    message catalog do nothing.  */
342 void
343 internal_function
_nl_load_domain(domain_file,domainbinding)344 _nl_load_domain (domain_file, domainbinding)
345      struct loaded_l10nfile *domain_file;
346      struct binding *domainbinding;
347 {
348   int fd;
349   size_t size;
350 #ifdef _LIBC
351   struct stat64 st;
352 #else
353   struct stat st;
354 #endif
355   struct mo_file_header *data = (struct mo_file_header *) -1;
356   int use_mmap = 0;
357   struct loaded_domain *domain;
358   const char *nullentry;
359 
360   domain_file->decided = 1;
361   domain_file->data = NULL;
362 
363   /* Note that it would be useless to store domainbinding in domain_file
364      because domainbinding might be == NULL now but != NULL later (after
365      a call to bind_textdomain_codeset).  */
366 
367   /* If the record does not represent a valid locale the FILENAME
368      might be NULL.  This can happen when according to the given
369      specification the locale file name is different for XPG and CEN
370      syntax.  */
371   if (domain_file->filename == NULL)
372     return;
373 
374   /* Try to open the addressed file.  */
375   fd = open (domain_file->filename, O_RDONLY | O_BINARY);
376   if (fd == -1)
377     return;
378 
379   /* We must know about the size of the file.  */
380   if (
381 #ifdef _LIBC
382       __builtin_expect (fstat64 (fd, &st) != 0, 0)
383 #else
384       __builtin_expect (fstat (fd, &st) != 0, 0)
385 #endif
386       || __builtin_expect ((size = (size_t) st.st_size) != (size_t) st.st_size, 0)
387       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
388     {
389       /* Something went wrong.  */
390       close (fd);
391       return;
392     }
393 
394 #ifdef HAVE_MMAP
395   /* Now we are ready to load the file.  If mmap() is available we try
396      this first.  If not available or it failed we try to load it.  */
397   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
398 					 MAP_PRIVATE, fd, 0);
399 
400   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
401     {
402       /* mmap() call was successful.  */
403       close (fd);
404       use_mmap = 1;
405     }
406 #endif
407 
408   /* If the data is not yet available (i.e. mmap'ed) we try to load
409      it manually.  */
410   if (data == (struct mo_file_header *) -1)
411     {
412       size_t to_read;
413       char *read_ptr;
414 
415       data = (struct mo_file_header *) malloc (size);
416       if (data == NULL) {
417     	  if (!use_mmap)
418 	      	close (fd);
419 		return;
420 	}
421 
422       to_read = size;
423       read_ptr = (char *) data;
424       do
425 	{
426 	  long int nb = (long int) read (fd, read_ptr, to_read);
427 	  if (nb <= 0)
428 	    {
429 #ifdef EINTR
430 	      if (nb == -1 && errno == EINTR)
431 		continue;
432 #endif
433 	      close (fd);
434 	      return;
435 	    }
436 	  read_ptr += nb;
437 	  to_read -= nb;
438 	}
439       while (to_read > 0);
440 
441       close (fd);
442     }
443 
444   /* Using the magic number we can test whether it really is a message
445      catalog file.  */
446   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
447 			0))
448     {
449       /* The magic number is wrong: not a message catalog file.  */
450 #ifdef HAVE_MMAP
451       if (use_mmap)
452 	munmap ((caddr_t) data, size);
453       else
454 #endif
455 	free (data);
456       return;
457     }
458 
459   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
460   if (domain == NULL)
461     return;
462   domain_file->data = domain;
463 
464   domain->data = (char *) data;
465   domain->use_mmap = use_mmap;
466   domain->mmap_size = size;
467   domain->must_swap = data->magic != _MAGIC;
468 
469   /* Fill in the information about the available tables.  */
470   switch (W (domain->must_swap, data->revision))
471     {
472     case 0:
473       domain->nstrings = W (domain->must_swap, data->nstrings);
474       domain->orig_tab = (struct string_desc *)
475 	((char *) data + W (domain->must_swap, data->orig_tab_offset));
476       domain->trans_tab = (struct string_desc *)
477 	((char *) data + W (domain->must_swap, data->trans_tab_offset));
478       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
479       domain->hash_tab = (nls_uint32 *)
480 	((char *) data + W (domain->must_swap, data->hash_tab_offset));
481       break;
482     default:
483       /* This is an invalid revision.  */
484 #ifdef HAVE_MMAP
485       if (use_mmap)
486 	munmap ((caddr_t) data, size);
487       else
488 #endif
489 	free (data);
490       free (domain);
491       domain_file->data = NULL;
492       return;
493     }
494 
495   /* Now initialize the character set converter from the character set
496      the file is encoded with (found in the header entry) to the domain's
497      specified character set or the locale's character set.  */
498   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
499 
500   /* Also look for a plural specification.  */
501   if (nullentry != NULL)
502     {
503       const char *plural;
504       const char *nplurals;
505 
506       plural = strstr (nullentry, "plural=");
507       nplurals = strstr (nullentry, "nplurals=");
508       if (plural == NULL || nplurals == NULL)
509 	goto no_plural;
510       else
511 	{
512 	  /* First get the number.  */
513 	  char *endp;
514 	  unsigned long int n;
515 	  struct parse_args args;
516 
517 	  nplurals += 9;
518 	  while (*nplurals != '\0' && isspace (*nplurals))
519 	    ++nplurals;
520 #if defined HAVE_STRTOUL || defined _LIBC
521 	  n = strtoul (nplurals, &endp, 10);
522 #else
523 	  for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
524 	    n = n * 10 + (*endp - '0');
525 #endif
526 	  domain->nplurals = n;
527 	  if (nplurals == endp)
528 	    goto no_plural;
529 
530 	  /* Due to the restrictions bison imposes onto the interface of the
531 	     scanner function we have to put the input string and the result
532 	     passed up from the parser into the same structure which address
533 	     is passed down to the parser.  */
534 	  plural += 7;
535 	  args.cp = plural;
536 	  if (PLURAL_PARSE (&args) != 0)
537 	    goto no_plural;
538 	  domain->plural = args.res;
539 	}
540     }
541   else
542     {
543       /* By default we are using the Germanic form: singular form only
544          for `one', the plural form otherwise.  Yes, this is also what
545          English is using since English is a Germanic language.  */
546     no_plural:
547       INIT_GERMANIC_PLURAL ();
548       domain->plural = &germanic_plural;
549       domain->nplurals = 2;
550     }
551 }
552 
553 
554 #ifdef _LIBC
555 void
556 internal_function
_nl_unload_domain(domain)557 _nl_unload_domain (domain)
558      struct loaded_domain *domain;
559 {
560   if (domain->plural != &germanic_plural)
561     __gettext_free_exp (domain->plural);
562 
563   _nl_free_domain_conv (domain);
564 
565 # ifdef _POSIX_MAPPED_FILES
566   if (domain->use_mmap)
567     munmap ((caddr_t) domain->data, domain->mmap_size);
568   else
569 # endif	/* _POSIX_MAPPED_FILES */
570     free ((void *) domain->data);
571 
572   free (domain);
573 }
574 #endif
575