Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

loadmsgcat.c

00001 /* Load needed message catalogs.
00002    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify it
00005    under the terms of the GNU Library General Public License as published
00006    by the Free Software Foundation; either version 2, or (at your option)
00007    any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public
00015    License along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00017    USA.  */
00018 
00019 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
00020    This must come before <config.h> because <config.h> may include
00021    <features.h>, and once <features.h> has been included, it's too late.  */
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE    1
00024 #endif
00025 
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <fcntl.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 
00036 #ifdef __GNUC__
00037 # define alloca __builtin_alloca
00038 # define HAVE_ALLOCA 1
00039 #else
00040 # if defined HAVE_ALLOCA_H || defined _LIBC
00041 #  include <alloca.h>
00042 # else
00043 #  ifdef _AIX
00044  #pragma alloca
00045 #  else
00046 #   ifndef alloca
00047 char *alloca ();
00048 #   endif
00049 #  endif
00050 # endif
00051 #endif
00052 
00053 #include <stdlib.h>
00054 #include <string.h>
00055 
00056 #if defined HAVE_UNISTD_H || defined _LIBC
00057 # include <unistd.h>
00058 #endif
00059 
00060 #ifdef _LIBC
00061 # include <langinfo.h>
00062 # include <locale.h>
00063 #endif
00064 
00065 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
00066     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
00067 # include <sys/mman.h>
00068 # undef HAVE_MMAP
00069 # define HAVE_MMAP      1
00070 #else
00071 # undef HAVE_MMAP
00072 #endif
00073 
00074 #include "gmo.h"
00075 #include "gettextP.h"
00076 #include "plural-exp.h"
00077 
00078 #ifdef _LIBC
00079 # include "../locale/localeinfo.h"
00080 #endif
00081 
00082 /* @@ end of prolog @@ */
00083 
00084 #ifdef _LIBC
00085 /* Rename the non ISO C functions.  This is required by the standard
00086    because some ISO C functions will require linking with this object
00087    file and the name space must not be polluted.  */
00088 # define open   __open
00089 # define close  __close
00090 # define read   __read
00091 # define mmap   __mmap
00092 # define munmap __munmap
00093 #endif
00094 
00095 /* For those losing systems which don't have `alloca' we have to add
00096    some additional code emulating it.  */
00097 #ifdef HAVE_ALLOCA
00098 # define freea(p) /* nothing */
00099 #else
00100 # define alloca(n) malloc (n)
00101 # define freea(p) free (p)
00102 #endif
00103 
00104 /* For systems that distinguish between text and binary I/O.
00105    O_BINARY is usually declared in <fcntl.h>. */
00106 #if !defined O_BINARY && defined _O_BINARY
00107   /* For MSC-compatible compilers.  */
00108 # define O_BINARY _O_BINARY
00109 # define O_TEXT _O_TEXT
00110 #endif
00111 #ifdef __BEOS__
00112   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
00113 # undef O_BINARY
00114 # undef O_TEXT
00115 #endif
00116 /* On reasonable systems, binary I/O is the default.  */
00117 #ifndef O_BINARY
00118 # define O_BINARY 0
00119 #endif
00120 
00121 /* We need a sign, whether a new catalog was loaded, which can be associated
00122    with all translations.  This is important if the translations are
00123    cached by one of GCC's features.  */
00124 int _nl_msg_cat_cntr;
00125 
00126 
00127 /* Initialize the codeset dependent parts of an opened message catalog.
00128    Return the header entry.  */
00129 const char *
00130 internal_function
00131 _nl_init_domain_conv (domain_file, domain, domainbinding)
00132      struct loaded_l10nfile *domain_file;
00133      struct loaded_domain *domain;
00134      struct binding *domainbinding;
00135 {
00136   /* Find out about the character set the file is encoded with.
00137      This can be found (in textual form) in the entry "".  If this
00138      entry does not exist or if this does not contain the `charset='
00139      information, we will assume the charset matches the one the
00140      current locale and we don't have to perform any conversion.  */
00141   char *nullentry;
00142   size_t nullentrylen;
00143 
00144   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
00145   domain->codeset_cntr =
00146     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
00147 #ifdef _LIBC
00148   domain->conv = (__gconv_t) -1;
00149 #else
00150 # if HAVE_ICONV
00151   domain->conv = (iconv_t) -1;
00152 # endif
00153 #endif
00154   domain->conv_tab = NULL;
00155 
00156   /* Get the header entry.  */
00157   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
00158 
00159   if (nullentry != NULL)
00160     {
00161 #if defined _LIBC || HAVE_ICONV
00162       const char *charsetstr;
00163 
00164       charsetstr = strstr (nullentry, "charset=");
00165       if (charsetstr != NULL)
00166         {
00167           size_t len;
00168           char *charset;
00169           const char *outcharset;
00170 
00171           charsetstr += strlen ("charset=");
00172           len = strcspn (charsetstr, " \t\n");
00173 
00174           charset = (char *) alloca (len + 1);
00175 # if defined _LIBC || HAVE_MEMPCPY
00176           *((char *) mempcpy (charset, charsetstr, len)) = '\0';
00177 # else
00178           memcpy (charset, charsetstr, len);
00179           charset[len] = '\0';
00180 # endif
00181 
00182           /* The output charset should normally be determined by the
00183              locale.  But sometimes the locale is not used or not correctly
00184              set up, so we provide a possibility for the user to override
00185              this.  Moreover, the value specified through
00186              bind_textdomain_codeset overrides both.  */
00187           if (domainbinding != NULL && domainbinding->codeset != NULL)
00188             outcharset = domainbinding->codeset;
00189           else
00190             {
00191               outcharset = getenv ("OUTPUT_CHARSET");
00192               if (outcharset == NULL || outcharset[0] == '\0')
00193                 {
00194 # ifdef _LIBC
00195                   outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
00196 # else
00197 #  if HAVE_ICONV
00198                   extern const char *locale_charset PARAMS ((void));
00199                   outcharset = locale_charset ();
00200 #  endif
00201 # endif
00202                 }
00203             }
00204 
00205 # ifdef _LIBC
00206           /* We always want to use transliteration.  */
00207           outcharset = norm_add_slashes (outcharset, "TRANSLIT");
00208           charset = norm_add_slashes (charset, NULL);
00209           if (__gconv_open (outcharset, charset, &domain->conv,
00210                             GCONV_AVOID_NOCONV)
00211               != __GCONV_OK)
00212             domain->conv = (__gconv_t) -1;
00213 # else
00214 #  if HAVE_ICONV
00215           /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
00216              we want to use transliteration.  */
00217 #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
00218        || _LIBICONV_VERSION >= 0x0105
00219           len = strlen (outcharset);
00220           {
00221             char *tmp = (char *) alloca (len + 10 + 1);
00222             memcpy (tmp, outcharset, len);
00223             memcpy (tmp + len, "//TRANSLIT", 10 + 1);
00224             outcharset = tmp;
00225           }
00226 #   endif
00227           domain->conv = iconv_open (outcharset, charset);
00228 #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
00229        || _LIBICONV_VERSION >= 0x0105
00230           freea (outcharset);
00231 #   endif
00232 #  endif
00233 # endif
00234 
00235           freea (charset);
00236         }
00237 #endif /* _LIBC || HAVE_ICONV */
00238     }
00239 
00240   return nullentry;
00241 }
00242 
00243 /* Frees the codeset dependent parts of an opened message catalog.  */
00244 void
00245 internal_function
00246 _nl_free_domain_conv (domain)
00247      struct loaded_domain *domain;
00248 {
00249   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
00250     free (domain->conv_tab);
00251 
00252 #ifdef _LIBC
00253   if (domain->conv != (__gconv_t) -1)
00254     __gconv_close (domain->conv);
00255 #else
00256 # if HAVE_ICONV
00257   if (domain->conv != (iconv_t) -1)
00258     iconv_close (domain->conv);
00259 # endif
00260 #endif
00261 }
00262 
00263 /* Load the message catalogs specified by FILENAME.  If it is no valid
00264    message catalog do nothing.  */
00265 void
00266 internal_function
00267 _nl_load_domain (domain_file, domainbinding)
00268      struct loaded_l10nfile *domain_file;
00269      struct binding *domainbinding;
00270 {
00271   int fd;
00272   size_t size;
00273 #ifdef _LIBC
00274   struct stat64 st;
00275 #else
00276   struct stat st;
00277 #endif
00278   struct mo_file_header *data = (struct mo_file_header *) -1;
00279   int use_mmap = 0;
00280   struct loaded_domain *domain;
00281   const char *nullentry;
00282 
00283   domain_file->decided = 1;
00284   domain_file->data = NULL;
00285 
00286   /* Note that it would be useless to store domainbinding in domain_file
00287      because domainbinding might be == NULL now but != NULL later (after
00288      a call to bind_textdomain_codeset).  */
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 = open (domain_file->filename, O_RDONLY | O_BINARY);
00299   if (fd == -1)
00300     return;
00301 
00302   /* We must know about the size of the file.  */
00303   if (
00304 #ifdef _LIBC
00305       __builtin_expect (fstat64 (fd, &st) != 0, 0)
00306 #else
00307       __builtin_expect (fstat (fd, &st) != 0, 0)
00308 #endif
00309       || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
00310       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
00311     {
00312       /* Something went wrong.  */
00313       close (fd);
00314       return;
00315     }
00316 
00317 #ifdef HAVE_MMAP
00318   /* Now we are ready to load the file.  If mmap() is available we try
00319      this first.  If not available or it failed we try to load it.  */
00320   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
00321                                          MAP_PRIVATE, fd, 0);
00322 
00323   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
00324     {
00325       /* mmap() call was successful.  */
00326       close (fd);
00327       use_mmap = 1;
00328     }
00329 #endif
00330 
00331   /* If the data is not yet available (i.e. mmap'ed) we try to load
00332      it manually.  */
00333   if (data == (struct mo_file_header *) -1)
00334     {
00335       size_t to_read;
00336       char *read_ptr;
00337 
00338       data = (struct mo_file_header *) malloc (size);
00339       if (data == NULL)
00340         return;
00341 
00342       to_read = size;
00343       read_ptr = (char *) data;
00344       do
00345         {
00346           long int nb = (long int) read (fd, read_ptr, to_read);
00347           if (nb <= 0)
00348             {
00349 #ifdef EINTR
00350               if (nb == -1 && errno == EINTR)
00351                 continue;
00352 #endif
00353               close (fd);
00354               return;
00355             }
00356           read_ptr += nb;
00357           to_read -= nb;
00358         }
00359       while (to_read > 0);
00360 
00361       close (fd);
00362     }
00363 
00364   /* Using the magic number we can test whether it really is a message
00365      catalog file.  */
00366   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
00367                         0))
00368     {
00369       /* The magic number is wrong: not a message catalog file.  */
00370 #ifdef HAVE_MMAP
00371       if (use_mmap)
00372         munmap ((caddr_t) data, size);
00373       else
00374 #endif
00375         free (data);
00376       return;
00377     }
00378 
00379   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
00380   if (domain == NULL)
00381     return;
00382   domain_file->data = domain;
00383 
00384   domain->data = (char *) data;
00385   domain->use_mmap = use_mmap;
00386   domain->mmap_size = size;
00387   domain->must_swap = data->magic != _MAGIC;
00388 
00389   /* Fill in the information about the available tables.  */
00390   switch (W (domain->must_swap, data->revision))
00391     {
00392     case 0:
00393       domain->nstrings = W (domain->must_swap, data->nstrings);
00394       domain->orig_tab = (struct string_desc *)
00395         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
00396       domain->trans_tab = (struct string_desc *)
00397         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
00398       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
00399       domain->hash_tab = (nls_uint32 *)
00400         ((char *) data + W (domain->must_swap, data->hash_tab_offset));
00401       break;
00402     default:
00403       /* This is an invalid revision.  */
00404 #ifdef HAVE_MMAP
00405       if (use_mmap)
00406         munmap ((caddr_t) data, size);
00407       else
00408 #endif
00409         free (data);
00410       free (domain);
00411       domain_file->data = NULL;
00412       return;
00413     }
00414 
00415   /* Now initialize the character set converter from the character set
00416      the file is encoded with (found in the header entry) to the domain's
00417      specified character set or the locale's character set.  */
00418   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
00419 
00420   /* Also look for a plural specification.  */
00421   EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
00422 }
00423 
00424 
00425 #ifdef _LIBC
00426 void
00427 internal_function
00428 _nl_unload_domain (domain)
00429      struct loaded_domain *domain;
00430 {
00431   if (domain->plural != &__gettext_germanic_plural)
00432     __gettext_free_exp (domain->plural);
00433 
00434   _nl_free_domain_conv (domain);
00435 
00436 # ifdef _POSIX_MAPPED_FILES
00437   if (domain->use_mmap)
00438     munmap ((caddr_t) domain->data, domain->mmap_size);
00439   else
00440 # endif /* _POSIX_MAPPED_FILES */
00441     free ((void *) domain->data);
00442 
00443   free (domain);
00444 }
00445 #endif

Generated on Sun Feb 16 23:39:49 2003 for FreeLCD by doxygen1.2.18