~terry.guo/+junk/xbinutils

« back to all changes in this revision

Viewing changes to src/binutils/intl/localealias.c

  • Committer: Terry Guo
  • Date: 2012-09-05 06:50:40 UTC
  • Revision ID: terry.guo@arm.com-20120905065040-430c6mhm9b11a6r6
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
 
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 || defined HAVE_FGETS_UNLOCKED
 
114
# undef fgets
 
115
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
 
116
#endif
 
117
#if defined _LIBC_REENTRANT || defined HAVE_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 PARAMS ((const char *fname, int fname_len))
 
144
     internal_function;
 
145
static int extend_alias_table PARAMS ((void));
 
146
static int alias_compare PARAMS ((const struct alias_map *map1,
 
147
                                  const struct alias_map *map2));
 
148
 
 
149
 
 
150
const char *
 
151
_nl_expand_alias (name)
 
152
    const char *name;
 
153
{
 
154
  static const char *locale_alias_path;
 
155
  struct alias_map *retval;
 
156
  const char *result = NULL;
 
157
  size_t added;
 
158
 
 
159
#ifdef _LIBC
 
160
  __libc_lock_lock (lock);
 
161
#endif
 
162
 
 
163
  if (locale_alias_path == NULL)
 
164
    locale_alias_path = LOCALE_ALIAS_PATH;
 
165
 
 
166
  do
 
167
    {
 
168
      struct alias_map item;
 
169
 
 
170
      item.alias = name;
 
171
 
 
172
      if (nmap > 0)
 
173
        retval = (struct alias_map *) bsearch (&item, map, nmap,
 
174
                                               sizeof (struct alias_map),
 
175
                                               (int (*) PARAMS ((const void *,
 
176
                                                                 const void *))
 
177
                                                ) alias_compare);
 
178
      else
 
179
        retval = NULL;
 
180
 
 
181
      /* We really found an alias.  Return the value.  */
 
182
      if (retval != NULL)
 
183
        {
 
184
          result = retval->value;
 
185
          break;
 
186
        }
 
187
 
 
188
      /* Perhaps we can find another alias file.  */
 
189
      added = 0;
 
190
      while (added == 0 && locale_alias_path[0] != '\0')
 
191
        {
 
192
          const char *start;
 
193
 
 
194
          while (locale_alias_path[0] == PATH_SEPARATOR)
 
195
            ++locale_alias_path;
 
196
          start = locale_alias_path;
 
197
 
 
198
          while (locale_alias_path[0] != '\0'
 
199
                 && locale_alias_path[0] != PATH_SEPARATOR)
 
200
            ++locale_alias_path;
 
201
 
 
202
          if (start < locale_alias_path)
 
203
            added = read_alias_file (start, locale_alias_path - start);
 
204
        }
 
205
    }
 
206
  while (added != 0);
 
207
 
 
208
#ifdef _LIBC
 
209
  __libc_lock_unlock (lock);
 
210
#endif
 
211
 
 
212
  return result;
 
213
}
 
214
 
 
215
 
 
216
static size_t
 
217
internal_function
 
218
read_alias_file (fname, fname_len)
 
219
     const char *fname;
 
220
     int fname_len;
 
