"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/intl/localealias.c" (28 Aug 2013, 9432 Bytes) of archive /linux/misc/tin-2.4.1.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. For more information about "localealias.c" see the Fossies "Dox" file reference documentation.

    1 /* Handle aliases for locale names.
    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 <stdio.h>
   62 #include <sys/types.h>
   63 
   64 #include <stdlib.h>
   65 
   66 #include <string.h>
   67 #if !HAVE_STRCHR && !defined _LIBC
   68 # ifndef strchr
   69 #  define strchr index
   70 # endif
   71 #endif
   72 
   73 #include "gettextP.h"
   74 
   75 /* @@ end of prolog @@ */
   76 
   77 #ifdef _LIBC
   78 /* Rename the non ANSI C functions.  This is required by the standard
   79    because some ANSI C functions will require linking with this object
   80    file and the name space must not be polluted.  */
   81 # define strcasecmp __strcasecmp
   82 
   83 # ifndef mempcpy
   84 #  define mempcpy __mempcpy
   85 # endif
   86 # define HAVE_MEMPCPY   1
   87 
   88 /* We need locking here since we can be called from different places.  */
   89 # include <bits/libc-lock.h>
   90 
   91 __libc_lock_define_initialized (static, lock);
   92 #endif
   93 
   94 #ifndef internal_function
   95 # define internal_function
   96 #endif
   97 
   98 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
   99 # undef fgets
  100 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
  101 #endif
  102 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
  103 # undef feof
  104 # define feof(s) feof_unlocked (s)
  105 #endif
  106 
  107 
  108 struct alias_map
  109 {
  110   const char *alias;
  111   const char *value;
  112 };
  113 
  114 
  115 static char *string_space;
  116 static size_t string_space_act;
  117 static size_t string_space_max;
  118 static struct alias_map *map;
  119 static size_t nmap;
  120 static size_t maxmap;
  121 
  122 
  123 /* Prototypes for local functions.  */
  124 static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
  125      internal_function;
  126 static int extend_alias_table PARAMS ((void));
  127 static int alias_compare PARAMS ((const struct alias_map *map1,
  128                   const struct alias_map *map2));
  129 
  130 
  131 const char *
  132 _nl_expand_alias (name)
  133     const char *name;
  134 {
  135   static const char *locale_alias_path = LOCALE_ALIAS_PATH;
  136   struct alias_map *retval;
  137   const char *result = NULL;
  138   size_t added;
  139 
  140 #ifdef _LIBC
  141   __libc_lock_lock (lock);
  142 #endif
  143 
  144   do
  145     {
  146       struct alias_map item;
  147 
  148       item.alias = name;
  149 
  150       if (nmap > 0)
  151     retval = (struct alias_map *) bsearch (&item, map, nmap,
  152                            sizeof (struct alias_map),
  153                            (int (*) PARAMS ((const void *,
  154                                  const void *))
  155                         ) alias_compare);
  156       else
  157     retval = NULL;
  158 
  159       /* We really found an alias.  Return the value.  */
  160       if (retval != NULL)
  161     {
  162       result = retval->value;
  163       break;
  164     }
  165 
  166       /* Perhaps we can find another alias file.  */
  167       added = 0;
  168       while (added == 0 && locale_alias_path[0] != '\0')
  169     {
  170       const char *start;
  171 
  172       while (locale_alias_path[0] == PATH_SEPARATOR)
  173         ++locale_alias_path;
  174       start = locale_alias_path;
  175 
  176       while (locale_alias_path[0] != '\0'
  177          && locale_alias_path[0] != PATH_SEPARATOR)
  178         ++locale_alias_path;
  179 
  180       if (start < locale_alias_path)
  181         added = read_alias_file (start, locale_alias_path - start);
  182     }
  183     }
  184   while (added != 0);
  185 
  186 #ifdef _LIBC
  187   __libc_lock_unlock (lock);
  188 #endif
  189 
  190   return result;
  191 }
  192 
  193 
  194 static size_t
  195 internal_function
  196 read_alias_file (fname, fname_len)
  197      const char *fname;
  198      int fname_len;
  199 {
  200   FILE *fp;
  201   char *full_fname;
  202   size_t added;
  203   static const char aliasfile[] = "/locale.alias";
  204 
  205   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
  206 #ifdef HAVE_MEMPCPY
  207   mempcpy (mempcpy (full_fname, fname, fname_len),
  208        aliasfile, sizeof aliasfile);
  209 #else
  210   memcpy (full_fname, fname, fname_len);
  211   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
  212 #endif
  213 
  214   fp = fopen (full_fname, "r");
  215   freea (full_fname);
  216   if (fp == NULL)
  217     return 0;
  218 
  219   added = 0;
  220   while (!feof (fp))
  221     {
  222       /* It is a reasonable approach to use a fix buffer here because
  223      a) we are only interested in the first two fields
  224      b) these fields must be usable as file names and so must not
  225         be that long
  226        */
  227       char buf[BUFSIZ];
  228       char *alias;
  229       char *value;
  230       char *cp;
  231 
  232       if (fgets (buf, sizeof buf, fp) == NULL)
  233     /* EOF reached.  */
  234     break;
  235 
  236       /* Possibly not the whole line fits into the buffer.  Ignore
  237      the rest of the line.  */
  238       if (strchr (buf, '\n') == NULL)
  239     {
  240       char altbuf[BUFSIZ];
  241       do
  242         if (fgets (altbuf, sizeof altbuf, fp) == NULL)
  243           /* Make sure the inner loop will be left.  The outer loop
  244          will exit at the `feof' test.  */
  245           break;
  246       while (strchr (altbuf, '\n') == NULL);
  247     }
  248 
  249       cp = buf;
  250       /* Ignore leading white space.  */
  251       while (isspace (cp[0]))
  252     ++cp;
  253 
  254       /* A leading '#' signals a comment line.  */
  255       if (cp[0] != '\0' && cp[0] != '#')
  256     {
  257       alias = cp++;
  258       while (cp[0] != '\0' && !isspace (cp[0]))
  259         ++cp;
  260       /* Terminate alias name.  */
  261       if (cp[0] != '\0')
  262         *cp++ = '\0';
  263 
  264       /* Now look for the beginning of the value.  */
  265       while (isspace (cp[0]))
  266         ++cp;
  267 
  268       if (cp[0] != '\0')
  269         {
  270           size_t alias_len;
  271           size_t value_len;
  272 
  273           value = cp++;
  274           while (cp[0] != '\0' && !isspace (cp[0]))
  275         ++cp;
  276           /* Terminate value.  */
  277           if (cp[0] == '\n')
  278         {
  279           /* This has to be done to make the following test
  280              for the end of line possible.  We are looking for
  281              the terminating '\n' which do not overwrite here.  */
  282           *cp++ = '\0';
  283           *cp = '\n';
  284         }
  285           else if (cp[0] != '\0')
  286         *cp++ = '\0';
  287 
  288           if (nmap >= maxmap)
  289         if (__builtin_expect (extend_alias_table (), 0))
  290           return added;
  291 
  292           alias_len = strlen (alias) + 1;
  293           value_len = strlen (value) + 1;
  294 
  295           if (string_space_act + alias_len + value_len > string_space_max)
  296         {
  297           /* Increase size of memory pool.  */
  298           size_t new_size = (string_space_max
  299                      + (alias_len + value_len > 1024
  300                     ? alias_len + value_len : 1024));
  301           char *new_pool = (char *) realloc (string_space, new_size);
  302           if (new_pool == NULL)
  303             return added;
  304 
  305           if (__builtin_expect (string_space != new_pool, 0))
  306             {
  307               size_t i;
  308 
  309               for (i = 0; i < nmap; i++)
  310             {
  311               map[i].alias += new_pool - string_space;
  312               map[i].value += new_pool - string_space;
  313             }
  314             }
  315 
  316           string_space = new_pool;
  317           string_space_max = new_size;
  318         }
  319 
  320           map[nmap].alias = memcpy (&string_space[string_space_act],
  321                     alias, alias_len);
  322           string_space_act += alias_len;
  323 
  324           map[nmap].value = memcpy (&string_space[string_space_act],
  325                     value, value_len);
  326           string_space_act += value_len;
  327 
  328           ++nmap;
  329           ++added;
  330         }
  331     }
  332     }
  333 
  334   /* Should we test for ferror()?  I think we have to silently ignore
  335      errors.  --drepper  */
  336   fclose (fp);
  337 
  338   if (added > 0)
  339     qsort (map, nmap, sizeof (struct alias_map),
  340        (int (*) PARAMS ((const void *, const void *))) alias_compare);
  341 
  342   return added;
  343 }
  344 
  345 
  346 static int
  347 extend_alias_table ()
  348 {
  349   size_t new_size;
  350   struct alias_map *new_map;
  351 
  352   new_size = maxmap == 0 ? 100 : 2 * maxmap;
  353   new_map = (struct alias_map *) realloc (map, (new_size
  354                         * sizeof (struct alias_map)));
  355   if (new_map == NULL)
  356     /* Simply don't extend: we don't have any more core.  */
  357     return -1;
  358 
  359   map = new_map;
  360   maxmap = new_size;
  361   return 0;
  362 }
  363 
  364 
  365 #ifdef _LIBC
  366 static void __attribute__ ((unused))
  367 free_mem (void)
  368 {
  369   if (string_space != NULL)
  370     free (string_space);
  371   if (map != NULL)
  372     free (map);
  373 }
  374 text_set_element (__libc_subfreeres, free_mem);
  375 #endif
  376 
  377 
  378 static int
  379 alias_compare (map1, map2)
  380      const struct alias_map *map1;
  381      const struct alias_map *map2;
  382 {
  383 #if defined _LIBC || defined HAVE_STRCASECMP
  384   return strcasecmp (map1->alias, map2->alias);
  385 #else
  386   const unsigned char *p1 = (const unsigned char *) map1->alias;
  387   const unsigned char *p2 = (const unsigned char *) map2->alias;
  388   unsigned char c1, c2;
  389 
  390   if (p1 == p2)
  391     return 0;
  392 
  393   do
  394     {
  395       /* I know this seems to be odd but the tolower() function in
  396      some systems libc cannot handle nonalpha characters.  */
  397       c1 = isupper (*p1) ? tolower (*p1) : *p1;
  398       c2 = isupper (*p2) ? tolower (*p2) : *p2;
  399       if (c1 == '\0')
  400     break;
  401       ++p1;
  402       ++p2;
  403     }
  404   while (c1 == c2);
  405 
  406   return c1 - c2;
  407 #endif
  408 }