• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

libintl.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00048 Boston, MA 02110-1301, USA.  */
00049 
00050 #include "kdelibs_export.h"
00051 #include "kde_file.h"
00052 #include <config.h>
00053 
00054 #include <qglobal.h>
00055 
00056 #include <stdlib.h>
00057 
00058 #if defined HAVE_STRING_H
00059 # include <string.h>
00060 #else
00061 # include <strings.h>
00062 #endif
00063 
00064 #include <sys/types.h>
00065 #include <fcntl.h>
00066 #include <sys/stat.h>
00067 
00068 #if defined HAVE_UNISTD_H
00069 # include <unistd.h>
00070 #endif
00071 
00072 #if (defined HAVE_MMAP && defined HAVE_MUNMAP)
00073 # include <sys/mman.h>
00074 #endif
00075 
00076 #ifndef W
00077 # define W(flag, data) ((flag) ? SWAP (data) : (data))
00078 #endif
00079 
00080 typedef Q_UINT32 nls_uint32;
00081 
00082 struct loaded_domain
00083 {
00084   const char *data;
00085 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00086   int use_mmap;
00087   size_t mmap_size;
00088 #endif
00089   int must_swap;
00090   nls_uint32 nstrings;
00091   struct string_desc *orig_tab;
00092   struct string_desc *trans_tab;
00093   nls_uint32 hash_size;
00094   nls_uint32 *hash_tab;
00095 };
00096 
00097 struct kde_loaded_l10nfile
00098 {
00099   const char *filename;
00100   int decided;
00101 
00102   const void *data;
00103 
00104   kde_loaded_l10nfile() : filename(0), decided(0), data(0) {}
00105 };
00106 
00107 void k_nl_load_domain(struct kde_loaded_l10nfile *__domain);
00108 
00109 static inline nls_uint32
00110 SWAP (nls_uint32  i)
00111 {
00112   return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
00113 }
00114 
00115 /* @@ end of prolog @@ */
00116 
00117 /* The magic number of the GNU message catalog format.  */
00118 #define _MAGIC 0x950412de
00119 #define _MAGIC_SWAPPED 0xde120495
00120 
00121 /* Revision number of the currently used .mo (binary) file format.  */
00122 #define MO_REVISION_NUMBER 0
00123 
00124 
00125 /* Defines the so called `hashpjw' function by P.J. Weinberger
00126    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
00127    1986, 1987 Bell Telephone Laboratories, Inc.]  */
00128 static inline unsigned long hash_string  (const char *__str_param);
00129 
00130 /* @@ end of prolog @@ */
00131 
00132 /* Header for binary .mo file format.  */
00133 struct mo_file_header
00134 {
00135   /* The magic number.  */
00136   nls_uint32 magic;
00137   /* The revision number of the file format.  */
00138   nls_uint32 revision;
00139   /* The number of strings pairs.  */
00140   nls_uint32 nstrings;
00141   /* Offset of table with start offsets of original strings.  */
00142   nls_uint32 orig_tab_offset;
00143   /* Offset of table with start offsets of translation strings.  */
00144   nls_uint32 trans_tab_offset;
00145   /* Size of hashing table.  */
00146   nls_uint32 hash_tab_size;
00147   /* Offset of first hashing entry.  */
00148   nls_uint32 hash_tab_offset;
00149 };
00150 
00151 struct string_desc
00152 {
00153   /* Length of addressed string.  */
00154   nls_uint32 length;
00155   /* Offset of string in file.  */
00156   nls_uint32 offset;
00157 };
00158 
00159 /* Prototypes for local functions.  */
00160 char *k_nl_find_msg  (struct kde_loaded_l10nfile *domain_file,
00161             const char *msgid);
00162 
00163 char *
00164 k_nl_find_msg (struct kde_loaded_l10nfile *domain_file, const char *msgid)
00165 {
00166   size_t top, act, bottom;
00167   struct loaded_domain *domain;
00168 
00169   if (domain_file->decided == 0)
00170     k_nl_load_domain (domain_file);
00171 
00172   if (domain_file->data == NULL)
00173     return NULL;
00174 
00175   domain = (struct loaded_domain *) domain_file->data;
00176 
00177   /* Locate the MSGID and its translation.  */
00178   if (domain->hash_size > 2 && domain->hash_tab != NULL)
00179     {
00180       /* Use the hashing table.  */
00181       nls_uint32 len = strlen (msgid);
00182       nls_uint32 hash_val = hash_string (msgid);
00183       nls_uint32 idx = hash_val % domain->hash_size;
00184       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
00185       nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
00186 
00187       if (nstr == 0)
00188     /* Hash table entry is empty.  */
00189     return NULL;
00190 
00191       if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
00192       && strcmp (msgid,
00193              domain->data + W (domain->must_swap,
00194                        domain->orig_tab[nstr - 1].offset)) == 0)
00195     return (char *) domain->data + W (domain->must_swap,
00196                       domain->trans_tab[nstr - 1].offset);
00197 
00198       while (1)
00199     {
00200       if (idx >= domain->hash_size - incr)
00201         idx -= domain->hash_size - incr;
00202       else
00203         idx += incr;
00204 
00205       nstr = W (domain->must_swap, domain->hash_tab[idx]);
00206       if (nstr == 0)
00207         /* Hash table entry is empty.  */
00208         return NULL;
00209 
00210       if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
00211           && strcmp (msgid,
00212              domain->data + W (domain->must_swap,
00213                        domain->orig_tab[nstr - 1].offset))
00214              == 0)
00215         return (char *) domain->data
00216           + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
00217     }
00218       /* NOTREACHED */
00219     }
00220 
00221   /* Now we try the default method:  binary search in the sorted
00222      array of messages.  */
00223   bottom = 0;
00224   top = domain->nstrings;
00225   act = top;
00226   while (bottom < top)
00227     {
00228       int cmp_val;
00229 
00230       act = (bottom + top) / 2;
00231       cmp_val = strcmp (msgid, domain->data
00232                    + W (domain->must_swap,
00233                     domain->orig_tab[act].offset));
00234       if (cmp_val < 0)
00235     top = act;
00236       else if (cmp_val > 0)
00237     bottom = act + 1;
00238       else
00239     break;
00240     }
00241 
00242   /* If an translation is found return this.  */
00243   return bottom >= top ? NULL : (char *) domain->data
00244                                 + W (domain->must_swap,
00245                      domain->trans_tab[act].offset);
00246 }
00247 
00248 /* @@ begin of epilog @@ */
00249 /* We assume to have `unsigned long int' value with at least 32 bits.  */
00250 #define HASHWORDBITS 32
00251 
00252 static inline unsigned long
00253 hash_string (const char *str_param)
00254 {
00255   unsigned long int hval, g;
00256   const char *str = str_param;
00257 
00258   /* Compute the hash value for the given string.  */
00259   hval = 0;
00260   while (*str != '\0')
00261     {
00262       hval <<= 4;
00263       hval += (unsigned long) *str++;
00264       g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
00265       if (g != 0)
00266     {
00267       hval ^= g >> (HASHWORDBITS - 8);
00268       hval ^= g;
00269     }
00270     }
00271   return hval;
00272 }
00273 
00274 /* Load the message catalogs specified by FILENAME.  If it is no valid
00275    message catalog do nothing.  */
00276 void
00277 k_nl_load_domain (struct kde_loaded_l10nfile *domain_file)
00278 {
00279   int fd;
00280   struct stat st;
00281   struct mo_file_header *data = (struct mo_file_header *) -1;
00282 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00283   int use_mmap = 0;
00284 #endif
00285   struct loaded_domain *domain;
00286 
00287   domain_file->decided = 1;
00288   domain_file->data = NULL;
00289 
00290   /* If the record does not represent a valid locale the FILENAME
00291      might be NULL.  This can happen when according to the given
00292      specification the locale file name is different for XPG and CEN
00293      syntax.  */
00294   if (domain_file->filename == NULL)
00295     return;
00296 
00297   /* Try to open the addressed file.  */
00298   fd = KDE_open (domain_file->filename, O_RDONLY);
00299   if (fd == -1)
00300     return;
00301 
00302   /* We must know about the size of the file.  */
00303   if (fstat (fd, &st) != 0
00304       || st.st_size < (off_t) sizeof (struct mo_file_header))
00305     {
00306       /* Something went wrong.  */
00307       close (fd);
00308       return;
00309     }
00310 
00311 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00312   /* Now we are ready to load the file.  If mmap() is available we try
00313      this first.  If not available or it failed we try to load it.  */
00314   data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ,
00315                      MAP_PRIVATE, fd, 0);
00316 
00317   if (data != (struct mo_file_header *) -1)
00318     {
00319       /* mmap() call was successful.  */
00320       close (fd);
00321       use_mmap = 1;
00322     }
00323 #endif
00324 
00325   /* If the data is not yet available (i.e. mmap'ed) we try to load
00326      it manually.  */
00327   if (data == (struct mo_file_header *) -1)
00328     {
00329       off_t to_read;
00330       char *read_ptr;
00331 
00332       data = (struct mo_file_header *) malloc (st.st_size);
00333       if (data == NULL)
00334     return;
00335 
00336       to_read = st.st_size;
00337       read_ptr = (char *) data;
00338       do
00339     {
00340       long int nb = (long int) read (fd, read_ptr, to_read);
00341       if (nb == -1)
00342         {
00343           close (fd);
00344           return;
00345         }
00346 
00347       read_ptr += nb;
00348       to_read -= nb;
00349     }
00350       while (to_read > 0);
00351 
00352       close (fd);
00353     }
00354 
00355   /* Using the magic number we can test whether it really is a message
00356      catalog file.  */
00357   if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
00358     {
00359       /* The magic number is wrong: not a message catalog file.  */
00360 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00361       if (use_mmap)
00362     munmap ((char *) data, st.st_size);
00363       else
00364 #endif
00365     free (data);
00366       return;
00367     }
00368 
00369   domain_file->data
00370     = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
00371   if (domain_file->data == NULL)
00372     return;
00373 
00374   domain = (struct loaded_domain *) domain_file->data;
00375   domain->data = (char *) data;
00376 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00377   domain->use_mmap = use_mmap;
00378   domain->mmap_size = st.st_size;
00379 #endif
00380   domain->must_swap = data->magic != _MAGIC;
00381 
00382   /* Fill in the information about the available tables.  */
00383   switch (W (domain->must_swap, data->revision))
00384     {
00385     case 0:
00386       domain->nstrings = W (domain->must_swap, data->nstrings);
00387       domain->orig_tab = (struct string_desc *)
00388     ((char *) data + W (domain->must_swap, data->orig_tab_offset));
00389       domain->trans_tab = (struct string_desc *)
00390     ((char *) data + W (domain->must_swap, data->trans_tab_offset));
00391       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
00392       domain->hash_tab = (nls_uint32 *)
00393     ((char *) data + W (domain->must_swap, data->hash_tab_offset));
00394       break;
00395     default:
00396       /* This is an illegal revision.  */
00397 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00398       if (use_mmap)
00399     munmap ((char *) data, st.st_size);
00400       else
00401 #endif
00402     free (data);
00403       free (domain);
00404       domain_file->data = NULL;
00405       return;
00406     }
00407 }
00408 
00409 void
00410 k_nl_unload_domain (struct loaded_domain *domain)
00411 {
00412 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP)
00413   if (domain->use_mmap)
00414     munmap ((caddr_t) domain->data, domain->mmap_size);
00415   else
00416 # endif
00417     free ((void *) domain->data);
00418 
00419   free (domain);
00420 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal