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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
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 || defined HAVE_FGETS_UNLOCKED
115
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
117
#if defined _LIBC_REENTRANT || defined HAVE_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 PARAMS ((const char *fname, int fname_len))
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));
151
_nl_expand_alias (name)
154
static const char *locale_alias_path;
155
struct alias_map *retval;
156
const char *result = NULL;
160
__libc_lock_lock (lock);
163
if (locale_alias_path == NULL)
164
locale_alias_path = LOCALE_ALIAS_PATH;
168
struct alias_map item;
173
retval = (struct alias_map *) bsearch (&item, map, nmap,
174
sizeof (struct alias_map),
175
(int (*) PARAMS ((const void *,
181
/* We really found an alias. Return the value. */
184
result = retval->value;
188
/* Perhaps we can find another alias file. */
190
while (added == 0 && locale_alias_path[0] != '\0')
194
while (locale_alias_path[0] == PATH_SEPARATOR)
196
start = locale_alias_path;
198
while (locale_alias_path[0] != '\0'
199
&& locale_alias_path[0] != PATH_SEPARATOR)
202
if (start < locale_alias_path)
203
added = read_alias_file (start, locale_alias_path - start);
209
__libc_lock_unlock (lock);
218
read_alias_file (fname, fname_len)
225
static const char aliasfile[] = "/locale.alias";
227
full_fname = (char *) alloca (fname_len + sizeof aliasfile);
229
mempcpy (mempcpy (full_fname, fname, fname_len),
230
aliasfile, sizeof aliasfile);
232
memcpy (full_fname, fname, fname_len);
233
memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
236
fp = fopen (relocate (full_fname), "r");
241
#ifdef HAVE___FSETLOCKING
242
/* No threads present. */
243
__fsetlocking (fp, FSETLOCKING_BYCALLER);
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
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
261
if (FGETS (buf, sizeof buf, fp) == NULL)
266
/* Ignore leading white space. */
267
while (isspace ((unsigned char) cp[0]))
270
/* A leading '#' signals a comment line. */
271
if (cp[0] != '\0' && cp[0] != '#')
274
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
276
/* Terminate alias name. */
280
/* Now look for the beginning of the value. */
281
while (isspace ((unsigned char) cp[0]))
290
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
292
/* Terminate value. */
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. */
301
else if (cp[0] != '\0')
305
if (__builtin_expect (extend_alias_table (), 0))
308
alias_len = strlen (alias) + 1;
309
value_len = strlen (value) + 1;
311
if (string_space_act + alias_len + value_len > string_space_max)
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)
321
if (__builtin_expect (string_space != new_pool, 0))
325
for (i = 0; i < nmap; i++)
327
map[i].alias += new_pool - string_space;
328
map[i].value += new_pool - string_space;
332
string_space = new_pool;
333
string_space_max = new_size;
336
map[nmap].alias = memcpy (&string_space[string_space_act],
338
string_space_act += alias_len;
340
map[nmap].value = memcpy (&string_space[string_space_act],
342
string_space_act += value_len;
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. */
358
/* Should we test for ferror()? I think we have to silently ignore
363
qsort (map, nmap, sizeof (struct alias_map),
364
(int (*) PARAMS ((const void *, const void *))) alias_compare);
371
extend_alias_table ()
374
struct alias_map *new_map;
376
new_size = maxmap == 0 ? 100 : 2 * maxmap;
377
new_map = (struct alias_map *) realloc (map, (new_size
378
* sizeof (struct alias_map)));
380
/* Simply don't extend: we don't have any more core. */
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;