localealias.c
上传用户:xxcykj
上传日期:2007-01-04
资源大小:727k
文件大小:10k
源码类别:

Email客户端

开发平台:

Unix_Linux

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