~ubuntu-branches/ubuntu/saucy/groundhog/saucy

« back to all changes in this revision

Viewing changes to intl/loadmsgcat.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2003-06-18 19:46:15 UTC
  • mto: (2.1.1 warty)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20030618194615-sztk57bkfjhmctl4
Tags: upstream-1.4
ImportĀ upstreamĀ versionĀ 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Load needed message catalogs.
2
 
   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
 
2
   Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3
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)
 
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
7
   any later version.
8
8
 
9
9
   This program is distributed in the hope that it will be useful,
10
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.  */
 
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
17
25
 
18
26
#ifdef HAVE_CONFIG_H
19
27
# include <config.h>
20
28
#endif
21
29
 
 
30
#include <ctype.h>
 
31
#include <errno.h>
22
32
#include <fcntl.h>
23
33
#include <sys/types.h>
24
34
#include <sys/stat.h>
25
35
 
26
 
#if defined STDC_HEADERS || defined _LIBC
27
 
# include <stdlib.h>
 
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
28
51
#endif
29
52
 
 
53
#include <stdlib.h>
 
54
#include <string.h>
 
55
 
30
56
#if defined HAVE_UNISTD_H || defined _LIBC
31
57
# include <unistd.h>
32
58
#endif
33
59
 
34
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC
 
60
#ifdef _LIBC
 
61
# include <langinfo.h>
 
62
# include <locale.h>
 
63
#endif
 
64
 
 
65
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
 
66
    || (defined _LIBC && defined _POSIX_MAPPED_FILES)
35
67
# include <sys/mman.h>
 
68
# undef HAVE_MMAP
 
69
# define HAVE_MMAP      1
 
70
#else
 
71
# undef HAVE_MMAP
36
72
#endif
37
73
 
38
 
#include "gettext.h"
 
74
#include "gmo.h"
39
75
#include "gettextP.h"
 
76
#include "plural-exp.h"
 
77
 
 
78
#ifdef _LIBC
 
79
# include "../locale/localeinfo.h"
 
80
#endif
40
81
 
41
82
/* @@ end of prolog @@ */
42
83
 
51
92
# define munmap __munmap
52
93
#endif
53
94
 
 
95
/* For those losing systems which don't have `alloca' we have to add
 
96
   some additional code emulating it.  */
 
97
#ifdef HAVE_ALLOCA
 
98
# define freea(p) /* nothing */
 
99
#else
 
100
# define alloca(n) malloc (n)
 
101
# define freea(p) free (p)
 
102
#endif
 
103
 
 
104
/* For systems that distinguish between text and binary I/O.
 
105
   O_BINARY is usually declared in <fcntl.h>. */
 
106
#if !defined O_BINARY && defined _O_BINARY
 
107
  /* For MSC-compatible compilers.  */
 
108
# define O_BINARY _O_BINARY
 
109
# define O_TEXT _O_TEXT
 
110
#endif
 
111
#ifdef __BEOS__
 
112
  /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
 
113
# undef O_BINARY
 
114
# undef O_TEXT
 
115
#endif
 
116
/* On reasonable systems, binary I/O is the default.  */
 
117
#ifndef O_BINARY
 
118
# define O_BINARY 0
 
119
#endif
 
120
 
54
121
/* We need a sign, whether a new catalog was loaded, which can be associated
55
122
   with all translations.  This is important if the translations are
56
123
   cached by one of GCC's features.  */
57
 
int _nl_msg_cat_cntr = 0;
58
 
 
 
124
int _nl_msg_cat_cntr;
 
125
 
 
126
 
 
127
/* Initialize the codeset dependent parts of an opened message catalog.
 
128
   Return the header entry.  */
 
129
const char *
 
130
internal_function
 
131
_nl_init_domain_conv (domain_file, domain, domainbinding)
 
132
     struct loaded_l10nfile *domain_file;
 
133
     struct loaded_domain *domain;
 
134
     struct binding *domainbinding;
 
