1 /* Load needed message catalogs. 2 Copyright (C) 1995, 1996, 1997, 1998 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 #ifdef HAVE_CONFIG_H 19 # include <config.h> 20 #endif 21 22 #include <fcntl.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 26 #if defined STDC_HEADERS || defined _LIBC 27 # include <stdlib.h> 28 #endif 29 30 #if defined HAVE_UNISTD_H || defined _LIBC 31 # include <unistd.h> 32 #endif 33 34 #if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC 35 # include <sys/mman.h> 36 #endif 37 38 #include "gettext.h" 39 #include "gettextP.h" 40 41 /* @@ end of prolog @@ */ 42 43 #ifdef _LIBC 44 /* Rename the non ISO C functions. This is required by the standard 45 because some ISO C functions will require linking with this object 46 file and the name space must not be polluted. */ 47 # define open __open 48 # define close __close 49 # define read __read 50 # define mmap __mmap 51 # define munmap __munmap 52 #endif 53 54 /* We need a sign, whether a new catalog was loaded, which can be associated 55 with all translations. This is important if the translations are 56 cached by one of GCC's features. */ 57 int _nl_msg_cat_cntr = 0; 58 59 60 /* Load the message catalogs specified by FILENAME. If it is no valid 61 message catalog do nothing. */ 62 void 63 internal_function 64 _nl_load_domain (domain_file) 65 struct loaded_l10nfile *domain_file; 66 { 67 int fd; 68 size_t size; 69 struct stat st; 70 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 int use_mmap = 0; 74 #endif 75 struct loaded_domain *domain; 76 77 domain_file->decided = 1; 78 domain_file->data = NULL; 79 80 /* If the record does not represent a valid locale the FILENAME 81 might be NULL. This can happen when according to the given 82 specification the locale file name is different for XPG and CEN 83 syntax. */ 84 if (domain_file->filename == NULL) 85 return; 86 87 /* Try to open the addressed file. */ 88 fd = open (domain_file->filename, O_RDONLY); 89 if (fd == -1) 90 return; 91 92 /* 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)) 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, 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 size_t to_read; 122 char *read_ptr; 123 124 data = (struct mo_file_header *) malloc (size); 125 if (data == NULL) 126 return; 127 128 to_read = 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, 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 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 170 || defined _LIBC 171 domain->use_mmap = use_mmap; 172 #endif 173 domain->mmap_size = size; 174 domain->must_swap = data->magic != _MAGIC; 175 176 /* Fill in the information about the available tables. */ 177 switch (W (domain->must_swap, data->revision)) 178 { 179 case 0: 180 domain->nstrings = W (domain->must_swap, data->nstrings); 181 domain->orig_tab = (struct string_desc *) 182 ((char *) data + W (domain->must_swap, data->orig_tab_offset)); 183 domain->trans_tab = (struct string_desc *) 184 ((char *) data + W (domain->must_swap, data->trans_tab_offset)); 185 domain->hash_size = W (domain->must_swap, data->hash_tab_size); 186 domain->hash_tab = (nls_uint32 *) 187 ((char *) data + W (domain->must_swap, data->hash_tab_offset)); 188 break; 189 default: 190 /* This is an illegal revision. */ 191 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 192 || defined _LIBC 193 if (use_mmap) 194 munmap ((caddr_t) data, size); 195 else 196 #endif 197 free (data); 198 free (domain); 199 domain_file->data = NULL; 200 return; 201 } 202 203 /* Show that one domain is changed. This might make some cached 204 translations invalid. */ 205 ++_nl_msg_cat_cntr; 206 } 207 208 209 #ifdef _LIBC 210 void 211 internal_function 212 _nl_unload_domain (domain) 213 struct loaded_domain *domain; 214 { 215 if (domain->use_mmap) 216 munmap ((caddr_t) domain->data, domain->mmap_size); 217 else 218 free ((void *) domain->data); 219 220 free (domain); 221 } 222 #endif 223