libintl.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | 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 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 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:59 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001