~ubuntu-branches/ubuntu/raring/findutils/raring

« back to all changes in this revision

Viewing changes to intl/loadmsgcat.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2005-07-04 11:37:37 UTC
  • mto: (11.1.1 lenny) (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050704113737-oxfumqxsqgfz5gay
Tags: upstream-4.2.22
ImportĀ upstreamĀ versionĀ 4.2.22

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
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)
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
12
 
   GNU General Public License for more details.
13
 
 
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.  */
17
 
 
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.  */
21
 
#ifndef _GNU_SOURCE
22
 
# define _GNU_SOURCE    1
23
 
#endif
24
 
 
25
 
#ifdef HAVE_CONFIG_H
26
 
# include <gnulib/config.h>
27
 
# undef VERSION
28
 
# undef PACKAGE_VERSION
29
 
# undef PACKAGE_TARNAME
30
 
# undef PACKAGE_STRING
31
 
# include <config.h>
32
 
#endif
33
 
 
34
 
#include <ctype.h>
35
 
#include <errno.h>
36
 
#include <fcntl.h>
37
 
#include <sys/types.h>
38
 
#include <sys/stat.h>
39
 
 
40
 
#ifdef __GNUC__
41
 
# define alloca __builtin_alloca
42
 
# define HAVE_ALLOCA 1
43
 
#else
44
 
# if defined HAVE_ALLOCA_H || defined _LIBC
45
 
#  include <alloca.h>
46
 
# else
47
 
#  ifdef _AIX
48
 
 #pragma alloca
49
 
#  else
50
 
#   ifndef alloca
51
 
char *alloca ();
52
 
#   endif
53
 
#  endif
54
 
# endif
55
 
#endif
56
 
 
57
 
#include <stdlib.h>
58
 
#include <string.h>
59
 
 
60
 
#if defined HAVE_UNISTD_H || defined _LIBC
61
 
# include <unistd.h>
62
 
#endif
63
 
 
64
 
#ifdef _LIBC
65
 
# include <langinfo.h>
66
 
# include <locale.h>
67
 
#endif
68
 
 
69
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
70
 
    || (defined _LIBC && defined _POSIX_MAPPED_FILES)
71
 
# include <sys/mman.h>
72
 
# undef HAVE_MMAP
73
 
# define HAVE_MMAP      1
74
 
#else
75
 
# undef HAVE_MMAP
76
 
#endif
77
 
 
78
 
#include "gettext.h"
79
 
#include "gettextP.h"
80
 
 
81
 
#ifdef _LIBC
82
 
# include "../locale/localeinfo.h"
83
 
#endif
84
 
 
85
 
/* @@ end of prolog @@ */
86
 
 
87
 
#ifdef _LIBC
88
 
/* Rename the non ISO C functions.  This is required by the standard
89
 
   because some ISO C functions will require linking with this object
90
 
   file and the name space must not be polluted.  */
91
 
# define open   __open
92
 
# define close  __close
93
 
# define read   __read
94
 
# define mmap   __mmap
95
 
# define munmap __munmap
96
 
#endif
97
 
 
98
 
/* Names for the libintl functions are a problem.  They must not clash
99
 
   with existing names and they should follow ANSI C.  But this source
100
 
   code is also used in GNU C Library where the names have a __
101
 
   prefix.  So we have to make a difference here.  */
102
 
#ifdef _LIBC
103
 
# define PLURAL_PARSE __gettextparse
104
 
#else
105
 
# define PLURAL_PARSE gettextparse__
106
 
#endif
107
 
 
108
 
/* For those losing systems which don't have `alloca' we have to add
109
 
   some additional code emulating it.  */
110
 
#ifdef HAVE_ALLOCA
111
 
# define freea(p) /* nothing */
112
 
#else
113
 
# define alloca(n) malloc (n)
114
 
# define freea(p) free (p)
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
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
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
 
# if 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 || 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
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
 
# if 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
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) != 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
 
        return;
418
 
 
419
 
      to_read = size;
420
 
      read_ptr = (char *) data;
421
 
      do
422
 
        {
423
 
          long int nb = (long int) read (fd, read_ptr, to_read);
424
 
          if (nb <= 0)
425
 
            {
426
 
#ifdef EINTR
427
 
              if (nb == -1 && errno == EINTR)
428
 
                continue;
429
 
#endif
430
 
              close (fd);
431
 
              return;
432
 
            }
433
 
          read_ptr += nb;
434
 
          to_read -= nb;
435
 
        }
436
 
      while (to_read > 0);
437
 
 
438
 
      close (fd);
439
 
    }
440
 
 
441
 
  /* Using the magic number we can test whether it really is a message
442
 
     catalog file.  */
443
 
  if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
444
 
                        0))