135
{
 
136
  /* Find out about the character set the file is encoded with.
 
137
     This can be found (in textual form) in the entry "".  If this
 
138
     entry does not exist or if this does not contain the `charset='
 
139
     information, we will assume the charset matches the one the
 
140
     current locale and we don't have to perform any conversion.  */
 
141
  char *nullentry;
 
142
  size_t nullentrylen;
 
143
 
 
144
  /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
 
145
  domain->codeset_cntr =
 
146
    (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
 
147
#ifdef _LIBC
 
148
  domain->conv = (__gconv_t) -1;
 
149
#else
 
150
# if HAVE_ICONV
 
151
  domain->conv = (iconv_t) -1;
 
152
# endif
 
153
#endif
 
154
  domain->conv_tab = NULL;
 
155
 
 
156
  /* Get the header entry.  */
 
157
  nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
 
158
 
 
159
  if (nullentry != NULL)
 
160
    {
 
161
#if defined _LIBC || HAVE_ICONV
 
162
      const char *charsetstr;
 
163
 
 
164
      charsetstr = strstr (nullentry, "charset=");
 
165
      if (charsetstr != NULL)
 
166
        {
 
167
          size_t len;
 
168
          char *charset;
 
169
          const char *outcharset;
 
170
 
 
171
          charsetstr += strlen ("charset=");
 
172
          len = strcspn (charsetstr, " \t\n");
 
173
 
 
174
          charset = (char *) alloca (len + 1);
 
175
# if defined _LIBC || HAVE_MEMPCPY
 
176
          *((char *) mempcpy (charset, charsetstr, len)) = '\0';
 
177
# else
 
178
          memcpy (charset, charsetstr, len);
 
179
          charset[len] = '\0';
 
180
# endif
 
181
 
 
182
          /* The output charset should normally be determined by the
 
183
             locale.  But sometimes the locale is not used or not correctly
 
184
             set up, so we provide a possibility for the user to override
 
185
             this.  Moreover, the value specified through
 
186
             bind_textdomain_codeset overrides both.  */
 
187
          if (domainbinding != NULL && domainbinding->codeset != NULL)
 
188
            outcharset = domainbinding->codeset;
 
189
          else
 
190
            {
 
191
              outcharset = getenv ("OUTPUT_CHARSET");
 
192
              if (outcharset == NULL || outcharset[0] == '\0')
 
193
                {
 
194
# ifdef _LIBC
 
195
                  outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
 
196
# else
 
197
#  if HAVE_ICONV
 
198
                  extern const char *locale_charset PARAMS ((void));
 
199
                  outcharset = locale_charset ();
 
200
#  endif
 
201
# endif
 
202
                }
 
203
            }
 
204
 
 
205
# ifdef _LIBC
 
206
          /* We always want to use transliteration.  */
 
207
          outcharset = norm_add_slashes (outcharset, "TRANSLIT");
 
208
          charset = norm_add_slashes (charset, NULL);
 
209
          if (__gconv_open (outcharset, charset, &domain->conv,
 
210
                            GCONV_AVOID_NOCONV)
 
211
              != __GCONV_OK)
 
212
            domain->conv = (__gconv_t) -1;
 
213
# else
 
214
#  if HAVE_ICONV
 
215
          /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
 
216
             we want to use transliteration.  */
 
217
#   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
 
218
       || _LIBICONV_VERSION >= 0x0105
 
219
          len = strlen (outcharset);
 
220
          {
 
221
            char *tmp = (char *) alloca (len + 10 + 1);
 
222
            memcpy (tmp, outcharset, len);
 
223
            memcpy (tmp + len, "//TRANSLIT", 10 + 1);
 
224
            outcharset = tmp;
 
225
          }
 
226
#   endif
 
227
          domain->conv = iconv_open (outcharset, charset);
 
228
#   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
 
229
       || _LIBICONV_VERSION >= 0x0105
 
230
          freea (outcharset);
 
231
#   endif
 
232
#  endif
 
233
# endif
 
234
 
 
235
          freea (charset);
 
236
        }
 
237
#endif /* _LIBC || HAVE_ICONV */
 
238
    }
 
239
 
 
240
  return nullentry;
 
241
}
 
242
 
 
243
/* Frees the codeset dependent parts of an opened message catalog.  */
 
244
void
 
245
internal_function
 
246
_nl_free_domain_conv (domain)
 
247
     struct loaded_domain *domain;
 
248
{
 
249
  if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
 
250
    free (domain->conv_tab);
 
251
 
 
252
#ifdef _LIBC
 
253
  if (domain->conv != (__gconv_t) -1)
 
254
    __gconv_close (domain->conv);
 
255
#else
 
256
# if HAVE_ICONV
 
257
  if (domain->conv != (iconv_t) -1)
 
258
    iconv_close (domain->conv);
 
259
# endif
 
260
#endif
 
261
}
59
262
 
60
263
/* Load the message catalogs specified by FILENAME.  If it is no valid
61
264
   message catalog do nothing.  */
62
265
void
63
266
internal_function
64
 
_nl_load_domain (domain_file)
 
267
_nl_load_domain (domain_file, domainbinding)
65
268
     struct loaded_l10nfile *domain_file;
 
269
     struct binding *domainbinding;
66
270
{
67
271
  int fd;
68
272
  size_t size;
 
273
#ifdef _LIBC
 
274
  struct stat64 st;
 
275
#else
69
276
  struct stat st;
 
277
#endif
70
278
  struct mo_file_header *data = (struct mo_file_header *) -1;
71
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
72
 
    || defined _LIBC
73
279
  int use_mmap = 0;
74
 
#endif
75
280
  struct loaded_domain *domain;
 
281
  const char *nullentry;
76
282
 
77
283
  domain_file->decided = 1;
78
284
  domain_file->data = NULL;
79
285
 
 
286
  /* Note that it would be useless to store domainbinding in domain_file
 
287
     because domainbinding might be == NULL now but != NULL later (after
 
288
     a call to bind_textdomain_codeset).  */
 
289
 
80
290
  /* If the record does not represent a valid locale the FILENAME
81
291
     might be NULL.  This can happen when according to the given
82
292
     specification the locale file name is different for XPG and CEN
85
295
    return;
86
296
 
87
297
  /* Try to open the addressed file.  */
88
 
  fd = open (domain_file->filename, O_RDONLY);
 
298
  fd = open (domain_file->filename, O_RDONLY | O_BINARY);
89
299
  if (fd == -1)
90
300
    return;
91
301
 
92
302
  /* We must know about the size of the file.  */
93
 
  if (fstat (fd, &st) != 0
94
 
      || (size = (size_t) st.st_size) != st.st_size
95
 
      || size < sizeof (struct mo_file_header))
 
303
  if (
 
304
#ifdef _LIBC
 
305
      __builtin_expect (fstat64 (fd, &st) != 0, 0)
 
306
#else
 
307
      __builtin_expect (fstat (fd, &st) != 0, 0)
 
308
#endif
 
309
      || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
 
310
      || __builtin_expect (size < sizeof (struct mo_file_header), 0))
96
311
    {
97
312
      /* Something went wrong.  */
98
313
      close (fd);
99
314
      return;
100
315
    }
101
316
 
102
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
103
 
    || defined _LIBC
 
317
#ifdef HAVE_MMAP
104
318
  /* Now we are ready to load the file.  If mmap() is available we try
105
319
     this first.  If not available or it failed we try to load it.  */
106
320
  data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
107
321
                                         MAP_PRIVATE, fd, 0);
108
322
 
109
 
  if (data != (struct mo_file_header *) -1)
 
323
  if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
110
324
    {
111
325
      /* mmap() call was successful.  */
112
326
      close (fd);
130
344
      do
131
345
        {
132
346
          long int nb = (long int) read (fd, read_ptr, to_read);
133
 
          if (nb == -1)
 
347
          if (nb <= 0)
134
348
            {
 
349
#ifdef EINTR
 
350
              if (nb == -1 && errno == EINTR)
 
351
                continue;
 
352
#endif
135
353
              close (fd);
136
354
              return;
137
355
            }
138
 
 
139
356
          read_ptr += nb;
140
357
          to_read -= nb;
141
358
        }
146
363
 
147
364
  /* Using the magic number we can test whether it really is a message
148
365
     catalog file.  */
149
 
  if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
 
366
  if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
 
367
                        0))
