localealias.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:10k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /* Handle aliases for locale names.
  2.    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
  3.    This program is free software; you can redistribute it and/or modify it
  4.    under the terms of the GNU Library General Public License as published
  5.    by the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.
  7.    This program is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10.    Library General Public License for more details.
  11.    You should have received a copy of the GNU Library General Public
  12.    License along with this program; if not, write to the Free Software
  13.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  14.    USA.  */
  15. /* Tell glibc's <string.h> to provide a prototype for mempcpy().
  16.    This must come before <config.h> because <config.h> may include
  17.    <features.h>, and once <features.h> has been included, it's too late.  */
  18. #ifndef _GNU_SOURCE
  19. # define _GNU_SOURCE    1
  20. #endif
  21. #ifdef HAVE_CONFIG_H
  22. # include <config.h>
  23. #endif
  24. #include <ctype.h>
  25. #include <stdio.h>
  26. #if defined _LIBC || defined HAVE___FSETLOCKING
  27. # include <stdio_ext.h>
  28. #endif
  29. #include <sys/types.h>
  30. #ifdef __GNUC__
  31. # define alloca __builtin_alloca
  32. # define HAVE_ALLOCA 1
  33. #else
  34. # if defined HAVE_ALLOCA_H || defined _LIBC
  35. #  include <alloca.h>
  36. # else
  37. #  ifdef _AIX
  38.  #pragma alloca
  39. #  else
  40. #   ifndef alloca
  41. char *alloca ();
  42. #   endif
  43. #  endif
  44. # endif
  45. #endif
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include "gettextP.h"
  49. /* @@ end of prolog @@ */
  50. #ifdef _LIBC
  51. /* Rename the non ANSI C functions.  This is required by the standard
  52.    because some ANSI C functions will require linking with this object
  53.    file and the name space must not be polluted.  */
  54. # define strcasecmp __strcasecmp
  55. # ifndef mempcpy
  56. #  define mempcpy __mempcpy
  57. # endif
  58. # define HAVE_MEMPCPY 1
  59. # define HAVE___FSETLOCKING 1
  60. /* We need locking here since we can be called from different places.  */
  61. # include <bits/libc-lock.h>
  62. __libc_lock_define_initialized (static, lock);
  63. #endif
  64. #ifndef internal_function
  65. # define internal_function
  66. #endif
  67. /* Some optimizations for glibc.  */
  68. #ifdef _LIBC
  69. # define FEOF(fp) feof_unlocked (fp)
  70. # define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
  71. #else
  72. # define FEOF(fp) feof (fp)
  73. # define FGETS(buf, n, fp) fgets (buf, n, fp)
  74. #endif
  75. /* For those losing systems which don't have `alloca' we have to add
  76.    some additional code emulating it.  */
  77. #ifdef HAVE_ALLOCA
  78. # define freea(p) /* nothing */
  79. #else
  80. # define alloca(n) malloc (n)
  81. # define freea(p) free (p)
  82. #endif
  83. #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
  84. # undef fgets
  85. # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
  86. #endif
  87. #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
  88. # undef feof
  89. # define feof(s) feof_unlocked (s)
  90. #endif
  91. struct alias_map
  92. {
  93.   const char *alias;
  94.   const char *value;
  95. };
  96. static char *string_space;
  97. static size_t string_space_act;
  98. static size_t string_space_max;
  99. static struct alias_map *map;
  100. static size_t nmap;
  101. static size_t maxmap;
  102. /* Prototypes for local functions.  */
  103. static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
  104.      internal_function;
  105. static int extend_alias_table PARAMS ((void));
  106. static int alias_compare PARAMS ((const struct alias_map *map1,
  107.   const struct alias_map *map2));
  108. const char *
  109. _nl_expand_alias (name)
  110.     const char *name;
  111. {
  112.   static const char *locale_alias_path;
  113.   struct alias_map *retval;
  114.   const char *result = NULL;
  115.   size_t added;
  116. #ifdef _LIBC
  117.   __libc_lock_lock (lock);
  118. #endif
  119.   if (locale_alias_path == NULL)
  120.     locale_alias_path = LOCALE_ALIAS_PATH;
  121.   do
  122.     {
  123.       struct alias_map item;
  124.       item.alias = name;
  125.       if (nmap > 0)
  126. retval = (struct alias_map *) bsearch (&item, map, nmap,
  127.        sizeof (struct alias_map),
  128.        (int (*) PARAMS ((const void *,
  129.  const void *))
  130. ) alias_compare);
  131.       else
  132. retval = NULL;
  133.       /* We really found an alias.  Return the value.  */
  134.       if (retval != NULL)
  135. {
  136.   result = retval->value;
  137.   break;
  138. }
  139.       /* Perhaps we can find another alias file.  */
  140.       added = 0;
  141.       while (added == 0 && locale_alias_path[0] != '')
  142. {
  143.   const char *start;
  144.   while (locale_alias_path[0] == PATH_SEPARATOR)
  145.     ++locale_alias_path;
  146.   start = locale_alias_path;
  147.   while (locale_alias_path[0] != ''
  148.  && locale_alias_path[0] != PATH_SEPARATOR)
  149.     ++locale_alias_path;
  150.   if (start < locale_alias_path)
  151.     added = read_alias_file (start, locale_alias_path - start);
  152. }
  153.     }
  154.   while (added != 0);
  155. #ifdef _LIBC
  156.   __libc_lock_unlock (lock);
  157. #endif
  158.   return result;
  159. }
  160. static size_t
  161. internal_function
  162. read_alias_file (fname, fname_len)
  163.      const char *fname;
  164.      int fname_len;
  165. {
  166.   FILE *fp;
  167.   char *full_fname;
  168.   size_t added;
  169.   static const char aliasfile[] = "/locale.alias";
  170.   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
  171. #ifdef HAVE_MEMPCPY
  172.   mempcpy (mempcpy (full_fname, fname, fname_len),
  173.    aliasfile, sizeof aliasfile);
  174. #else
  175.   memcpy (full_fname, fname, fname_len);
  176.   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
  177. #endif
  178.   fp = fopen (full_fname, "r");
  179.   freea (full_fname);
  180.   if (fp == NULL)
  181.     return 0;
  182. #ifdef HAVE___FSETLOCKING
  183.   /* No threads present.  */
  184.   __fsetlocking (fp, FSETLOCKING_BYCALLER);
  185. #endif
  186.   added = 0;
  187.   while (!FEOF (fp))
  188.     {
  189.       /* It is a reasonable approach to use a fix buffer here because
  190.  a) we are only interested in the first two fields
  191.  b) these fields must be usable as file names and so must not
  192.     be that long
  193.        */
  194.       char buf[BUFSIZ];
  195.       char *alias;
  196.       char *value;
  197.       char *cp;
  198.       if (FGETS (buf, sizeof buf, fp) == NULL)
  199. /* EOF reached.  */
  200. break;
  201.       /* Possibly not the whole line fits into the buffer.  Ignore
  202.  the rest of the line.  */
  203.       if (strchr (buf, 'n') == NULL)
  204. {
  205.   char altbuf[BUFSIZ];
  206.   do
  207.     if (FGETS (altbuf, sizeof altbuf, fp) == NULL)
  208.       /* Make sure the inner loop will be left.  The outer loop
  209.  will exit at the `feof' test.  */
  210.       break;
  211.   while (strchr (altbuf, 'n') == NULL);
  212. }
  213.       cp = buf;
  214.       /* Ignore leading white space.  */
  215.       while (isspace ((unsigned char) cp[0]))
  216. ++cp;
  217.       /* A leading '#' signals a comment line.  */
  218.       if (cp[0] != '' && cp[0] != '#')
  219. {
  220.   alias = cp++;
  221.   while (cp[0] != '' && !isspace ((unsigned char) cp[0]))
  222.     ++cp;
  223.   /* Terminate alias name.  */
  224.   if (cp[0] != '')
  225.     *cp++ = '';
  226.   /* Now look for the beginning of the value.  */
  227.   while (isspace ((unsigned char) cp[0]))
  228.     ++cp;
  229.   if (cp[0] != '')
  230.     {
  231.       size_t alias_len;
  232.       size_t value_len;
  233.       value = cp++;
  234.       while (cp[0] != '' && !isspace ((unsigned char) cp[0]))
  235. ++cp;
  236.       /* Terminate value.  */
  237.       if (cp[0] == 'n')
  238. {
  239.   /* This has to be done to make the following test
  240.      for the end of line possible.  We are looking for
  241.      the terminating 'n' which do not overwrite here.  */
  242.   *cp++ = '';
  243.   *cp = 'n';
  244. }
  245.       else if (cp[0] != '')
  246. *cp++ = '';
  247.       if (nmap >= maxmap)
  248. if (__builtin_expect (extend_alias_table (), 0))
  249.   return added;
  250.       alias_len = strlen (alias) + 1;
  251.       value_len = strlen (value) + 1;
  252.       if (string_space_act + alias_len + value_len > string_space_max)
  253. {
  254.   /* Increase size of memory pool.  */
  255.   size_t new_size = (string_space_max
  256.      + (alias_len + value_len > 1024
  257. ? alias_len + value_len : 1024));
  258.   char *new_pool = (char *) realloc (string_space, new_size);
  259.   if (new_pool == NULL)
  260.     return added;
  261.   if (__builtin_expect (string_space != new_pool, 0))
  262.     {
  263.       size_t i;
  264.       for (i = 0; i < nmap; i++)
  265. {
  266.   map[i].alias += new_pool - string_space;
  267.   map[i].value += new_pool - string_space;
  268. }
  269.     }
  270.   string_space = new_pool;
  271.   string_space_max = new_size;
  272. }
  273.       map[nmap].alias = memcpy (&string_space[string_space_act],
  274. alias, alias_len);
  275.       string_space_act += alias_len;
  276.       map[nmap].value = memcpy (&string_space[string_space_act],
  277. value, value_len);
  278.       string_space_act += value_len;
  279.       ++nmap;
  280.       ++added;
  281.     }
  282. }
  283.     }
  284.   /* Should we test for ferror()?  I think we have to silently ignore
  285.      errors.  --drepper  */
  286.   fclose (fp);
  287.   if (added > 0)
  288.     qsort (map, nmap, sizeof (struct alias_map),
  289.    (int (*) PARAMS ((const void *, const void *))) alias_compare);
  290.   return added;
  291. }
  292. static int
  293. extend_alias_table ()
  294. {
  295.   size_t new_size;
  296.   struct alias_map *new_map;
  297.   new_size = maxmap == 0 ? 100 : 2 * maxmap;
  298.   new_map = (struct alias_map *) realloc (map, (new_size
  299. * sizeof (struct alias_map)));
  300.   if (new_map == NULL)
  301.     /* Simply don't extend: we don't have any more core.  */
  302.     return -1;
  303.   map = new_map;
  304.   maxmap = new_size;
  305.   return 0;
  306. }
  307. #ifdef _LIBC
  308. static void __attribute__ ((unused))
  309. free_mem (void)
  310. {
  311.   if (string_space != NULL)
  312.     free (string_space);
  313.   if (map != NULL)
  314.     free (map);
  315. }
  316. text_set_element (__libc_subfreeres, free_mem);
  317. #endif
  318. static int
  319. alias_compare (map1, map2)
  320.      const struct alias_map *map1;
  321.      const struct alias_map *map2;
  322. {
  323. #if defined _LIBC || defined HAVE_STRCASECMP
  324.   return strcasecmp (map1->alias, map2->alias);
  325. #else
  326.   const unsigned char *p1 = (const unsigned char *) map1->alias;
  327.   const unsigned char *p2 = (const unsigned char *) map2->alias;
  328.   unsigned char c1, c2;
  329.   if (p1 == p2)
  330.     return 0;
  331.   do
  332.     {
  333.       /* I know this seems to be odd but the tolower() function in
  334.  some systems libc cannot handle nonalpha characters.  */
  335.       c1 = isupper (*p1) ? tolower (*p1) : *p1;
  336.       c2 = isupper (*p2) ? tolower (*p2) : *p2;
  337.       if (c1 == '')
  338. break;
  339.       ++p1;
  340.       ++p2;
  341.     }
  342.   while (c1 == c2);
  343.   return c1 - c2;
  344. #endif
  345. }