kdecore Library: libintl.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 "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 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:12 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003