~ubuntu-branches/ubuntu/feisty/groundhog/feisty

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-01-29 19:11:33 UTC
  • Revision ID: james.westby@ubuntu.com-20020129191133-r8u9eu0ggn5xbws4
Tags: upstream-1.3.2
ImportĀ upstreamĀ versionĀ 1.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
 
83
# define mempcpy __mempcpy
 
84
# define HAVE_MEMPCPY   1
 
85
 
 
86
/* We need locking here since we can be called from different places.  */
 
87
# include <bits/libc-lock.h>
 
88
 
 
89
__libc_lock_define_initialized (static, lock);
 
90
#endif
 
91
 
 
92
 
 
93
/* For those loosing systems which don't have `alloca' we have to add
 
94
   some additional code emulating it.  */
 
95
#ifdef HAVE_ALLOCA
 
96
/* Nothing has to be done.  */
 
97
# define ADD_BLOCK(list, address) /* nothing */
 
98
# define FREE_BLOCKS(list) /* nothing */
 
99
#else
 
100
struct block_list
 
101
{
 
102
  void *address;
 
103
  struct block_list *next;
 
104
};
 
105
# define ADD_BLOCK(list, addr)                                                \
 
106
  do {                                                                        \
 
107
    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
 
108
    /* If we cannot get a free block we cannot add the new element to         \
 
109
       the list.  */                                                          \
 
110
    if (newp != NULL) {                                                       \
 
111
      newp->address = (addr);                                                 \
 
112
      newp->next = (list);                                                    \
 
113
      (list) = newp;                                                          \
 
114
    }                                                                         \
 
115
  } while (0)
 
116
# define FREE_BLOCKS(list)                                                    \
 
117
  do {                                                                        \
 
118
    while (list != NULL) {                                                    \
 
119
      struct block_list *old = list;                                          \
 
120
      list = list->next;                                                      \
 
121
      free (old);                                                             \
 
122
    }                                                                         \
 
123
  } while (0)
 
124
# undef alloca
 
125
# define alloca(size) (malloc (size))
 
126
#endif  /* have alloca */
 
127
 
 
128
 
 
129
struct alias_map
 
130
{
 
131
  const char *alias;
 
132
  const char *value;
 
133
};
 
134
 
 
135
 
 
136
static char *string_space = NULL;
 
137
static size_t string_space_act = 0;
 
138
static size_t string_space_max = 0;
 
139
static struct alias_map *map;
 
140
static size_t nmap = 0;
 
141
static size_t maxmap = 0;
 
142
 
 
143
 
 
144
/* Prototypes for local functions.  */
 
145
static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
 
146
     internal_function;
 
147
static void extend_alias_table PARAMS ((void));
 
148
static int alias_compare PARAMS ((const struct alias_map *map1,
 
149
                                  const struct alias_map *map2));
 
150
 
 
151
 
 
152
const char *
 
153
_nl_expand_alias (name)
 
154
    const char *name;
 
155
{
 
156
  static const char *locale_alias_path = LOCALE_ALIAS_PATH;
 
157
  struct alias_map *retval;
 
158
  const char *result = NULL;
 
159
  size_t added;
 
160
 
 
161
#ifdef _LIBC
 
162
  __libc_lock_lock (lock);
 
163
#endif
 
164
 
 
165
  do
 
166
    {
 
167
      struct alias_map item;
 
168
 
 
169
      item.alias = name;
 
170
 
 
171
      if (nmap > 0)
 
172
        retval = (struct alias_map *) bsearch (&item, map, nmap,
 
173
                                               sizeof (struct alias_map),
 
174
                                               (int (*) PARAMS ((const void *,
 
175
                                                                 const void *))
 
176
                                                ) alias_compare);
 
177
      else
 
178
        retval = NULL;
 
179
 
 
180
      /* We really found an alias.  Return the value.  */
 
181
      if (retval != NULL)
 
182
        {
 
183
          result = retval->value;
 
184
          break;
 
185
        }
 
186
 
 
187
      /* Perhaps we can find another alias file.  */
 
188
      added = 0;
 
189
      while (added == 0 && locale_alias_path[0] != '\0')
 
190
        {
 
191
          const char *start;
 
192
 
 
193
          while (locale_alias_path[0] == ':')
 
194
            ++locale_alias_path;
 
195
          start = locale_alias_path;
 
196
 
 
197
          while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
 
198
            ++locale_alias_path;
 
199
 
 
200
          if (start < locale_alias_path)
 
201
            added = read_alias_file (start, locale_alias_path - start);
 
202
        }
 
203
    }
 
204
  while (added != 0);
 
205
 
 
206
#ifdef _LIBC
 
207
  __libc_lock_unlock (lock);
 
208
#endif
 
209
 
 
210
  return result;
 
211
}
 
