Back to index

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