"Fossies" - the Fresh Open Source Software Archive

Member "plptools-1.0.15/intl/localealias.c" (31 Oct 2019, 10639 Bytes) of package /linux/privat/plptools-1.0.15.tar.gz:


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. See also the last Fossies "Diffs" side-by-side code changes report for "localealias.c": 1.0.13_vs_1.0.14-Source.

    1 /* Handle aliases for locale names.
    2    Copyright (C) 1995-2015 Free Software Foundation, Inc.
    3 
    4    This program is free software: you can redistribute it and/or modify
    5    it under the terms of the GNU Lesser General Public License as published by
    6    the Free Software Foundation; either version 2.1 of the License, or
    7    (at your option) 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
   12    GNU Lesser General Public License for more details.
   13 
   14    You should have received a copy of the GNU Lesser General Public License
   15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   16 
   17 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
   18    This must come before <config.h> because <config.h> may include
   19    <features.h>, and once <features.h> has been included, it's too late.  */
   20 #ifndef _GNU_SOURCE
   21 # define _GNU_SOURCE    1
   22 #endif
   23 
   24 #ifdef HAVE_CONFIG_H
   25 # include <config.h>
   26 #endif
   27 
   28 #include <ctype.h>
   29 #include <stdio.h>
   30 #if defined _LIBC || defined HAVE___FSETLOCKING
   31 # include <stdio_ext.h>
   32 #endif
   33 #include <sys/types.h>
   34 
   35 #ifdef __GNUC__
   36 # undef alloca
   37 # define alloca __builtin_alloca
   38 # define HAVE_ALLOCA 1
   39 #else
   40 # ifdef _MSC_VER
   41 #  include <malloc.h>
   42 #  define alloca _alloca
   43 # else
   44 #  if defined HAVE_ALLOCA_H || defined _LIBC
   45 #   include <alloca.h>
   46 #  else
   47 #   ifdef _AIX
   48  #pragma alloca
   49 #   else
   50 #    ifndef alloca
   51 char *alloca ();
   52 #    endif
   53 #   endif
   54 #  endif
   55 # endif
   56 #endif
   57 
   58 #include <stdlib.h>
   59 #include <string.h>
   60 
   61 #include "gettextP.h"
   62 
   63 #ifdef ENABLE_RELOCATABLE
   64 # include "relocatable.h"
   65 #else
   66 # define relocate(pathname) (pathname)
   67 #endif
   68 
   69 /* @@ end of prolog @@ */
   70 
   71 #ifdef _LIBC
   72 /* Rename the non ANSI C functions.  This is required by the standard
   73    because some ANSI C functions will require linking with this object
   74    file and the name space must not be polluted.  */
   75 # define strcasecmp(s1, s2) __strcasecmp_l (s1, s2, _nl_C_locobj_ptr)
   76 
   77 # ifndef mempcpy
   78 #  define mempcpy __mempcpy
   79 # endif
   80 # define HAVE_MEMPCPY   1
   81 # define HAVE___FSETLOCKING 1
   82 #endif
   83 
   84 /* Handle multi-threaded applications.  */
   85 #ifdef _LIBC
   86 # include <bits/libc-lock.h>
   87 #else
   88 # include "lock.h"
   89 #endif
   90 
   91 #ifndef internal_function
   92 # define internal_function
   93 #endif
   94 
   95 /* Some optimizations for glibc.  */
   96 #ifdef _LIBC
   97 # define FEOF(fp)       feof_unlocked (fp)
   98 # define FGETS(buf, n, fp)  __fgets_unlocked (buf, n, fp)
   99 #else
  100 # define FEOF(fp)       feof (fp)
  101 # define FGETS(buf, n, fp)  fgets (buf, n, fp)
  102 #endif
  103 
  104 /* For those losing systems which don't have `alloca' we have to add
  105    some additional code emulating it.  */
  106 #ifdef HAVE_ALLOCA
  107 # define freea(p) /* nothing */
  108 #else
  109 # define alloca(n) malloc (n)
  110 # define freea(p) free (p)
  111 #endif
  112 
  113 #if defined _LIBC_REENTRANT \
  114   || (defined HAVE_DECL_FGETS_UNLOCKED && HAVE_DECL_FGETS_UNLOCKED)
  115 # undef fgets
  116 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
  117 #endif
  118 #if defined _LIBC_REENTRANT \
  119   || (defined HAVE_DECL_FEOF_UNLOCKED && HAVE_DECL_FEOF_UNLOCKED)
  120 # undef feof
  121 # define feof(s) feof_unlocked (s)
  122 #endif
  123 
  124 
  125 __libc_lock_define_initialized (static, lock)
  126 
  127 
  128 struct alias_map
  129 {
  130   const char *alias;
  131   const char *value;
  132 };
  133 
  134 
  135 #ifndef _LIBC
  136 # define libc_freeres_ptr(decl) decl
  137 #endif
  138 
  139 libc_freeres_ptr (static char *string_space);
  140 static size_t string_space_act;
  141 static size_t string_space_max;
  142 libc_freeres_ptr (static struct alias_map *map);
  143 static size_t nmap;
  144 static size_t maxmap;
  145 
  146 
  147 /* Prototypes for local functions.  */
  148 static size_t read_alias_file (const char *fname, int fname_len)
  149      internal_function;
  150 static int extend_alias_table (void);
  151 static int alias_compare (const struct alias_map *map1,
  152               const struct alias_map *map2);
  153 
  154 
  155 const char *
  156 _nl_expand_alias (const char *name)
  157 {
  158   static const char *locale_alias_path;
  159   struct alias_map *retval;
  160   const char *result = NULL;
  161   size_t added;
  162 
  163   __libc_lock_lock (lock);
  164 
  165   if (locale_alias_path == NULL)
  166     locale_alias_path = LOCALE_ALIAS_PATH;
  167 
  168   do
  169     {
  170       struct alias_map item;
  171 
  172       item.alias = name;
  173 
  174       if (nmap > 0)
  175     retval = (struct alias_map *) bsearch (&item, map, nmap,
  176                            sizeof (struct alias_map),
  177                            (int (*) (const void *,
  178                              const void *)
  179                         ) alias_compare);
  180       else
  181     retval = NULL;
  182 
  183       /* We really found an alias.  Return the value.  */
  184       if (retval != NULL)
  185     {
  186       result = retval->value;
  187       break;
  188     }
  189 
  190       /* Perhaps we can find another alias file.  */
  191       added = 0;
  192       while (added == 0 && locale_alias_path[0] != '\0')
  193     {
  194       const char *start;
  195 
  196       while (locale_alias_path[0] == PATH_SEPARATOR)
  197         ++locale_alias_path;
  198       start = locale_alias_path;
  199 
  200       while (locale_alias_path[0] != '\0'
  201          && locale_alias_path[0] != PATH_SEPARATOR)
  202         ++locale_alias_path;
  203 
  204       if (start < locale_alias_path)
  205         added = read_alias_file (start, locale_alias_path - start);
  206     }
  207     }
  208   while (added != 0);
  209 
  210   __libc_lock_unlock (lock);
  211 
  212   return result;
  213 }
  214 
  215 
  216 static size_t
  217 internal_function
  218 read_alias_file (const char *fname, int fname_len)
  219 {
  220   FILE *fp;
  221   char *full_fname;
  222   size_t added;
  223   static const char aliasfile[] = "/locale.alias";
  224 
  225   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
  226 #ifdef HAVE_MEMPCPY
  227   mempcpy (mempcpy (full_fname, fname, fname_len),
  228        aliasfile, sizeof aliasfile);
  229 #else
  230   memcpy (full_fname, fname, fname_len);
  231   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
  232 #endif
  233 
  234 #ifdef _LIBC
  235   /* Note the file is opened with cancellation in the I/O functions
  236      disabled.  */
  237   fp = fopen (relocate (full_fname), "rce");
  238 #else
  239   fp = fopen (relocate (full_fname), "r");
  240 #endif
  241   freea (full_fname);
  242   if (fp == NULL)
  243     return 0;
  244 
  245 #ifdef HAVE___FSETLOCKING
  246   /* No threads present.  */
  247   __fsetlocking (fp, FSETLOCKING_BYCALLER);
  248 #endif
  249 
  250   added = 0;
  251   while (!FEOF (fp))
  252     {
  253       /* It is a reasonable approach to use a fix buffer here because
  254      a) we are only interested in the first two fields
  255      b) these fields must be usable as file names and so must not
  256         be that long
  257      We avoid a multi-kilobyte buffer here since this would use up
  258      stack space which we might not have if the program ran out of
  259      memory.  */
  260       char buf[400];
  261       char *alias;
  262       char *value;
  263       char *cp;
  264       int complete_line;
  265 
  266       if (FGETS (buf, sizeof buf, fp) == NULL)
  267     /* EOF reached.  */
  268     break;
  269 
  270       /* Determine whether the line is complete.  */
  271       complete_line = strchr (buf, '\n') != NULL;
  272 
  273       cp = buf;
  274       /* Ignore leading white space.  */
  275       while (isspace ((unsigned char) cp[0]))
  276     ++cp;
  277 
  278       /* A leading '#' signals a comment line.  */
  279       if (cp[0] != '\0' && cp[0] != '#')
  280     {
  281       alias = cp++;
  282       while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
  283         ++cp;
  284       /* Terminate alias name.  */
  285       if (cp[0] != '\0')
  286         *cp++ = '\0';
  287 
  288       /* Now look for the beginning of the value.  */
  289       while (isspace ((unsigned char) cp[0]))
  290         ++cp;
  291 
  292       if (cp[0] != '\0')
  293         {
  294           value = cp++;
  295           while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
  296         ++cp;
  297           /* Terminate value.  */
  298           if (cp[0] == '\n')
  299         {
  300           /* This has to be done to make the following test
  301              for the end of line possible.  We are looking for
  302              the terminating '\n' which do not overwrite here.  */
  303           *cp++ = '\0';
  304           *cp = '\n';
  305         }
  306           else if (cp[0] != '\0')
  307         *cp++ = '\0';
  308 
  309 #ifdef IN_LIBGLOCALE
  310           /* glibc's locale.alias contains entries for ja_JP and ko_KR
  311          that make it impossible to use a Japanese or Korean UTF-8
  312          locale under the name "ja_JP" or "ko_KR".  Ignore these
  313          entries.  */
  314           if (strchr (alias, '_') == NULL)
  315 #endif
  316         {
  317           size_t alias_len;
  318           size_t value_len;
  319 
  320           if (nmap >= maxmap)
  321             if (__builtin_expect (extend_alias_table (), 0))
  322               goto out;
  323 
  324           alias_len = strlen (alias) + 1;
  325           value_len = strlen (value) + 1;
  326 
  327           if (string_space_act + alias_len + value_len > string_space_max)
  328             {
  329               /* Increase size of memory pool.  */
  330               size_t new_size = (string_space_max
  331                      + (alias_len + value_len > 1024
  332                         ? alias_len + value_len : 1024));
  333               char *new_pool = (char *) realloc (string_space, new_size);
  334               if (new_pool == NULL)
  335             goto out;
  336 
  337               if (__builtin_expect (string_space != new_pool, 0))
  338             {
  339               size_t i;
  340 
  341               for (i = 0; i < nmap; i++)
  342                 {
  343                   map[i].alias += new_pool - string_space;
  344                   map[i].value += new_pool - string_space;
  345                 }
  346             }
  347 
  348               string_space = new_pool;
  349               string_space_max = new_size;
  350             }
  351 
  352           map[nmap].alias =
  353             (const char *) memcpy (&string_space[string_space_act],
  354                        alias, alias_len);
  355           string_space_act += alias_len;
  356 
  357           map[nmap].value =
  358             (const char *) memcpy (&string_space[string_space_act],
  359                        value, value_len);
  360           string_space_act += value_len;
  361 
  362           ++nmap;
  363           ++added;
  364         }
  365         }
  366     }
  367 
  368       /* Possibly not the whole line fits into the buffer.  Ignore
  369      the rest of the line.  */
  370       if (! complete_line)
  371     do
  372       if (FGETS (buf, sizeof buf, fp) == NULL)
  373         /* Make sure the inner loop will be left.  The outer loop
  374            will exit at the `feof' test.  */
  375         break;
  376     while (strchr (buf, '\n') == NULL);
  377     }
  378 
  379  out:
  380   /* Should we test for ferror()?  I think we have to silently ignore
  381      errors.  --drepper  */
  382   fclose (fp);
  383 
  384   if (added > 0)
  385     qsort (map, nmap, sizeof (struct alias_map),
  386        (int (*) (const void *, const void *)) alias_compare);
  387 
  388   return added;
  389 }
  390 
  391 
  392 static int
  393 extend_alias_table (void)
  394 {
  395   size_t new_size;
  396   struct alias_map *new_map;
  397 
  398   new_size = maxmap == 0 ? 100 : 2 * maxmap;
  399   new_map = (struct alias_map *) realloc (map, (new_size
  400                         * sizeof (struct alias_map)));
  401   if (new_map == NULL)
  402     /* Simply don't extend: we don't have any more core.  */
  403     return -1;
  404 
  405   map = new_map;
  406   maxmap = new_size;
  407   return 0;
  408 }
  409 
  410 
  411 static int
  412 alias_compare (const struct alias_map *map1, const struct alias_map *map2)
  413 {
  414 #if defined _LIBC || defined HAVE_STRCASECMP
  415   return strcasecmp (map1->alias, map2->alias);
  416 #else
  417   const unsigned char *p1 = (const unsigned char *) map1->alias;
  418   const unsigned char *p2 = (const unsigned char *) map2->alias;
  419   unsigned char c1, c2;
  420 
  421   if (p1 == p2)
  422     return 0;
  423 
  424   do
  425     {
  426       /* I know this seems to be odd but the tolower() function in
  427      some systems libc cannot handle nonalpha characters.  */
  428       c1 = isupper (*p1) ? tolower (*p1) : *p1;
  429       c2 = isupper (*p2) ? tolower (*p2) : *p2;
  430       if (c1 == '\0')
  431     break;
  432       ++p1;
  433       ++p2;
  434     }
  435   while (c1 == c2);
  436 
  437   return c1 - c2;
  438 #endif
  439 }