212
 
 
213
 
 
214
static size_t
 
215
internal_function
 
216
read_alias_file (fname, fname_len)
 
217
     const char *fname;
 
218
     int fname_len;
 
219
{
 
220
#ifndef HAVE_ALLOCA
 
221
  struct block_list *block_list = NULL;
 
222
#endif
 
223
  FILE *fp;
 
224
  char *full_fname;
 
225
  size_t added;
 
226
  static const char aliasfile[] = "/locale.alias";
 
227
 
 
228
  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
 
229
  ADD_BLOCK (block_list, full_fname);
 
230
#ifdef HAVE_MEMPCPY
 
231
  mempcpy (mempcpy (full_fname, fname, fname_len),
 
232
           aliasfile, sizeof aliasfile);
 
233
#else
 
234
  memcpy (full_fname, fname, fname_len);
 
235
  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
 
236
#endif
 
237
 
 
238
  fp = fopen (full_fname, "r");
 
239
  if (fp == NULL)
 
240
    {
 
241
      FREE_BLOCKS (block_list);
 
242
      return 0;
 
243
    }
 
244
 
 
245
  added = 0;
 
246
  while (!feof (fp))
 
247
    {
 
248
      /* It is a reasonable approach to use a fix buffer here because
 
249
         a) we are only interested in the first two fields
 
250
         b) these fields must be usable as file names and so must not
 
251
            be that long
 
252
       */
 
253
      unsigned char buf[BUFSIZ];
 
254
      unsigned char *alias;
 
255
      unsigned char *value;
 
256
      unsigned char *cp;
 
257
 
 
258
      if (fgets (buf, sizeof buf, fp) == NULL)
 
259
        /* EOF reached.  */
 
260
        break;
 
261
 
 
262
      /* Possibly not the whole line fits into the buffer.  Ignore
 
263
         the rest of the line.  */
 
264
      if (strchr (buf, '\n') == NULL)
 
265
        {
 
266
          char altbuf[BUFSIZ];
 
267
          do
 
268
            if (fgets (altbuf, sizeof altbuf, fp) == NULL)
 
269
              /* Make sure the inner loop will be left.  The outer loop
 
270
                 will exit at the `feof' test.  */
 
271
              break;
 
272
          while (strchr (altbuf, '\n') == NULL);
 
273
        }
 
274
 
 
275
      cp = buf;
 
276
      /* Ignore leading white space.  */
 
277
      while (isspace (cp[0]))
 
278
        ++cp;
 
279
 
 
280
      /* A leading '#' signals a comment line.  */
 
281
      if (cp[0] != '\0' && cp[0] != '#')
 
282
        {
 
283
          alias = cp++;
 
284
          while (cp[0] != '\0' && !isspace (cp[0]))
 
285
            ++cp;
 
286
          /* Terminate alias name.  */
 
287
          if (cp[0] != '\0')
 
288
            *cp++ = '\0';
 
289
 
 
290
          /* Now look for the beginning of the value.  */
 
291
          while (isspace (cp[0]))
 
292
            ++cp;
 
293
 
 
294
          if (cp[0] != '\0')
 
295
            {
 
296
              size_t alias_len;
 
297
              size_t value_len;
 
298
 
 
299
              value = cp++;
 
300
              while (cp[0] != '\0' && !isspace (cp[0]))
 
301
                ++cp;
 
302
              /* Terminate value.  */
 
303
              if (cp[0] == '\n')
 
304
                {
 
305
                  /* This has to be done to make the following test
 
306
                     for the end of line possible.  We are looking for
 
307
                     the terminating '\n' which do not overwrite here.  */
 
308
                  *cp++ = '\0';
 
309
                  *cp = '\n';
 
310
                }
 
311
              else if (cp[0] != '\0')
 
312
                *cp++ = '\0';
 
313
 
 
314
              if (nmap >= maxmap)
 
315
                extend_alias_table ();
 
316
 
 
317
              alias_len = strlen (alias) + 1;
 
318
              value_len = strlen (value) + 1;
 
319
 
 
320
              if (string_space_act + alias_len + value_len > string_space_max)
 
321
                {
 
322
                  /* Increase size of memory pool.  */
 
323
                  size_t new_size = (string_space_max
 
324
                                     + (alias_len + value_len > 1024
 
325
                                        ? alias_len + value_len : 1024));
 
326
                  char *new_pool = (char *) realloc (string_space, new_size);
 
327
                  if (new_pool == NULL)
 
328
                    {
 
329
                      FREE_BLOCKS (block_list);
 
330
                      return added;
 
331
                    }
 
332
                  string_space = new_pool;
 
333
                  string_space_max = new_size;
 
334
                }
 
335
 
 
336
              map[nmap].alias = memcpy (&string_space[string_space_act],
 
337
                                        alias, alias_len);
 
338
              string_space_act += alias_len;
 
339
 
 
340
              map[nmap].value = memcpy (&string_space[string_space_act],
 
341
                                        value, value_len);
 
342
              string_space_act += value_len;
 
343
 
 
344
              ++nmap;
 
345
              ++added;
 
346
            }
 
347
        }
 
348
    }
 
349
 
 
350
  /* Should we test for ferror()?  I think we have to silently ignore
 
351
     errors.  --drepper  */
 
352
  fclose (fp);
 
353
 
 
354
  if (added > 0)
 
355
    qsort (map, nmap, sizeof (struct alias_map),
 
356
           (int (*) PARAMS ((const void *, const void *))) alias_compare);
 
357
 
 
358
  FREE_BLOCKS (block_list);
 
359
  return added;
 
360
}
 
