kdecore Library API Documentation

libintl.cpp

00001 /* libintl.cpp -- gettext related functions from glibc-2.0.5 00002 Copyright (C) 1995 Software Foundation, Inc. 00003 00004 This file is part of the KDE libraries, but it's derived work out 00005 of glibc. The master sources can be found in 00006 00007 bindtextdom.c 00008 dcgettext.c 00009 dgettext.c 00010 explodename.c 00011 finddomain.c 00012 gettext.c 00013 gettext.h 00014 gettextP.h 00015 hash-string.h 00016 l10nflist.c 00017 libintl.h 00018 loadinfo.h 00019 loadmsgcat.c 00020 localealias.c 00021 textdomain.c 00022 00023 which are part of glibc. The license is the same as in GLIBC, which 00024 is the GNU Library General Public License. See COPYING.LIB for more 00025 details. 00026 00027 */ 00028 00029 /* gettext.c -- implementation of gettext(3) function 00030 Copyright (C) 1995 Software Foundation, Inc. 00031 00032 This file is part of the GNU C Library. Its master source is NOT part of 00033 the C library, however. The master source lives in /gd/gnu/lib. 00034 00035 The GNU C Library is free software; you can redistribute it and/or 00036 modify it under the terms of the GNU Library General Public License as 00037 published by the Free Software Foundation; either version 2 of the 00038 License, or (at your option) any later version. 00039 00040 The GNU C Library is distributed in the hope that it will be useful, 00041 but WITHOUT ANY WARRANTY; without even the implied warranty of 00042 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00043 Library General Public License for more details. 00044 00045 You should have received a copy of the GNU Library General Public 00046 License along with the GNU C Library; see the file COPYING.LIB. If 00047 not, write to the Free Software Foundation, Inc., 675 Mass Ave, 00048 Cambridge, MA 02111-1307, USA. */ 00049 00050 #include <config.h> 00051 00052 #include <qglobal.h> 00053 00054 #include <stdlib.h> 00055 00056 #if defined HAVE_STRING_H 00057 # include <string.h> 00058 #else 00059 # include <strings.h> 00060 #endif 00061 00062 #include <sys/types.h> 00063 #include <fcntl.h> 00064 #include <sys/stat.h> 00065 00066 #if defined HAVE_UNISTD_H 00067 # include <unistd.h> 00068 #endif 00069 00070 #if (defined HAVE_MMAP && defined HAVE_MUNMAP) 00071 # include <sys/mman.h> 00072 #endif 00073 00074 #ifndef W 00075 # define W(flag, data) ((flag) ? SWAP (data) : (data)) 00076 #endif 00077 00078 typedef Q_UINT32 nls_uint32; 00079 00080 struct loaded_domain 00081 { 00082 const char *data; 00083 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00084 int use_mmap; 00085 size_t mmap_size; 00086 #endif 00087 int must_swap; 00088 nls_uint32 nstrings; 00089 struct string_desc *orig_tab; 00090 struct string_desc *trans_tab; 00091 nls_uint32 hash_size; 00092 nls_uint32 *hash_tab; 00093 }; 00094 00095 struct kde_loaded_l10nfile 00096 { 00097 const char *filename; 00098 int decided; 00099 00100 const void *data; 00101 00102 kde_loaded_l10nfile() : filename(0), decided(0), data(0) {} 00103 }; 00104 00105 void k_nl_load_domain(struct kde_loaded_l10nfile *__domain); 00106 00107 static inline nls_uint32 00108 SWAP (nls_uint32 i) 00109 { 00110 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); 00111 } 00112 00113 /* @@ end of prolog @@ */ 00114 00115 /* The magic number of the GNU message catalog format. */ 00116 #define _MAGIC 0x950412de 00117 #define _MAGIC_SWAPPED 0xde120495 00118 00119 /* Revision number of the currently used .mo (binary) file format. */ 00120 #define MO_REVISION_NUMBER 0 00121 00122 00123 /* Defines the so called `hashpjw' function by P.J. Weinberger 00124 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, 00125 1986, 1987 Bell Telephone Laboratories, Inc.] */ 00126 static inline unsigned long hash_string (const char *__str_param); 00127 00128 /* @@ end of prolog @@ */ 00129 00130 /* Header for binary .mo file format. */ 00131 struct mo_file_header 00132 { 00133 /* The magic number. */ 00134 nls_uint32 magic; 00135 /* The revision number of the file format. */ 00136 nls_uint32 revision; 00137 /* The number of strings pairs. */ 00138 nls_uint32 nstrings; 00139 /* Offset of table with start offsets of original strings. */ 00140 nls_uint32 orig_tab_offset; 00141 /* Offset of table with start offsets of translation strings. */ 00142 nls_uint32 trans_tab_offset; 00143 /* Size of hashing table. */ 00144 nls_uint32 hash_tab_size; 00145 /* Offset of first hashing entry. */ 00146 nls_uint32 hash_tab_offset; 00147 }; 00148 00149 struct string_desc 00150 { 00151 /* Length of addressed string. */ 00152 nls_uint32 length; 00153 /* Offset of string in file. */ 00154 nls_uint32 offset; 00155 }; 00156 00157 /* Prototypes for local functions. */ 00158 char *k_nl_find_msg (struct kde_loaded_l10nfile *domain_file, 00159 const char *msgid); 00160 00161 char * 00162 k_nl_find_msg (struct kde_loaded_l10nfile *domain_file, const char *msgid) 00163 { 00164 size_t top, act, bottom; 00165 struct loaded_domain *domain; 00166 00167 if (domain_file->decided == 0) 00168 k_nl_load_domain (domain_file); 00169 00170 if (domain_file->data == NULL) 00171 return NULL; 00172 00173 domain = (struct loaded_domain *) domain_file->data; 00174 00175 /* Locate the MSGID and its translation. */ 00176 if (domain->hash_size > 2 && domain->hash_tab != NULL) 00177 { 00178 /* Use the hashing table. */ 00179 nls_uint32 len = strlen (msgid); 00180 nls_uint32 hash_val = hash_string (msgid); 00181 nls_uint32 idx = hash_val % domain->hash_size; 00182 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); 00183 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]); 00184 00185 if (nstr == 0) 00186 /* Hash table entry is empty. */ 00187 return NULL; 00188 00189 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len 00190 && strcmp (msgid, 00191 domain->data + W (domain->must_swap, 00192 domain->orig_tab[nstr - 1].offset)) == 0) 00193 return (char *) domain->data + W (domain->must_swap, 00194 domain->trans_tab[nstr - 1].offset); 00195 00196 while (1) 00197 { 00198 if (idx >= domain->hash_size - incr) 00199 idx -= domain->hash_size - incr; 00200 else 00201 idx += incr; 00202 00203 nstr = W (domain->must_swap, domain->hash_tab[idx]); 00204 if (nstr == 0) 00205 /* Hash table entry is empty. */ 00206 return NULL; 00207 00208 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len 00209 && strcmp (msgid, 00210 domain->data + W (domain->must_swap, 00211 domain->orig_tab[nstr - 1].offset)) 00212 == 0) 00213 return (char *) domain->data 00214 + W (domain->must_swap, domain->trans_tab[nstr - 1].offset); 00215 } 00216 /* NOTREACHED */ 00217 } 00218 00219 /* Now we try the default method: binary search in the sorted 00220 array of messages. */ 00221 bottom = 0; 00222 top = domain->nstrings; 00223 act = top; 00224 while (bottom < top) 00225 { 00226 int cmp_val; 00227 00228 act = (bottom + top) / 2; 00229 cmp_val = strcmp (msgid, domain->data 00230 + W (domain->must_swap, 00231 domain->orig_tab[act].offset)); 00232 if (cmp_val < 0) 00233 top = act; 00234 else if (cmp_val > 0) 00235 bottom = act + 1; 00236 else 00237 break; 00238 } 00239 00240 /* If an translation is found return this. */ 00241 return bottom >= top ? NULL : (char *) domain->data 00242 + W (domain->must_swap, 00243 domain->trans_tab[act].offset); 00244 } 00245 00246 /* @@ begin of epilog @@ */ 00247 /* We assume to have `unsigned long int' value with at least 32 bits. */ 00248 #define HASHWORDBITS 32 00249 00250 static inline unsigned long 00251 hash_string (const char *str_param) 00252 { 00253 unsigned long int hval, g; 00254 const char *str = str_param; 00255 00256 /* Compute the hash value for the given string. */ 00257 hval = 0; 00258 while (*str != '\0') 00259 { 00260 hval <<= 4; 00261 hval += (unsigned long) *str++; 00262 g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4)); 00263 if (g != 0) 00264 { 00265 hval ^= g >> (HASHWORDBITS - 8); 00266 hval ^= g; 00267 } 00268 } 00269 return hval; 00270 } 00271 00272 /* Load the message catalogs specified by FILENAME. If it is no valid 00273 message catalog do nothing. */ 00274 void 00275 k_nl_load_domain (struct kde_loaded_l10nfile *domain_file) 00276 { 00277 int fd; 00278 struct stat st; 00279 struct mo_file_header *data = (struct mo_file_header *) -1; 00280 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00281 int use_mmap = 0; 00282 #endif 00283 struct loaded_domain *domain; 00284 00285 domain_file->decided = 1; 00286 domain_file->data = NULL; 00287 00288 /* If the record does not represent a valid locale the FILENAME 00289 might be NULL. This can happen when according to the given 00290 specification the locale file name is different for XPG and CEN 00291 syntax. */ 00292 if (domain_file->filename == NULL) 00293 return; 00294 00295 /* Try to open the addressed file. */ 00296 fd = open (domain_file->filename, O_RDONLY); 00297 if (fd == -1) 00298 return; 00299 00300 /* We must know about the size of the file. */ 00301 if (fstat (fd, &st) != 0 00302 || st.st_size < (off_t) sizeof (struct mo_file_header)) 00303 { 00304 /* Something went wrong. */ 00305 close (fd); 00306 return; 00307 } 00308 00309 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00310 /* Now we are ready to load the file. If mmap() is available we try 00311 this first. If not available or it failed we try to load it. */ 00312 data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ, 00313 MAP_PRIVATE, fd, 0); 00314 00315 if (data != (struct mo_file_header *) -1) 00316 { 00317 /* mmap() call was successful. */ 00318 close (fd); 00319 use_mmap = 1; 00320 } 00321 #endif 00322 00323 /* If the data is not yet available (i.e. mmap'ed) we try to load 00324 it manually. */ 00325 if (data == (struct mo_file_header *) -1) 00326 { 00327 off_t to_read; 00328 char *read_ptr; 00329 00330 data = (struct mo_file_header *) malloc (st.st_size); 00331 if (data == NULL) 00332 return; 00333 00334 to_read = st.st_size; 00335 read_ptr = (char *) data; 00336 do 00337 { 00338 long int nb = (long int) read (fd, read_ptr, to_read); 00339 if (nb == -1) 00340 { 00341 close (fd); 00342 return; 00343 } 00344 00345 read_ptr += nb; 00346 to_read -= nb; 00347 } 00348 while (to_read > 0); 00349 00350 close (fd); 00351 } 00352 00353 /* Using the magic number we can test whether it really is a message 00354 catalog file. */ 00355 if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED) 00356 { 00357 /* The magic number is wrong: not a message catalog file. */ 00358 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00359 if (use_mmap) 00360 munmap ((char *) data, st.st_size); 00361 else 00362 #endif 00363 free (data); 00364 return; 00365 } 00366 00367 domain_file->data 00368 = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); 00369 if (domain_file->data == NULL) 00370 return; 00371 00372 domain = (struct loaded_domain *) domain_file->data; 00373 domain->data = (char *) data; 00374 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00375 domain->use_mmap = use_mmap; 00376 domain->mmap_size = st.st_size; 00377 #endif 00378 domain->must_swap = data->magic != _MAGIC; 00379 00380 /* Fill in the information about the available tables. */ 00381 switch (W (domain->must_swap, data->revision)) 00382 { 00383 case 0: 00384 domain->nstrings = W (domain->must_swap, data->nstrings); 00385 domain->orig_tab = (struct string_desc *) 00386 ((char *) data + W (domain->must_swap, data->orig_tab_offset)); 00387 domain->trans_tab = (struct string_desc *) 00388 ((char *) data + W (domain->must_swap, data->trans_tab_offset)); 00389 domain->hash_size = W (domain->must_swap, data->hash_tab_size); 00390 domain->hash_tab = (nls_uint32 *) 00391 ((char *) data + W (domain->must_swap, data->hash_tab_offset)); 00392 break; 00393 default: 00394 /* This is an illegal revision. */ 00395 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00396 if (use_mmap) 00397 munmap ((char *) data, st.st_size); 00398 else 00399 #endif 00400 free (data); 00401 free (domain); 00402 domain_file->data = NULL; 00403 return; 00404 } 00405 } 00406 00407 void 00408 k_nl_unload_domain (struct loaded_domain *domain) 00409 { 00410 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) 00411 if (domain->use_mmap) 00412 munmap ((caddr_t) domain->data, domain->mmap_size); 00413 else 00414 # endif 00415 free ((void *) domain->data); 00416 00417 free (domain); 00418 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:26:11 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003