Update.
[platform/upstream/glibc.git] / intl / loadmsgcat.c
1 /* Load needed message catalogs.
2    Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
3
4    This file is part of the GNU C Library.  Its master source is NOT part of
5    the C library, however.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Library General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Library General Public License for more details.
16
17    You should have received a copy of the GNU Library General Public
18    License along with the GNU C Library; see the file COPYING.LIB.  If not,
19    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #if defined STDC_HEADERS || defined _LIBC
31 # include <stdlib.h>
32 #endif
33
34 #if defined HAVE_STRING_H || defined _LIBC
35 # ifndef _GNU_SOURCE
36 #  define _GNU_SOURCE   1
37 # endif
38 # include <string.h>
39 #else
40 # include <strings.h>
41 #endif
42
43 #if defined HAVE_UNISTD_H || defined _LIBC
44 # include <unistd.h>
45 #endif
46
47 #ifdef _LIBC
48 # include <langinfo.h>
49 #endif
50
51 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
52     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
53 # include <sys/mman.h>
54 # undef HAVE_MMAP
55 # define HAVE_MMAP      1
56 #else
57 # undef HAVE_MMAP
58 #endif
59
60 #include "gettext.h"
61 #include "gettextP.h"
62
63 #ifdef _LIBC
64 # include "../locale/localeinfo.h"
65 #endif
66
67 /* @@ end of prolog @@ */
68
69 #ifdef _LIBC
70 /* Rename the non ISO C functions.  This is required by the standard
71    because some ISO C functions will require linking with this object
72    file and the name space must not be polluted.  */
73 # define open   __open
74 # define close  __close
75 # define read   __read
76 # define mmap   __mmap
77 # define munmap __munmap
78 #endif
79
80 /* We need a sign, whether a new catalog was loaded, which can be associated
81    with all translations.  This is important if the translations are
82    cached by one of GCC's features.  */
83 int _nl_msg_cat_cntr;
84
85
86 /* Load the message catalogs specified by FILENAME.  If it is no valid
87    message catalog do nothing.  */
88 void
89 internal_function
90 _nl_load_domain (domain_file)
91      struct loaded_l10nfile *domain_file;
92 {
93   int fd;
94   size_t size;
95   struct stat st;
96   struct mo_file_header *data = (struct mo_file_header *) -1;
97   int use_mmap = 0;
98   struct loaded_domain *domain;
99   char *nullentry;
100
101   domain_file->decided = 1;
102   domain_file->data = NULL;
103
104   /* If the record does not represent a valid locale the FILENAME
105      might be NULL.  This can happen when according to the given
106      specification the locale file name is different for XPG and CEN
107      syntax.  */
108   if (domain_file->filename == NULL)
109     return;
110
111   /* Try to open the addressed file.  */
112   fd = open (domain_file->filename, O_RDONLY);
113   if (fd == -1)
114     return;
115
116   /* We must know about the size of the file.  */
117   if (fstat (fd, &st) != 0
118       || (size = (size_t) st.st_size) != st.st_size
119       || size < sizeof (struct mo_file_header))
120     {
121       /* Something went wrong.  */
122       close (fd);
123       return;
124     }
125
126 #ifdef HAVE_MMAP
127   /* Now we are ready to load the file.  If mmap() is available we try
128      this first.  If not available or it failed we try to load it.  */
129   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
130                                          MAP_PRIVATE, fd, 0);
131
132   if (data != (struct mo_file_header *) -1)
133     {
134       /* mmap() call was successful.  */
135       close (fd);
136       use_mmap = 1;
137     }
138 #endif
139
140   /* If the data is not yet available (i.e. mmap'ed) we try to load
141      it manually.  */
142   if (data == (struct mo_file_header *) -1)
143     {
144       size_t to_read;
145       char *read_ptr;
146
147       data = (struct mo_file_header *) malloc (size);
148       if (data == NULL)
149         return;
150
151       to_read = size;
152       read_ptr = (char *) data;
153       do
154         {
155           long int nb = (long int) read (fd, read_ptr, to_read);
156           if (nb == -1)
157             {
158               close (fd);
159               return;
160             }
161
162           read_ptr += nb;
163           to_read -= nb;
164         }
165       while (to_read > 0);
166
167       close (fd);
168     }
169
170   /* Using the magic number we can test whether it really is a message
171      catalog file.  */
172   if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
173     {
174       /* The magic number is wrong: not a message catalog file.  */
175 #ifdef HAVE_MMAP
176       if (use_mmap)
177         munmap ((caddr_t) data, size);
178       else
179 #endif
180         free (data);
181       return;
182     }
183
184   domain_file->data
185     = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
186   if (domain_file->data == NULL)
187     return;
188
189   domain = (struct loaded_domain *) domain_file->data;
190   domain->data = (char *) data;
191   domain->use_mmap = use_mmap;
192   domain->mmap_size = size;
193   domain->must_swap = data->magic != _MAGIC;
194
195   /* Fill in the information about the available tables.  */
196   switch (W (domain->must_swap, data->revision))
197     {
198     case 0:
199       domain->nstrings = W (domain->must_swap, data->nstrings);
200       domain->orig_tab = (struct string_desc *)
201         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
202       domain->trans_tab = (struct string_desc *)
203         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
204       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
205       domain->hash_tab = (nls_uint32 *)
206         ((char *) data + W (domain->must_swap, data->hash_tab_offset));
207       break;
208     default:
209       /* This is an invalid revision.  */
210 #ifdef HAVE_MMAP
211       if (use_mmap)
212         munmap ((caddr_t) data, size);
213       else
214 #endif
215         free (data);
216       free (domain);
217       domain_file->data = NULL;
218       return;
219     }
220
221   /* Now find out about the character set the file is encoded with.
222      This can be found (in textual form) in the entry "".  If this
223      entry does not exist or if this does not contain the `charset='
224      information, we will assume the charset matches the one the
225      current locale and we don't have to perform any conversion.  */
226 #if HAVE_ICONV || defined _LIBC
227   domain->conv = (iconv_t) -1;
228 #endif
229   nullentry = _nl_find_msg (domain_file, "");
230   if (nullentry != NULL)
231     {
232       char *charsetstr = strstr (nullentry, "charset=");
233
234       if (charsetstr != NULL)
235         {
236           size_t len;
237           char *charset;
238
239           charsetstr += strlen ("charset=");
240           len = strcspn (charsetstr, " \t\n");
241
242           charset = (char *) alloca (len + 1);
243 #if defined _LIBC || HAVE_MEMPCPY
244           *((char *) mempcpy (charset, charsetstr, len)) = '\0';
245 #else
246           memcpy (charset, charsetstr, len);
247           charset[len] = '\0';
248 #endif
249
250 #if HAVE_ICONV || defined _LIBC
251           domain->conv = iconv_open ((*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string, charset);
252 #endif
253         }
254     }
255 }
256
257
258 #ifdef _LIBC
259 void
260 internal_function
261 _nl_unload_domain (domain)
262      struct loaded_domain *domain;
263 {
264 #ifdef _POSIX_MAPPED_FILES
265   if (domain->use_mmap)
266     munmap ((caddr_t) domain->data, domain->mmap_size);
267   else
268 #endif  /* _POSIX_MAPPED_FILES */
269     free ((void *) domain->data);
270
271   free (domain);
272 }
273 #endif