1
/* Handle aliases for locale names.
2
Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
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)
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.
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,
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. */
23
# define _GNU_SOURCE 1
32
#if defined _LIBC || defined HAVE___FSETLOCKING
33
# include <stdio_ext.h>
35
#include <sys/types.h>
39
# define alloca __builtin_alloca
40
# define HAVE_ALLOCA 1
44
# define alloca _alloca
46
# if defined HAVE_ALLOCA_H || defined _LIBC
65
#if ENABLE_RELOCATABLE
66
# include "relocatable.h"
68
# define relocate(pathname) (pathname)
71
/* @@ end of prolog @@ */
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
80
# define mempcpy __mempcpy
82
# define HAVE_MEMPCPY 1
83
# define HAVE___FSETLOCKING 1
85
/* We need locking here since we can be called from different places. */
86
# include <bits/libc-lock.h>
88
__libc_lock_define_initialized (static, lock);
91
#ifndef internal_function
92
# define internal_function
95
/* Some optimizations for glibc. */
97
# define FEOF(fp) feof_unlocked (fp)
98
# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
100
# define FEOF(fp) feof (fp)
101
# define FGETS(buf, n, fp) fgets (buf, n, fp)
104
/* For those losing systems which don't have `alloca' we have to add
105
some additional code emulating it. */
107
# define freea(p) /* nothing */
109
# define alloca(n) malloc (n)
110
# define freea(p) free (p)
113
#if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
115
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
117
#if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
119
# define feof(s) feof_unlocked (s)
131
# define libc_freeres_ptr(decl) decl
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);
139
static size_t maxmap;
142
/* Prototypes for local functions. */
143
static size_t read_alias_file (const char *fname, int fname_len)
145
static int extend_alias_table (void);
146
static int alias_compare (const struct alias_map *map1,
147
const struct alias_map *map2);
151
_nl_expand_alias (const char *name)
153
static const char *locale_alias_path;
154
struct alias_map *retval;
155
const char *result = NULL;
159
__libc_lock_lock (lock);
162
if (locale_alias_path == NULL)
163
locale_alias_path = LOCALE_ALIAS_PATH;
167
struct alias_map item;
172
retval = (struct alias_map *) bsearch (&item, map, nmap,
173
sizeof (struct alias_map),
174
(int (*) (const void *,
180
/* We really found an alias. Return the value. */
183
result = retval->value;
187
/* Perhaps we can find another alias file. */
189
while (added == 0 && locale_alias_path[0] != '\0')
193
while (locale_alias_path[0] == PATH_SEPARATOR)
195
start = locale_alias_path;
197
while (locale_alias_path[0] != '\0'
198
&& locale_alias_path[0] != PATH_SEPARATOR)
201
if (start < locale_alias_path)
202
added = read_alias_file (start, locale_alias_path - start);
208
__libc_lock_unlock (lock);
217
read_alias_file (const char *fname, int fname_len)
222
static const char aliasfile[] = "/locale.alias";
224
full_fname = (char *) alloca (fname_len + sizeof aliasfile);
226
mempcpy (mempcpy (full_fname, fname, fname_len),
227
aliasfile, sizeof aliasfile);
229
memcpy (full_fname, fname, fname_len);
230
memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
233
fp = fopen (relocate (full_fname), "r");
238
#ifdef HAVE___FSETLOCKING
239
/* No threads present. */
240
__fsetlocking (fp, FSETLOCKING_BYCALLER);
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
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
258
if (FGETS (buf, sizeof buf, fp) == NULL)
263
/* Ignore leading white space. */
264
while (isspace ((unsigned char) cp[0]))
267
/* A leading '#' signals a comment line. */
268
if (cp[0] != '\0' && cp[0] != '#')
271
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
273
/* Terminate alias name. */
277
/* Now look for the beginning of the value. */
278
while (isspace ((unsigned char) cp[0]))
287
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
289
/* Terminate value. */
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. */
298
else if (cp[0] != '\0')
302
if (__builtin_expect (extend_alias_table (), 0))
305
alias_len = strlen (alias) + 1;
306
value_len = strlen (value) + 1;
308
if (string_space_act + alias_len + value_len > string_space_max)
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)
318
if (__builtin_expect (string_space != new_pool, 0))
322
for (i = 0; i < nmap; i++)
324
map[i].alias += new_pool - string_space;
325
map[i].value += new_pool - string_space;
329
string_space = new_pool;
330
string_space_max = new_size;
333
map[nmap].alias = memcpy (&string_space[string_space_act],
335
string_space_act += alias_len;
337
map[nmap].value = memcpy (&string_space[string_space_act],
339
string_space_act += value_len;
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. */
355
/* Should we test for ferror()? I think we have to silently ignore
360
qsort (map, nmap, sizeof (struct alias_map),
361
(int (*) (const void *, const void *)) alias_compare);
368
extend_alias_table ()
371
struct alias_map *new_map;
373
new_size = maxmap == 0 ? 100 : 2 * maxmap;
374
new_map = (struct alias_map *) realloc (map, (new_size
375
* sizeof (struct alias_map)));
377
/* Simply don't extend: we don't have any more core. */
387
alias_compare (const struct alias_map *map1, const struct alias_map *map2)
389
#if defined _LIBC || defined HAVE_STRCASECMP
390
return strcasecmp (map1->alias, map2->alias);
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;
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;