"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/intl/loadmsgcat.c" (23 Aug 2021, 15020 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Load needed message catalogs.
    2    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
    3 
    4    This program is free software; you can redistribute it and/or modify it
    5    under the terms of the GNU Library General Public License as published
    6    by the Free Software Foundation; either version 2, or (at your option)
    7    any later version.
    8 
    9    This program is distributed in the hope that it will be useful,
   10    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12    Library General Public License for more details.
   13 
   14    You should have received a copy of the GNU Library General Public
   15    License along with this program; if not, write to the Free Software
   16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   17    USA.  */
   18 
   19 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
   20    This must come before <autoconf.h> because <autoconf.h> may include
   21    <features.h>, and once <features.h> has been included, it's too late.  */
   22 #ifndef _GNU_SOURCE
   23 # define _GNU_SOURCE    1
   24 #endif
   25 
   26 #ifdef HAVE_CONFIG_H
   27 # include <autoconf.h>
   28 #endif
   29 
   30 #undef freea
   31 
   32 /* see AC_FUNC_ALLOCA macro */
   33 #ifdef __GNUC__
   34 # define alloca __builtin_alloca
   35 #else
   36 # ifdef _MSC_VER
   37 #  include <malloc.h>
   38 #  define alloca _alloca
   39 # else
   40 #  if HAVE_ALLOCA_H
   41 #   include <alloca.h>
   42 #  else
   43 #   ifdef _AIX
   44  #pragma alloca
   45 #   else
   46 #    ifndef alloca /* predefined by HP cc +Olibcalls */
   47 char *alloca ();
   48 #    else
   49 #     define freea(n) free(n)
   50 #    endif
   51 #   endif
   52 #  endif
   53 # endif
   54 #endif
   55 
   56 #ifndef freea
   57 #define freea(n) /* nothing */
   58 #endif
   59 
   60 #include <ctype.h>
   61 #include <errno.h>
   62 #include <fcntl.h>
   63 #include <sys/types.h>
   64 #include <sys/stat.h>
   65 
   66 #include <stdlib.h>
   67 #include <string.h>
   68 
   69 #if defined HAVE_UNISTD_H || defined _LIBC
   70 # include <unistd.h>
   71 #endif
   72 
   73 #ifdef _LIBC
   74 # include <langinfo.h>
   75 # include <locale.h>
   76 #endif
   77 
   78 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
   79     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
   80 # include <sys/mman.h>
   81 # undef HAVE_MMAP
   82 # define HAVE_MMAP  1
   83 #else
   84 # undef HAVE_MMAP
   85 #endif
   86 
   87 #include "gettext.h"
   88 #include "gettextP.h"
   89 
   90 #ifdef _LIBC
   91 # include "../locale/localeinfo.h"
   92 #endif
   93 
   94 /* @@ end of prolog @@ */
   95 
   96 #ifdef _LIBC
   97 /* Rename the non ISO C functions.  This is required by the standard
   98    because some ISO C functions will require linking with this object
   99    file and the name space must not be polluted.  */
  100 # define open   __open
  101 # define close  __close
  102 # define read   __read
  103 # define mmap   __mmap
  104 # define munmap __munmap
  105 #endif
  106 
  107 /* Names for the libintl functions are a problem.  They must not clash
  108    with existing names and they should follow ANSI C.  But this source
  109    code is also used in GNU C Library where the names have a __
  110    prefix.  So we have to make a difference here.  */
  111 #ifdef _LIBC
  112 # define PLURAL_PARSE __gettextparse
  113 #else
  114 # define PLURAL_PARSE gettextparse__
  115 #endif
  116 
  117 /* For systems that distinguish between text and binary I/O.
  118    O_BINARY is usually declared in <fcntl.h>. */
  119 #if !defined O_BINARY && defined _O_BINARY
  120   /* For MSC-compatible compilers.  */
  121 # define O_BINARY _O_BINARY
  122 # define O_TEXT _O_TEXT
  123 #endif
  124 #ifdef __BEOS__
  125   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
  126 # undef O_BINARY
  127 # undef O_TEXT
  128 #endif
  129 /* On reasonable systems, binary I/O is the default.  */
  130 #ifndef O_BINARY
  131 # define O_BINARY 0
  132 #endif
  133 
  134 /* We need a sign, whether a new catalog was loaded, which can be associated
  135    with all translations.  This is important if the translations are
  136    cached by one of GCC's features.  */
  137 int _nl_msg_cat_cntr;
  138 
  139 #if (defined __GNUC__ && !defined __APPLE_CC__) \
  140     || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
  141 
  142 /* These structs are the constant expression for the germanic plural
  143    form determination.  It represents the expression  "n != 1".  */
  144 static const struct expression plvar =
  145 {
  146   .nargs = 0,
  147   .operation = var,
  148 };
  149 static const struct expression plone =
  150 {
  151   .nargs = 0,
  152   .operation = num,
  153   .val =
  154   {
  155     .num = 1
  156   }
  157 };
  158 static struct expression germanic_plural =
  159 {
  160   .nargs = 2,
  161   .operation = not_equal,
  162   .val =
  163   {
  164     .args =
  165     {
  166       [0] = (struct expression *) &plvar,
  167       [1] = (struct expression *) &plone
  168     }
  169   }
  170 };
  171 
  172 # define INIT_GERMANIC_PLURAL()
  173 
  174 #else
  175 
  176 /* For compilers without support for ISO C 99 struct/union initializers:
  177    Initialization at run-time.  */
  178 
  179 static struct expression plvar;
  180 static struct expression plone;
  181 static struct expression germanic_plural;
  182 
  183 static void
  184 init_germanic_plural ()
  185 {
  186   if (plone.val.num == 0)
  187     {
  188       plvar.nargs = 0;
  189       plvar.operation = var;
  190 
  191       plone.nargs = 0;
  192       plone.operation = num;
  193       plone.val.num = 1;
  194 
  195       germanic_plural.nargs = 2;
  196       germanic_plural.operation = not_equal;
  197       germanic_plural.val.args[0] = &plvar;
  198       germanic_plural.val.args[1] = &plone;
  199     }
  200 }
  201 
  202 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
  203 
  204 #endif
  205 
  206 
  207 /* Initialize the codeset dependent parts of an opened message catalog.
  208    Return the header entry.  */
  209 const char *
  210 internal_function
  211 _nl_init_domain_conv (domain_file, domain, domainbinding)
  212      struct loaded_l10nfile *domain_file;
  213      struct loaded_domain *domain;
  214      struct binding *domainbinding;
  215 {
  216   /* Find out about the character set the file is encoded with.
  217      This can be found (in textual form) in the entry "".  If this
  218      entry does not exist or if this does not contain the `charset='
  219      information, we will assume the charset matches the one the
  220      current locale and we don't have to perform any conversion.  */
  221   char *nullentry;
  222   size_t nullentrylen;
  223 
  224   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
  225   domain->codeset_cntr =
  226     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
  227 #ifdef _LIBC
  228   domain->conv = (__gconv_t) -1;
  229 #else
  230 # ifdef HAVE_ICONV
  231   domain->conv = (iconv_t) -1;
  232 # endif
  233 #endif
  234   domain->conv_tab = NULL;
  235 
  236   /* Get the header entry.  */
  237   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
  238 
  239   if (nullentry != NULL)
  240     {
  241 #if defined _LIBC || defined HAVE_ICONV
  242       const char *charsetstr;
  243 
  244       charsetstr = strstr (nullentry, "charset=");
  245       if (charsetstr != NULL)
  246     {
  247       size_t len;
  248       char *charset;
  249       const char *outcharset;
  250 
  251       charsetstr += strlen ("charset=");
  252       len = strcspn (charsetstr, " \t\n");
  253 
  254       charset = (char *) alloca (len + 1);
  255 # if defined _LIBC || HAVE_MEMPCPY
  256       *((char *) mempcpy (charset, charsetstr, len)) = '\0';
  257 # else
  258       memcpy (charset, charsetstr, len);
  259       charset[len] = '\0';
  260 # endif
  261 
  262       /* The output charset should normally be determined by the
  263          locale.  But sometimes the locale is not used or not correctly
  264          set up, so we provide a possibility for the user to override
  265          this.  Moreover, the value specified through
  266          bind_textdomain_codeset overrides both.  */
  267       if (domainbinding != NULL && domainbinding->codeset != NULL)
  268         outcharset = domainbinding->codeset;
  269       else
  270         {
  271           outcharset = getenv ("OUTPUT_CHARSET");
  272           if (outcharset == NULL || outcharset[0] == '\0')
  273         {
  274 # ifdef _LIBC
  275           outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
  276 # else
  277 #  if HAVE_ICONV
  278           extern const char *locale_charset (void);
  279           outcharset = locale_charset ();
  280 #  endif
  281 # endif
  282         }
  283         }
  284 
  285 # ifdef _LIBC
  286       /* We always want to use transliteration.  */
  287       outcharset = norm_add_slashes (outcharset, "TRANSLIT");
  288       charset = norm_add_slashes (charset, NULL);
  289       if (__gconv_open (outcharset, charset, &domain->conv,
  290                 GCONV_AVOID_NOCONV)
  291           != __GCONV_OK)
  292         domain->conv = (__gconv_t) -1;
  293 # else
  294 #  if HAVE_ICONV
  295       /* When using GNU libiconv, we want to use transliteration.  */
  296 #   if _LIBICONV_VERSION >= 0x0105
  297       len = strlen (outcharset);
  298       {
  299         char *tmp = (char *) alloca (len + 10 + 1);
  300         memcpy (tmp, outcharset, len);
  301         memcpy (tmp + len, "//TRANSLIT", 10 + 1);
  302         outcharset = tmp;
  303       }
  304 #   endif
  305       domain->conv = iconv_open (outcharset, charset);
  306 #   if _LIBICONV_VERSION >= 0x0105
  307       freea (outcharset);
  308 #   endif
  309 #  endif
  310 # endif
  311 
  312       freea (charset);
  313     }
  314 #endif /* _LIBC || HAVE_ICONV */
  315     }
  316 
  317   return nullentry;
  318 }
  319 
  320 /* Frees the codeset dependent parts of an opened message catalog.  */
  321 void
  322 internal_function
  323 _nl_free_domain_conv (domain)
  324      struct loaded_domain *domain;
  325 {
  326   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
  327     free (domain->conv_tab);
  328 
  329 #ifdef _LIBC
  330   if (domain->conv != (__gconv_t) -1)
  331     __gconv_close (domain->conv);
  332 #else
  333 # ifdef HAVE_ICONV
  334   if (domain->conv != (iconv_t) -1)
  335     iconv_close (domain->conv);
  336 # endif
  337 #endif
  338 }
  339 
  340 /* Load the message catalogs specified by FILENAME.  If it is no valid
  341    message catalog do nothing.  */
  342 void
  343 internal_function
  344 _nl_load_domain (domain_file, domainbinding)
  345      struct loaded_l10nfile *domain_file;
  346      struct binding *domainbinding;
  347 {
  348   int fd;
  349   size_t size;
  350 #ifdef _LIBC
  351   struct stat64 st;
  352 #else
  353   struct stat st;
  354 #endif
  355   struct mo_file_header *data = (struct mo_file_header *) -1;
  356   int use_mmap = 0;
  357   struct loaded_domain *domain;
  358   const char *nullentry;
  359 
  360   domain_file->decided = 1;
  361   domain_file->data = NULL;
  362 
  363   /* Note that it would be useless to store domainbinding in domain_file
  364      because domainbinding might be == NULL now but != NULL later (after
  365      a call to bind_textdomain_codeset).  */
  366 
  367   /* If the record does not represent a valid locale the FILENAME
  368      might be NULL.  This can happen when according to the given
  369      specification the locale file name is different for XPG and CEN
  370      syntax.  */
  371   if (domain_file->filename == NULL)
  372     return;
  373 
  374   /* Try to open the addressed file.  */
  375   fd = open (domain_file->filename, O_RDONLY | O_BINARY);
  376   if (fd == -1)
  377     return;
  378 
  379   /* We must know about the size of the file.  */
  380   if (
  381 #ifdef _LIBC
  382       __builtin_expect (fstat64 (fd, &st) != 0, 0)
  383 #else
  384       __builtin_expect (fstat (fd, &st) != 0, 0)
  385 #endif
  386       || __builtin_expect ((size = (size_t) st.st_size) != (size_t) st.st_size, 0)
  387       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
  388     {
  389       /* Something went wrong.  */
  390       close (fd);
  391       return;
  392     }
  393 
  394 #ifdef HAVE_MMAP
  395   /* Now we are ready to load the file.  If mmap() is available we try
  396      this first.  If not available or it failed we try to load it.  */
  397   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
  398                      MAP_PRIVATE, fd, 0);
  399 
  400   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
  401     {
  402       /* mmap() call was successful.  */
  403       close (fd);
  404       use_mmap = 1;
  405     }
  406 #endif
  407 
  408   /* If the data is not yet available (i.e. mmap'ed) we try to load
  409      it manually.  */
  410   if (data == (struct mo_file_header *) -1)
  411     {
  412       size_t to_read;
  413       char *read_ptr;
  414 
  415       data = (struct mo_file_header *) malloc (size);
  416       if (data == NULL) {
  417           if (!use_mmap)
  418             close (fd);
  419         return;
  420     }
  421 
  422       to_read = size;
  423       read_ptr = (char *) data;
  424       do
  425     {
  426       long int nb = (long int) read (fd, read_ptr, to_read);
  427       if (nb <= 0)
  428         {
  429 #ifdef EINTR
  430           if (nb == -1 && errno == EINTR)
  431         continue;
  432 #endif
  433           close (fd);
  434           return;
  435         }
  436       read_ptr += nb;
  437       to_read -= nb;
  438     }
  439       while (to_read > 0);
  440 
  441       close (fd);
  442     }
  443 
  444   /* Using the magic number we can test whether it really is a message
  445      catalog file.  */
  446   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
  447             0))
  448     {
  449       /* The magic number is wrong: not a message catalog file.  */
  450 #ifdef HAVE_MMAP
  451       if (use_mmap)
  452     munmap ((caddr_t) data, size);
  453       else
  454 #endif
  455     free (data);
  456       return;
  457     }
  458 
  459   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
  460   if (domain == NULL)
  461     return;
  462   domain_file->data = domain;
  463 
  464   domain->data = (char *) data;
  465   domain->use_mmap = use_mmap;
  466   domain->mmap_size = size;
  467   domain->must_swap = data->magic != _MAGIC;
  468 
  469   /* Fill in the information about the available tables.  */
  470   switch (W (domain->must_swap, data->revision))
  471     {
  472     case 0:
  473       domain->nstrings = W (domain->must_swap, data->nstrings);
  474       domain->orig_tab = (struct string_desc *)
  475     ((char *) data + W (domain->must_swap, data->orig_tab_offset));
  476       domain->trans_tab = (struct string_desc *)
  477     ((char *) data + W (domain->must_swap, data->trans_tab_offset));
  478       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
  479       domain->hash_tab = (nls_uint32 *)
  480     ((char *) data + W (domain->must_swap, data->hash_tab_offset));
  481       break;
  482     default:
  483       /* This is an invalid revision.  */
  484 #ifdef HAVE_MMAP
  485       if (use_mmap)
  486     munmap ((caddr_t) data, size);
  487       else
  488 #endif
  489     free (data);
  490       free (domain);
  491       domain_file->data = NULL;
  492       return;
  493     }
  494 
  495   /* Now initialize the character set converter from the character set
  496      the file is encoded with (found in the header entry) to the domain's
  497      specified character set or the locale's character set.  */
  498   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
  499 
  500   /* Also look for a plural specification.  */
  501   if (nullentry != NULL)
  502     {
  503       const char *plural;
  504       const char *nplurals;
  505 
  506       plural = strstr (nullentry, "plural=");
  507       nplurals = strstr (nullentry, "nplurals=");
  508       if (plural == NULL || nplurals == NULL)
  509     goto no_plural;
  510       else
  511     {
  512       /* First get the number.  */
  513       char *endp;
  514       unsigned long int n;
  515       struct parse_args args;
  516 
  517       nplurals += 9;
  518       while (*nplurals != '\0' && isspace (*nplurals))
  519         ++nplurals;
  520 #if defined HAVE_STRTOUL || defined _LIBC
  521       n = strtoul (nplurals, &endp, 10);
  522 #else
  523       for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
  524         n = n * 10 + (*endp - '0');
  525 #endif
  526       domain->nplurals = n;
  527       if (nplurals == endp)
  528         goto no_plural;
  529 
  530       /* Due to the restrictions bison imposes onto the interface of the
  531          scanner function we have to put the input string and the result
  532          passed up from the parser into the same structure which address
  533          is passed down to the parser.  */
  534       plural += 7;
  535       args.cp = plural;
  536       if (PLURAL_PARSE (&args) != 0)
  537         goto no_plural;
  538       domain->plural = args.res;
  539     }
  540     }
  541   else
  542     {
  543       /* By default we are using the Germanic form: singular form only
  544          for `one', the plural form otherwise.  Yes, this is also what
  545          English is using since English is a Germanic language.  */
  546     no_plural:
  547       INIT_GERMANIC_PLURAL ();
  548       domain->plural = &germanic_plural;
  549       domain->nplurals = 2;
  550     }
  551 }
  552 
  553 
  554 #ifdef _LIBC
  555 void
  556 internal_function
  557 _nl_unload_domain (domain)
  558      struct loaded_domain *domain;
  559 {
  560   if (domain->plural != &germanic_plural)
  561     __gettext_free_exp (domain->plural);
  562 
  563   _nl_free_domain_conv (domain);
  564 
  565 # ifdef _POSIX_MAPPED_FILES
  566   if (domain->use_mmap)
  567     munmap ((caddr_t) domain->data, domain->mmap_size);
  568   else
  569 # endif /* _POSIX_MAPPED_FILES */
  570     free ((void *) domain->data);
  571 
  572   free (domain);
  573 }
  574 #endif