150
368
    {
151
369
      /* The magic number is wrong: not a message catalog file.  */
152
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
153
 
    || defined _LIBC
 
370
#ifdef HAVE_MMAP
154
371
      if (use_mmap)
155
372
        munmap ((caddr_t) data, size);
156
373
      else
159
376
      return;
160
377
    }
161
378
 
162
 
  domain_file->data
163
 
    = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
164
 
  if (domain_file->data == NULL)
 
379
  domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
 
380
  if (domain == NULL)
165
381
    return;
 
382
  domain_file->data = domain;
166
383
 
167
 
  domain = (struct loaded_domain *) domain_file->data;
168
384
  domain->data = (char *) data;
169
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
170
 
    || defined _LIBC
171
385
  domain->use_mmap = use_mmap;
172
 
#endif
173
386
  domain->mmap_size = size;
174
387
  domain->must_swap = data->magic != _MAGIC;
175
388
 
187
400
        ((char *) data + W (domain->must_swap, data->hash_tab_offset));
188
401
      break;
189
402
    default:
190
 
      /* This is an illegal revision.  */
191
 
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
192
 
    || defined _LIBC
 
403
      /* This is an invalid revision.  */
 
404
#ifdef HAVE_MMAP
193
405
      if (use_mmap)
194
406
        munmap ((caddr_t) data, size);
195
407
      else
200
412
      return;
201
413
    }
202
414
 
203
 
  /* Show that one domain is changed.  This might make some cached
204
 
     translations invalid.  */
205
 
  ++_nl_msg_cat_cntr;
 
415
  /* Now initialize the character set converter from the character set
 
416
     the file is encoded with (found in the header entry) to the domain's
 
417
     specified character set or the locale's character set.  */
 
418
  nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
 
419
 
 
420
  /* Also look for a plural specification.  */
 
421
  EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
206
422
}
207
423
 
208
424
 
212
428
_nl_unload_domain (domain)
213
429
     struct loaded_domain *domain;
214
430
{
 
431
  if (domain->plural != &__gettext_germanic_plural)
 
432
    __gettext_free_exp (domain->plural);
 
433
 
 
434
  _nl_free_domain_conv (domain);
 
435
 
 
436
# ifdef _POSIX_MAPPED_FILES
215
437
  if (domain->use_mmap)
216
438
    munmap ((caddr_t) domain->data, domain->mmap_size);
217
439
  else
 
440
# endif /* _POSIX_MAPPED_FILES */
218
441
    free ((void *) domain->data);
219
442
 
220
443
  free (domain);