221
{
 
222
  FILE *fp;
 
223
  char *full_fname;
 
224
  size_t added;
 
225
  static const char aliasfile[] = "/locale.alias";
 
226
 
 
227
  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
 
228
#ifdef HAVE_MEMPCPY
 
229
  mempcpy (mempcpy (full_fname, fname, fname_len),
 
230
           aliasfile, sizeof aliasfile);
 
231
#else
 
232
  memcpy (full_fname, fname, fname_len);
 
233
  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
 
234
#endif
 
235
 
 
236
  fp = fopen (relocate (full_fname), "r");
 
237
  freea (full_fname);
 
238
  if (fp == NULL)
 
239
    return 0;
 
240
 
 
241
#ifdef HAVE___FSETLOCKING
 
242
  /* No threads present.  */
 
243
  __fsetlocking (fp, FSETLOCKING_BYCALLER);
 
244
#endif
 
245
 
 
246
  added = 0;
 
247
  while (!FEOF (fp))
 
248
    {
 
249
      /* It is a reasonable approach to use a fix buffer here because
 
250
         a) we are only interested in the first two fields
 
251
         b) these fields must be usable as file names and so must not
 
252
            be that long
 
253
         We avoid a multi-kilobyte buffer here since this would use up
 
254
         stack space which we might not have if the program ran out of
 
255
         memory.  */
 
256
      char buf[400];
 
257
      char *alias;
 
258
      char *value;
 
259
      char *cp;
 
260
 
 
261
      if (FGETS (buf, sizeof buf, fp) == NULL)
 
262
        /* EOF reached.  */
 
263
        break;
 
264
 
 
265
      cp = buf;
 
266
      /* Ignore leading white space.  */
 
267
      while (isspace ((unsigned char) cp[0]))
 
268
        ++cp;
 
269
 
 
270
      /* A leading '#' signals a comment line.  */
 
271
      if (cp[0] != '\0' && cp[0] != '#')
 
272
        {
 
273
          alias = cp++;
 
274
          while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
 
275
            ++cp;
 
276
          /* Terminate alias name.  */
 
277
          if (cp[0] != '\0')
 
278
            *cp++ = '\0';
 
279
 
 
280
          /* Now look for the beginning of the value.  */
 
281
          while (isspace ((unsigned char) cp[0]))
 
282
            ++cp;
 
283
 
 
284
          if (cp[0] != '\0')
 
285
            {
 
286
              size_t alias_len;
 
287
              size_t value_len;
 
288
 
 
289
              value = cp++;
 
290
              while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
 
291
                ++cp;
 
292
              /* Terminate value.  */
 
293
              if (cp[0] == '\n')
 
294
                {
 
295
                  /* This has to be done to make the following test
 
296
                     for the end of line possible.  We are looking for
 
297
                     the terminating '\n' which do not overwrite here.  */
 
298
                  *cp++ = '\0';
 
299
                  *cp = '\n';
 
300
                }
 
301
              else if (cp[0] != '\0')
 
302
                *cp++ = '\0';
 
303
 
 
304
              if (nmap >= maxmap)
 
305
                if (__builtin_expect (extend_alias_table (), 0))
 
306
                  return added;
 
307
 
 
308
              alias_len = strlen (alias) + 1;
 
309
              value_len = strlen (value) + 1;
 
310
 
 
311
              if (string_space_act + alias_len + value_len > string_space_max)
 
312
                {
 
313
                  /* Increase size of memory pool.  */
 
314
                  size_t new_size = (string_space_max
 
315
                                     + (alias_len + value_len > 1024
 
316
                                        ? alias_len + value_len : 1024));
 
317
                  char *new_pool = (char *) realloc (string_space, new_size);
 
318
                  if (new_pool == NULL)
 
319
                    return added;
 
320
 
 
321
                  if (__builtin_expect (string_space != new_pool, 0))
 
322
                    {
 
323
                      size_t i;
 
324
 
 
325
                      for (i = 0; i < nmap; i++)
 
326
                        {
 
327
                          map[i].alias += new_pool - string_space;
 
328
                          map[i].value += new_pool - string_space;
 
329
                        }
 
330
                    }
 
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
      /* Possibly not the whole line fits into the buffer.  Ignore
 
350
         the rest of the line.  */
 
351
      while (strchr (buf, '\n') == NULL)
 
352
        if (FGETS (buf, sizeof buf, fp) == NULL)
 
353
          /* Make sure the inner loop will be left.  The outer loop
 
354
             will exit at the `feof' test.  */
 
355
          break;
 
356
    }
 
357
 
 
358
  /* Should we test for ferror()?  I think we have to silently ignore
 
359
     errors.  --drepper  */
 
360
  fclose (fp);
 
361
 
 
362
  if (added > 0)
 
363
    qsort (map, nmap, sizeof (struct alias_map),
 
364
           (int (*) PARAMS ((const void *, const void *))) alias_compare);
 
365
 
 
366
  return added;
 
367
}
 
368
 
 
369
 
 
370
static int
 
371
extend_alias_table ()
 
372
{
 
373
  size_t new_size;
 
374
  struct alias_map *new_map;
 
375
 
 
376
  new_size = maxmap == 0 ? 100 : 2 * maxmap;
 
377
  new_map = (struct alias_map *) realloc (map, (new_size
 
378
                                                * sizeof (struct alias_map)));
 
379
  if (new_map == NULL)
 
380
    /* Simply don't extend: we don't have any more core.  */
 
381
    return -1;
 
382
 
 
383
  map = new_map;
 
384
  maxmap = new_size;
 
385
  return 0;
 
386
}
 
387
 
 
388
 
 
389
static int
 
390
alias_compare (map1, map2)
 
391
     const struct alias_map *map1;
 
392
     const struct alias_map *map2;
 
393
{
 
394
#if defined _LIBC || defined HAVE_STRCASECMP
 
395
  return strcasecmp (map1->alias, map2->alias);
 
396
#else
 
397
  const unsigned char *p1 = (const unsigned char *) map1->alias;
 
398
  const unsigned char *p2 = (const unsigned char *) map2->alias;
 
399
  unsigned char c1, c2;
 
400
 
 
401
  if (p1 == p2)
 
402
    return 0;
 
403
 
 
404
  do
 
405
    {
 
406
      /* I know this seems to be odd but the tolower() function in
 
407
         some systems libc cannot handle nonalpha characters.  */
 
408
      c1 = isupper (*p1) ? tolower (*p1) : *p1;
 
409
      c2 = isupper (*p2) ? tolower (*p2) : *p2;
 
410
      if (c1 == '\0')
 
411
        break;
 
412
      ++p1;
 
413
      ++p2;
 
414
    }
 
415
  while (c1 == c2);
 
416
 
 
417
  return c1 - c2;
 
418
#endif
 
419
}