~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

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