~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

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