Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

localealias.c

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

Generated on Tue Dec 20 10:14:20 2005 for vlc-0.8.4a by  doxygen 1.4.2