Sun May 26 19:39:53 1996 Ulrich Drepper <drepper@cygnus.com>
[kopensolaris-gnu/glibc.git] / intl / loadmsgcat.c
1 /* loadmsgcat.c -- load needed message catalogs
2 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27
28 #if defined STDC_HEADERS || defined _LIBC
29 # include <stdlib.h>
30 #endif
31
32 #if defined HAVE_UNISTD_H || defined _LIBC
33 # include <unistd.h>
34 #endif
35
36 #if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC
37 # include <sys/mman.h>
38 #endif
39
40 #include "gettext.h"
41 #include "gettextP.h"
42
43 /* @@ end of prolog @@ */
44
45 #ifdef _LIBC
46 /* Rename the non ANSI C functions.  This is required by the standard
47    because some ANSI C functions will require linking with this object
48    file and the name space must not be polluted.  */
49 # define fstat  __fstat
50 # define open   __open
51 # define close  __close
52 # define read   __read
53 # define mmap   __mmap
54 # define munmap __munmap
55 #endif
56
57 /* We need a sign, whether a new catalog was loaded, which can be associated
58    with all translations.  This is important if the translations are
59    cached by one of GCC's features.  */
60 int _nl_msg_cat_cntr;
61
62
63 /* Load the message catalogs specified by FILENAME.  If it is no valid
64    message catalog do nothing.  */
65 void
66 _nl_load_domain (domain_file)
67      struct loaded_l10nfile *domain_file;
68 {
69   int fd;
70   struct stat st;
71   struct mo_file_header *data = (struct mo_file_header *) -1;
72 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
73     || defined _LIBC
74   int use_mmap = 0;
75 #endif
76   struct loaded_domain *domain;
77
78   domain_file->decided = 1;
79   domain_file->data = NULL;
80
81   /* If the record does not represent a valid locale the FILENAME
82      might be NULL.  This can happen when according to the given
83      specification the locale file name is different for XPG and CEN
84      syntax.  */
85   if (domain_file->filename == NULL)
86     return;
87
88   /* Try to open the addressed file.  */
89   fd = open (domain_file->filename, O_RDONLY);
90   if (fd == -1)
91     return;
92
93   /* We must know about the size of the file.  */
94   if (fstat (fd, &st) != 0
95       && st.st_size < (off_t) sizeof (struct mo_file_header))
96     {
97       /* Something went wrong.  */
98       close (fd);
99       return;
100     }
101
102 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
103     || defined _LIBC
104   /* Now we are ready to load the file.  If mmap() is available we try
105      this first.  If not available or it failed we try to load it.  */
106   data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ,
107                                          MAP_PRIVATE, fd, 0);
108
109   if (data != (struct mo_file_header *) -1)
110     {
111       /* mmap() call was successful.  */
112       close (fd);
113       use_mmap = 1;
114     }
115 #endif
116
117   /* If the data is not yet available (i.e. mmap'ed) we try to load
118      it manually.  */
119   if (data == (struct mo_file_header *) -1)
120     {
121       off_t to_read;
122       char *read_ptr;
123
124       data = (struct mo_file_header *) malloc (st.st_size);
125       if (data == NULL)
126         return;
127
128       to_read = st.st_size;
129       read_ptr = (char *) data;
130       do
131         {
132           long int nb = (long int) read (fd, read_ptr, to_read);
133           if (nb == -1)
134             {
135               close (fd);
136               return;
137             }
138
139           read_ptr += nb;
140           to_read -= nb;
141         }
142       while (to_read > 0);
143
144       close (fd);
145     }
146
147   /* Using the magic number we can test whether it really is a message
148      catalog file.  */
149   if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
150     {
151       /* The magic number is wrong: not a message catalog file.  */
152 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
153     || defined _LIBC
154       if (use_mmap)
155         munmap ((caddr_t) data, st.st_size);
156       else
157 #endif
158         free (data);
159       return;
160     }
161
162   domain_file->data
163     = (struct loaded_domain *) malloc (sizeof (struct loaded_domain *));
164   if (domain_file->data == NULL)
165     return;
166
167   domain = (struct loaded_domain *) domain_file->data;
168   domain->data = (char *) data;
169   domain->must_swap = data->magic != _MAGIC;
170
171   /* Fill in the information about the available tables.  */
172   switch (W (domain->must_swap, data->revision))
173     {
174     case 0:
175       domain->nstrings = W (domain->must_swap, data->nstrings);
176       domain->orig_tab = (struct string_desc *)
177         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
178       domain->trans_tab = (struct string_desc *)
179         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
180       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
181       domain->hash_tab = (nls_uint32 *)
182         ((char *) data + W (domain->must_swap, data->hash_tab_offset));
183       break;
184     default:
185       /* This is an illegal revision.  */
186 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
187     || defined _LIBC
188       if (use_mmap)
189         munmap ((caddr_t) data, st.st_size);
190       else
191 #endif
192         free (data);
193       free (domain);
194       domain_file->data = NULL;
195       return;
196     }
197
198   /* Show that one domain is changed.  This might make some cached
199      translations invalid.  */
200   ++_nl_msg_cat_cntr;
201 }