1
/* Handle aliases for locale names.
2
Copyright (C) 1995-1999, 2000, 2001 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>
38
# define alloca __builtin_alloca
39
# define HAVE_ALLOCA 1
41
# if defined HAVE_ALLOCA_H || defined _LIBC
59
/* @@ end of prolog @@ */
62
/* Rename the non ANSI C functions. This is required by the standard
63
because some ANSI C functions will require linking with this object
64
file and the name space must not be polluted. */
65
# define strcasecmp __strcasecmp
68
# define mempcpy __mempcpy
70
# define HAVE_MEMPCPY 1
71
# define HAVE___FSETLOCKING 1
73
/* We need locking here since we can be called from different places. */
74
# include <bits/libc-lock.h>
76
__libc_lock_define_initialized (static, lock);
79
#ifndef internal_function
80
# define internal_function
83
/* Some optimizations for glibc. */
85
# define FEOF(fp) feof_unlocked (fp)
86
# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
88
# define FEOF(fp) feof (fp)
89
# define FGETS(buf, n, fp) fgets (buf, n, fp)
92
/* For those losing systems which don't have `alloca' we have to add
93
some additional code emulating it. */
95
# define freea(p) /* nothing */
97
# define alloca(n) malloc (n)
98
# define freea(p) free (p)
101
#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
103
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
105
#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
107
# define feof(s) feof_unlocked (s)
118
static char *string_space;
119
static size_t string_space_act;
120
static size_t string_space_max;
121
static struct alias_map *map;
123
static size_t maxmap;
126
/* Prototypes for local functions. */
127
static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
129
static int extend_alias_table PARAMS ((void));
130
static int alias_compare PARAMS ((const struct alias_map *map1,
131
const struct alias_map *map2));
135
_nl_expand_alias (name)
138
static const char *locale_alias_path;
139
struct alias_map *retval;
140
const char *result = NULL;
144
__libc_lock_lock (lock);
147
if (locale_alias_path == NULL)
148
locale_alias_path = LOCALE_ALIAS_PATH;
152
struct alias_map item;
157
retval = (struct alias_map *) bsearch (&item, map, nmap,
158
sizeof (struct alias_map),
159
(int (*) PARAMS ((const void *,
165
/* We really found an alias. Return the value. */
168
result = retval->value;
172
/* Perhaps we can find another alias file. */
174
while (added == 0 && locale_alias_path[0] != '\0')
178
while (locale_alias_path[0] == PATH_SEPARATOR)
180
start = locale_alias_path;
182
while (locale_alias_path[0] != '\0'
183
&& locale_alias_path[0] != PATH_SEPARATOR)
186
if (start < locale_alias_path)
187
added = read_alias_file (start, locale_alias_path - start);
193
__libc_lock_unlock (lock);
202
read_alias_file (fname, fname_len)
209
static const char aliasfile[] = "/locale.alias";
211
full_fname = (char *) alloca (fname_len + sizeof aliasfile);
213
mempcpy (mempcpy (full_fname, fname, fname_len),
214
aliasfile, sizeof aliasfile);
216
memcpy (full_fname, fname, fname_len);
217
memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
220
fp = fopen (full_fname, "r");
225
#ifdef HAVE___FSETLOCKING
226
/* No threads present. */
227
__fsetlocking (fp, FSETLOCKING_BYCALLER);
233
/* It is a reasonable approach to use a fix buffer here because
234
a) we are only interested in the first two fields
235
b) these fields must be usable as file names and so must not
243
if (FGETS (buf, sizeof buf, fp) == NULL)
247
/* Possibly not the whole line fits into the buffer. Ignore
248
the rest of the line. */
249
if (strchr (buf, '\n') == NULL)
253
if (FGETS (altbuf, sizeof altbuf, fp) == NULL)
254
/* Make sure the inner loop will be left. The outer loop
255
will exit at the `feof' test. */
257
while (strchr (altbuf, '\n') == NULL);
261
/* Ignore leading white space. */
262
while (isspace ((unsigned char) cp[0]))
265
/* A leading '#' signals a comment line. */
266
if (cp[0] != '\0' && cp[0] != '#')
269
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
271
/* Terminate alias name. */
275
/* Now look for the beginning of the value. */
276
while (isspace ((unsigned char) cp[0]))
285
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
287
/* Terminate value. */
290
/* This has to be done to make the following test
291
for the end of line possible. We are looking for
292
the terminating '\n' which do not overwrite here. */
296
else if (cp[0] != '\0')
300
if (__builtin_expect (extend_alias_table (), 0))
303
alias_len = strlen (alias) + 1;
304
value_len = strlen (value) + 1;
306
if (string_space_act + alias_len + value_len > string_space_max)
308
/* Increase size of memory pool. */
309
size_t new_size = (string_space_max
310
+ (alias_len + value_len > 1024
311
? alias_len + value_len : 1024));
312
char *new_pool = (char *) realloc (string_space, new_size);
313
if (new_pool == NULL)
316
if (__builtin_expect (string_space != new_pool, 0))
320
for (i = 0; i < nmap; i++)
322
map[i].alias += new_pool - string_space;
323
map[i].value += new_pool - string_space;
327
string_space = new_pool;
328
string_space_max = new_size;
331
map[nmap].alias = memcpy (&string_space[string_space_act],
333
string_space_act += alias_len;
335
map[nmap].value = memcpy (&string_space[string_space_act],
337
string_space_act += value_len;
345
/* Should we test for ferror()? I think we have to silently ignore
350
qsort (map, nmap, sizeof (struct alias_map),
351
(int (*) PARAMS ((const void *, const void *))) alias_compare);
358
extend_alias_table ()
361
struct alias_map *new_map;
363
new_size = maxmap == 0 ? 100 : 2 * maxmap;
364
new_map = (struct alias_map *) realloc (map, (new_size
365
* sizeof (struct alias_map)));
367
/* Simply don't extend: we don't have any more core. */
377
static void __attribute__ ((unused))
380
if (string_space != NULL)
385
text_set_element (__libc_subfreeres, free_mem);
390
alias_compare (map1, map2)
391
const struct alias_map *map1;
392
const struct alias_map *map2;
394
#if defined _LIBC || defined HAVE_STRCASECMP
395
return strcasecmp (map1->alias, map2->alias);
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;
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;