1 /* Load needed message catalogs 2 Copyright (C) 1995, 1996, 1997 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 fstat __fstat 48 # define open __open 49 # define close __close 50 # define read __read 51 # define mmap __mmap 52 # define munmap __munmap 53 #endif 54 55 /* We need a sign, whether a new catalog was loaded, which can be associated 56 with all translations. This is important if the translations are 57 cached by one of GCC's features. */ 58 int _nl_msg_cat_cntr = 0; 59 60 61 /* Load the message catalogs specified by FILENAME. If it is no valid 62 message catalog do nothing. */ 63 void 64 _nl_load_domain (domain_file) 65 struct loaded_l10nfile *domain_file; 66 { 67 int fd; 68 struct stat st; 69 struct mo_file_header *data = (struct mo_file_header *) -1; 70 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 71 || defined _LIBC 72 int use_mmap = 0; 73 #endif 74 struct loaded_domain *domain; 75 76 domain_file->decided = 1; 77 domain_file->data = NULL; 78 79 /* If the record does not represent a valid locale the FILENAME 80 might be NULL. This can happen when according to the given 81 specification the locale file name is different for XPG and CEN 82 syntax. */ 83 if (domain_file->filename == NULL) 84 return; 85 86 /* Try to open the addressed file. */ 87 fd = open (domain_file->filename, O_RDONLY); 88 if (fd == -1) 89 return; 90 91 /* We must know about the size of the file. */ 92 if (fstat (fd, &st) != 0 93 && st.st_size < (off_t) sizeof (struct mo_file_header)) 94 { 95 /* Something went wrong. */ 96 close (fd); 97 return; 98 } 99 100 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 101 || defined _LIBC 102 /* Now we are ready to load the file. If mmap() is available we try 103 this first. If not available or it failed we try to load it. */ 104 data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ, 105 MAP_PRIVATE, fd, 0); 106 107 if (data != (struct mo_file_header *) -1) 108 { 109 /* mmap() call was successful. */ 110 close (fd); 111 use_mmap = 1; 112 } 113 #endif 114 115 /* If the data is not yet available (i.e. mmap'ed) we try to load 116 it manually. */ 117 if (data == (struct mo_file_header *) -1) 118 { 119 off_t to_read; 120 char *read_ptr; 121 122 data = (struct mo_file_header *) malloc (st.st_size); 123 if (data == NULL) 124 return; 125 126 to_read = st.st_size; 127 read_ptr = (char *) data; 128 do 129 { 130 long int nb = (long int) read (fd, read_ptr, to_read); 131 if (nb == -1) 132 { 133 close (fd); 134 return; 135 } 136 137 read_ptr += nb; 138 to_read -= nb; 139 } 140 while (to_read > 0); 141 142 close (fd); 143 } 144 145 /* Using the magic number we can test whether it really is a message 146 catalog file. */ 147 if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED) 148 { 149 /* The magic number is wrong: not a message catalog file. */ 150 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 151 || defined _LIBC 152 if (use_mmap) 153 munmap ((caddr_t) data, st.st_size); 154 else 155 #endif 156 free (data); 157 return; 158 } 159 160 domain_file->data 161 = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); 162 if (domain_file->data == NULL) 163 return; 164 165 domain = (struct loaded_domain *) domain_file->data; 166 domain->data = (char *) data; 167 domain->must_swap = data->magic != _MAGIC; 168 169 /* Fill in the information about the available tables. */ 170 switch (W (domain->must_swap, data->revision)) 171 { 172 case 0: 173 domain->nstrings = W (domain->must_swap, data->nstrings); 174 domain->orig_tab = (struct string_desc *) 175 ((char *) data + W (domain->must_swap, data->orig_tab_offset)); 176 domain->trans_tab = (struct string_desc *) 177 ((char *) data + W (domain->must_swap, data->trans_tab_offset)); 178 domain->hash_size = W (domain->must_swap, data->hash_tab_size); 179 domain->hash_tab = (nls_uint32 *) 180 ((char *) data + W (domain->must_swap, data->hash_tab_offset)); 181 break; 182 default: 183 /* This is an illegal revision. */ 184 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ 185 || defined _LIBC 186 if (use_mmap) 187 munmap ((caddr_t) data, st.st_size); 188 else 189 #endif 190 free (data); 191 free (domain); 192 domain_file->data = NULL; 193 return; 194 } 195 196 /* Show that one domain is changed. This might make some cached 197 translations invalid. */ 198 ++_nl_msg_cat_cntr; 199 } 200