Back to Evolution Project page


Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Header Files   Sources   Compound Members   File Members  

localealias.c

00001 /* Handle aliases for locale names.
00002    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
00003    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2, or (at your option)
00008    any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software Foundation,
00017    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022 
00023 #include <ctype.h>
00024 #include <stdio.h>
00025 #include <sys/types.h>
00026 
00027 #ifdef __GNUC__
00028 # define alloca __builtin_alloca
00029 # define HAVE_ALLOCA 1
00030 #else
00031 # if defined HAVE_ALLOCA_H || defined _LIBC
00032 #  include <alloca.h>
00033 # else
00034 #  ifdef _AIX
00035  #pragma alloca
00036 #  else
00037 #   ifndef alloca
00038 char *alloca ();
00039 #   endif
00040 #  endif
00041 # endif
00042 #endif
00043 
00044 #if defined STDC_HEADERS || defined _LIBC
00045 # include <stdlib.h>
00046 #else
00047 char *getenv ();
00048 # ifdef HAVE_MALLOC_H
00049 #  include <malloc.h>
00050 # else
00051 void free ();
00052 # endif
00053 #endif
00054 
00055 #if defined HAVE_STRING_H || defined _LIBC
00056 # ifndef _GNU_SOURCE
00057 #  define _GNU_SOURCE   1
00058 # endif
00059 # include <string.h>
00060 #else
00061 # include <strings.h>
00062 # ifndef memcpy
00063 #  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
00064 # endif
00065 #endif
00066 #if !HAVE_STRCHR && !defined _LIBC
00067 # ifndef strchr
00068 #  define strchr index
00069 # endif
00070 #endif
00071 
00072 #include "gettext.h"
00073 #include "gettextP.h"
00074 
00075 /* @@ end of prolog @@ */
00076 
00077 #ifdef _LIBC
00078 /* Rename the non ANSI C functions.  This is required by the standard
00079    because some ANSI C functions will require linking with this object
00080    file and the name space must not be polluted.  */
00081 # define strcasecmp __strcasecmp
00082 
00083 # ifndef mempcpy
00084 #  define mempcpy __mempcpy
00085 # endif
00086 # define HAVE_MEMPCPY   1
00087 
00088 /* We need locking here since we can be called from different places.  */
00089 # include <bits/libc-lock.h>
00090 
00091 __libc_lock_define_initialized (static, lock);
00092 #endif
00093 
00094 #ifndef internal_function
00095 # define internal_function
00096 #endif
00097 
00098 /* For those loosing systems which don't have `alloca' we have to add
00099    some additional code emulating it.  */
00100 #ifdef HAVE_ALLOCA
00101 /* Nothing has to be done.  */
00102 # define ADD_BLOCK(list, address) /* nothing */
00103 # define FREE_BLOCKS(list) /* nothing */
00104 #else
00105 struct block_list
00106 {
00107   void *address;
00108   struct block_list *next;
00109 };
00110 # define ADD_BLOCK(list, addr)                            \
00111   do {                                        \
00112     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
00113     /* If we cannot get a free block we cannot add the new element to         \
00114        the list.  */                                  \
00115     if (newp != NULL) {                               \
00116       newp->address = (addr);                             \
00117       newp->next = (list);                            \
00118       (list) = newp;                                  \
00119     }                                         \
00120   } while (0)
00121 # define FREE_BLOCKS(list)                            \
00122   do {                                        \
00123     while (list != NULL) {                            \
00124       struct block_list *old = list;                          \
00125       list = list->next;                              \
00126       free (old);                                 \
00127     }                                         \
00128   } while (0)
00129 # undef alloca
00130 # define alloca(size) (malloc (size))
00131 #endif  /* have alloca */
00132 
00133 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
00134 # undef fgets
00135 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
00136 #endif
00137 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
00138 # undef feof
00139 # define feof(s) feof_unlocked (s)
00140 #endif
00141 
00142 
00143 struct alias_map
00144 {
00145   const char *alias;
00146   const char *value;
00147 };
00148 
00149 
00150 static char *string_space = NULL;
00151 static size_t string_space_act = 0;
00152 static size_t string_space_max = 0;
00153 static struct alias_map *map;
00154 static size_t nmap = 0;
00155 static size_t maxmap = 0;
00156 
00157 
00158 /* Prototypes for local functions.  */
00159 static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
00160      internal_function;
00161 static void extend_alias_table PARAMS ((void));
00162 static int alias_compare PARAMS ((const struct alias_map *map1,
00163                   const struct alias_map *map2));
00164 
00165 
00166 const char *
00167 _nl_expand_alias (name)
00168     const char *name;
00169 {
00170   static const char *locale_alias_path = LOCALE_ALIAS_PATH;
00171   struct alias_map *retval;
00172   const char *result = NULL;
00173   size_t added;
00174 
00175 #ifdef _LIBC
00176   __libc_lock_lock (lock);
00177 #endif
00178 
00179   do
00180     {
00181       struct alias_map item;
00182 
00183       item.alias = name;
00184 
00185       if (nmap > 0)
00186     retval = (struct alias_map *) bsearch (&item, map, nmap,
00187                            sizeof (struct alias_map),
00188                            (int (*) PARAMS ((const void *,
00189                                  const void *))
00190                         ) alias_compare);
00191       else
00192     retval = NULL;
00193 
00194       /* We really found an alias.  Return the value.  */
00195       if (retval != NULL)
00196     {
00197       result = retval->value;
00198       break;
00199     }
00200 
00201       /* Perhaps we can find another alias file.  */
00202       added = 0;
00203       while (added == 0 && locale_alias_path[0] != '\0')
00204     {
00205       const char *start;
00206 
00207       while (locale_alias_path[0] == ':')
00208         ++locale_alias_path;
00209       start = locale_alias_path;
00210 
00211       while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
00212         ++locale_alias_path;
00213 
00214       if (start < locale_alias_path)
00215         added = read_alias_file (start, locale_alias_path - start);
00216     }
00217     }
00218   while (added != 0);
00219 
00220 #ifdef _LIBC
00221   __libc_lock_unlock (lock);
00222 #endif
00223 
00224   return result;
00225 }
00226 
00227 
00228 static size_t
00229 internal_function
00230 read_alias_file (fname, fname_len)
00231      const char *fname;
00232      int fname_len;
00233 {
00234 #ifndef HAVE_ALLOCA
00235   struct block_list *block_list = NULL;
00236 #endif
00237   FILE *fp;
00238   char *full_fname;
00239   size_t added;
00240   static const char aliasfile[] = "/locale.alias";
00241 
00242   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
00243   ADD_BLOCK (block_list, full_fname);
00244 #ifdef HAVE_MEMPCPY
00245   mempcpy (mempcpy (full_fname, fname, fname_len),
00246        aliasfile, sizeof aliasfile);
00247 #else
00248   memcpy (full_fname, fname, fname_len);
00249   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
00250 #endif
00251 
00252   fp = fopen (full_fname, "r");
00253   if (fp == NULL)
00254     {
00255       FREE_BLOCKS (block_list);
00256       return 0;
00257     }
00258 
00259   added = 0;
00260   while (!feof (fp))
00261     {
00262       /* It is a reasonable approach to use a fix buffer here because
00263      a) we are only interested in the first two fields
00264      b) these fields must be usable as file names and so must not
00265         be that long
00266        */
00267       char buf[BUFSIZ];
00268       char *alias;
00269       char *value;
00270       char *cp;
00271 
00272       if (fgets (buf, sizeof buf, fp) == NULL)
00273     /* EOF reached.  */
00274     break;
00275 
00276       /* Possibly not the whole line fits into the buffer.  Ignore
00277      the rest of the line.  */
00278       if (strchr (buf, '\n') == NULL)
00279     {
00280       char altbuf[BUFSIZ];
00281       do
00282         if (fgets (altbuf, sizeof altbuf, fp) == NULL)
00283           /* Make sure the inner loop will be left.  The outer loop
00284          will exit at the `feof' test.  */
00285           break;
00286       while (strchr (altbuf, '\n') == NULL);
00287     }
00288 
00289       cp = buf;
00290       /* Ignore leading white space.  */
00291       while (isspace (cp[0]))
00292     ++cp;
00293 
00294       /* A leading '#' signals a comment line.  */
00295       if (cp[0] != '\0' && cp[0] != '#')
00296     {
00297       alias = cp++;
00298       while (cp[0] != '\0' && !isspace (cp[0]))
00299         ++cp;
00300       /* Terminate alias name.  */
00301       if (cp[0] != '\0')
00302         *cp++ = '\0';
00303 
00304       /* Now look for the beginning of the value.  */
00305       while (isspace (cp[0]))
00306         ++cp;
00307 
00308       if (cp[0] != '\0')
00309         {
00310           size_t alias_len;
00311           size_t value_len;
00312 
00313           value = cp++;
00314           while (cp[0] != '\0' && !isspace (cp[0]))
00315         ++cp;
00316           /* Terminate value.  */
00317           if (cp[0] == '\n')
00318         {
00319           /* This has to be done to make the following test
00320              for the end of line possible.  We are looking for
00321              the terminating '\n' which do not overwrite here.  */
00322           *cp++ = '\0';
00323           *cp = '\n';
00324         }
00325           else if (cp[0] != '\0')
00326         *cp++ = '\0';
00327 
00328           if (nmap >= maxmap)
00329         extend_alias_table ();
00330 
00331           alias_len = strlen (alias) + 1;
00332           value_len = strlen (value) + 1;
00333 
00334           if (string_space_act + alias_len + value_len > string_space_max)
00335         {
00336           /* Increase size of memory pool.  */
00337           size_t new_size = (string_space_max
00338                      + (alias_len + value_len > 1024
00339                     ? alias_len + value_len : 1024));
00340           char *new_pool = (char *) realloc (string_space, new_size);
00341           if (new_pool == NULL)
00342             {
00343               FREE_BLOCKS (block_list);
00344               return added;
00345             }
00346           string_space = new_pool;
00347           string_space_max = new_size;
00348         }
00349 
00350           map[nmap].alias = memcpy (&string_space[string_space_act],
00351                     alias, alias_len);
00352           string_space_act += alias_len;
00353 
00354           map[nmap].value = memcpy (&string_space[string_space_act],
00355                     value, value_len);
00356           string_space_act += value_len;
00357 
00358           ++nmap;
00359           ++added;
00360         }
00361     }
00362     }
00363 
00364   /* Should we test for ferror()?  I think we have to silently ignore
00365      errors.  --drepper  */
00366   fclose (fp);
00367 
00368   if (added > 0)
00369     qsort (map, nmap, sizeof (struct alias_map),
00370        (int (*) PARAMS ((const void *, const void *))) alias_compare);
00371 
00372   FREE_BLOCKS (block_list);
00373   return added;
00374 }
00375 
00376 
00377 static void
00378 extend_alias_table ()
00379 {
00380   size_t new_size;
00381   struct alias_map *new_map;
00382 
00383   new_size = maxmap == 0 ? 100 : 2 * maxmap;
00384   new_map = (struct alias_map *) realloc (map, (new_size
00385                         * sizeof (struct alias_map)));
00386   if (new_map == NULL)
00387     /* Simply don't extend: we don't have any more core.  */
00388     return;
00389 
00390   map = new_map;
00391   maxmap = new_size;
00392 }
00393 
00394 
00395 #ifdef _LIBC
00396 static void __attribute__ ((unused))
00397 free_mem (void)
00398 {
00399   if (string_space != NULL)
00400     free (string_space);
00401   if (map != NULL)
00402     free (map);
00403 }
00404 text_set_element (__libc_subfreeres, free_mem);
00405 #endif
00406 
00407 
00408 static int
00409 alias_compare (map1, map2)
00410      const struct alias_map *map1;
00411      const struct alias_map *map2;
00412 {
00413 #if defined _LIBC || defined HAVE_STRCASECMP
00414   return strcasecmp (map1->alias, map2->alias);
00415 #else
00416   const unsigned char *p1 = (const unsigned char *) map1->alias;
00417   const unsigned char *p2 = (const unsigned char *) map2->alias;
00418   unsigned char c1, c2;
00419 
00420   if (p1 == p2)
00421     return 0;
00422 
00423   do
00424     {
00425       /* I know this seems to be odd but the tolower() function in
00426      some systems libc cannot handle nonalpha characters.  */
00427       c1 = isupper (*p1) ? tolower (*p1) : *p1;
00428       c2 = isupper (*p2) ? tolower (*p2) : *p2;
00429       if (c1 == '\0')
00430     break;
00431       ++p1;
00432       ++p2;
00433     }
00434   while (c1 == c2);
00435 
00436   return c1 - c2;
00437 #endif
00438 }

Generated at Mon Nov 6 22:47:05 2000 for TheGameofEvolution by doxygen 1.0.0 written by Dimitri van Heesch, © 1997-1999