~ubuntu-branches/ubuntu/wily/alsaplayer/wily

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Hubert Chathi
  • Date: 2007-10-10 15:33:10 UTC
  • mto: (9.2.5 sid)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: james.westby@ubuntu.com-20071010153310-h3holq75eu2cigb0
Tags: upstream-0.99.80~rc4
ImportĀ upstreamĀ versionĀ 0.99.80~rc4

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