OSDN Git Service

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