~ubuntu-branches/ubuntu/breezy/tiemu/breezy

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien BLACHE
  • Date: 2005-06-02 16:50:15 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050602165015-59ab24414tl2wzol
Tags: 1.99+svn1460-1
* New snapshot.
* debian/control:
  + Updated build-depends.

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