~ubuntu-branches/ubuntu/trusty/gcompris/trusty

« back to all changes in this revision

Viewing changes to intl/localealias.c

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