445
 
    {
446
 
      /* The magic number is wrong: not a message catalog file.  */
447
 
#ifdef HAVE_MMAP
448
 
      if (use_mmap)
449
 
        munmap ((caddr_t) data, size);
450
 
      else
451
 
#endif
452
 
        free (data);
453
 
      return;
454
 
    }
455
 
 
456
 
  domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
457
 
  if (domain == NULL)
458
 
    return;
459
 
  domain_file->data = domain;
460
 
 
461
 
  domain->data = (char *) data;
462
 
  domain->use_mmap = use_mmap;
463
 
  domain->mmap_size = size;
464
 
  domain->must_swap = data->magic != _MAGIC;
465
 
 
466
 
  /* Fill in the information about the available tables.  */
467
 
  switch (W (domain->must_swap, data->revision))
468
 
    {
469
 
    case 0:
470
 
      domain->nstrings = W (domain->must_swap, data->nstrings);
471
 
      domain->orig_tab = (struct string_desc *)
472
 
        ((char *) data + W (domain->must_swap, data->orig_tab_offset));
473
 
      domain->trans_tab = (struct string_desc *)
474
 
        ((char *) data + W (domain->must_swap, data->trans_tab_offset));
475
 
      domain->hash_size = W (domain->must_swap, data->hash_tab_size);
476
 
      domain->hash_tab = (nls_uint32 *)
477
 
        ((char *) data + W (domain->must_swap, data->hash_tab_offset));
478
 
      break;
479
 
    default:
480
 
      /* This is an invalid revision.  */
481
 
#ifdef HAVE_MMAP
482
 
      if (use_mmap)
483
 
        munmap ((caddr_t) data, size);
484
 
      else
485
 
#endif
486
 
        free (data);
487
 
      free (domain);
488
 
      domain_file->data = NULL;
489
 
      return;
490
 
    }
491
 
 
492
 
  /* Now initialize the character set converter from the character set
493
 
     the file is encoded with (found in the header entry) to the domain's
494
 
     specified character set or the locale's character set.  */
495
 
  nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
496
 
 
497
 
  /* Also look for a plural specification.  */
498
 
  if (nullentry != NULL)
499
 
    {
500
 
      const char *plural;
501
 
      const char *nplurals;
502
 
 
503
 
      plural = strstr (nullentry, "plural=");
504
 
      nplurals = strstr (nullentry, "nplurals=");
505
 
      if (plural == NULL || nplurals == NULL)
506
 
        goto no_plural;
507
 
      else
508
 
        {
509
 
          /* First get the number.  */
510
 
          char *endp;
511
 
          unsigned long int n;
512
 
          struct parse_args args;
513
 
 
514
 
          nplurals += 9;
515
 
          while (*nplurals != '\0' && isspace (*nplurals))
516
 
            ++nplurals;
517
 
#if defined HAVE_STRTOUL || defined _LIBC
518
 
          n = strtoul (nplurals, &endp, 10);
519
 
#else
520
 
          for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
521
 
            n = n * 10 + (*endp - '0');
522
 
#endif
523
 
          domain->nplurals = n;
524
 
          if (nplurals == endp)
525
 
            goto no_plural;
526
 
 
527
 
          /* Due to the restrictions bison imposes onto the interface of the
528
 
             scanner function we have to put the input string and the result
529
 
             passed up from the parser into the same structure which address
530
 
             is passed down to the parser.  */
531
 
          plural += 7;
532
 
          args.cp = plural;
533
 
          if (PLURAL_PARSE (&args) != 0)
534
 
            goto no_plural;
535
 
          domain->plural = args.res;
536
 
        }
537
 
    }
538
 
  else
539
 
    {
540
 
      /* By default we are using the Germanic form: singular form only
541
 
         for `one', the plural form otherwise.  Yes, this is also what
542
 
         English is using since English is a Germanic language.  */
543
 
    no_plural:
544
 
      INIT_GERMANIC_PLURAL ();
545
 
      domain->plural = &germanic_plural;
546
 
      domain->nplurals = 2;
547
 
    }
548
 
}
549
 
 
550
 
 
551
 
#ifdef _LIBC
552
 
void
553
 
internal_function
554
 
_nl_unload_domain (domain)
555
 
     struct loaded_domain *domain;
556
 
{
557
 
  if (domain->plural != &germanic_plural)
558
 
    __gettext_free_exp (domain->plural);
559
 
 
560
 
  _nl_free_domain_conv (domain);
561
 
 
562
 
# ifdef _POSIX_MAPPED_FILES
563
 
  if (domain->use_mmap)
564
 
    munmap ((caddr_t) domain->data, domain->mmap_size);
565
 
  else
566
 
# endif /* _POSIX_MAPPED_FILES */
567
 
    free ((void *) domain->data);
568
 
 
569
 
  free (domain);
570
 
}
571
 
#endif