Annotation of embedaddon/lrzsz/intl/localealias.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>