361
 
 
362
 
 
363
static void
 
364
extend_alias_table ()
 
365
{
 
366
  size_t new_size;
 
367
  struct alias_map *new_map;
 
368
 
 
369
  new_size = maxmap == 0 ? 100 : 2 * maxmap;
 
370
  new_map = (struct alias_map *) realloc (map, (new_size
 
371
                                                * sizeof (struct alias_map)));
 
372
  if (new_map == NULL)
 
373
    /* Simply don't extend: we don't have any more core.  */
 
374
    return;
 
375
 
 
376
  map = new_map;
 
377
  maxmap = new_size;
 
378
}
 
379
 
 
380
 
 
381
#ifdef _LIBC
 
382
static void __attribute__ ((unused))
 
383
free_mem (void)
 
384
{
 
385
  if (string_space != NULL)
 
386
    free (string_space);
 
387
  if (map != NULL)
 
388
    free (map);
 
389
}
 
390
text_set_element (__libc_subfreeres, free_mem);
 
391
#endif
 
392
 
 
393
 
 
394
static int
 
395
alias_compare (map1, map2)
 
396
     const struct alias_map *map1;
 
397
     const struct alias_map *map2;
 
398
{
 
399
#if defined _LIBC || defined HAVE_STRCASECMP
 
400
  return strcasecmp (map1->alias, map2->alias);
 
401
#else
 
402
  const unsigned char *p1 = (const unsigned char *) map1->alias;
 
403
  const unsigned char *p2 = (const unsigned char *) map2->alias;
 
404
  unsigned char c1, c2;
 
405
 
 
406
  if (p1 == p2)
 
407
    return 0;
 
408
 
 
409
  do
 
410
    {
 
411
      /* I know this seems to be odd but the tolower() function in
 
412
         some systems libc cannot handle nonalpha characters.  */
 
413
      c1 = isupper (*p1) ? tolower (*p1) : *p1;
 
414
      c2 = isupper (*p2) ? tolower (*p2) : *p2;
 
415
      if (c1 == '\0')
 
416
        break;
 
417
      ++p1;
 
418
      ++p2;
 
419
    }
 
420
  while (c1 == c2);
 
421
 
 
422
  return c1 - c2;
 
423
#endif
 
424
}