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 02139, 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 loaded_l10nfile
00096 {
00097   const char *filename;
00098   int decided;
00099 
00100   const void *data;
00101 
00102   loaded_l10nfile() : filename(0), decided(0), data(0) {}
00103 };
00104 
00105 void k_nl_load_domain(struct 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 loaded_l10nfile *domain_file,
00159             const char *msgid);
00160 
00161 char *
00162 k_nl_find_msg (struct 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 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 kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:48 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001