1 /* Handle aliases for locale names.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
21 This must come before <config.h> because <config.h> may include
22 <features.h>, and once <features.h> has been included, it's too late. */
24 # define _GNU_SOURCE 1
33 #include <sys/types.h>
36 # define alloca __builtin_alloca
37 # define HAVE_ALLOCA 1
39 # if defined HAVE_ALLOCA_H || defined _LIBC
52 #if defined STDC_HEADERS || defined _LIBC
63 #if defined HAVE_STRING_H || defined _LIBC
68 # define memcpy(Dst, Src, Num) (bcopy (Src, Dst, Num), (Dst))
71 #if !HAVE_STRCHR && !defined _LIBC
79 /* @@ end of prolog @@ */
82 /* Rename the non ANSI C functions. This is required by the standard
83 because some ANSI C functions will require linking with this object
84 file and the name space must not be polluted. */
85 # define strcasecmp __strcasecmp
88 # define mempcpy __mempcpy
90 # define HAVE_MEMPCPY 1
92 /* We need locking here since we can be called from different places. */
93 # include <bits/libc-lock.h>
95 __libc_lock_define_initialized (static, lock
);
98 #ifndef internal_function
99 # define internal_function
102 /* For those losing systems which don't have `alloca' we have to add
103 some additional code emulating it. */
105 # define freea(p) /* nothing */
107 # define alloca(n) malloc (n)
108 # define freea(p) free (p)
111 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
113 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
115 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
117 # define feof(s) feof_unlocked (s)
128 static char *string_space
;
129 static size_t string_space_act
;
130 static size_t string_space_max
;
131 static struct alias_map
*map
;
133 static size_t maxmap
;
136 /* Prototypes for local functions. */
137 static size_t read_alias_file
PARAMS ((const char *fname
, int fname_len
))
139 static int extend_alias_table
PARAMS ((void));
140 static int alias_compare
PARAMS ((const struct alias_map
*map1
,
141 const struct alias_map
*map2
));
145 _nl_expand_alias (name
)
148 static const char *locale_alias_path
= LOCALE_ALIAS_PATH
;
149 struct alias_map
*retval
;
150 const char *result
= NULL
;
154 __libc_lock_lock (lock
);
159 struct alias_map item
;
164 retval
= (struct alias_map
*) bsearch (&item
, map
, nmap
,
165 sizeof (struct alias_map
),
166 (int (*) PARAMS ((const void *,
172 /* We really found an alias. Return the value. */
175 result
= retval
->value
;
179 /* Perhaps we can find another alias file. */
181 while (added
== 0 && locale_alias_path
[0] != '\0')
185 while (locale_alias_path
[0] == ':')
187 start
= locale_alias_path
;
189 while (locale_alias_path
[0] != '\0' && locale_alias_path
[0] != ':')
192 if (start
< locale_alias_path
)
193 added
= read_alias_file (start
, locale_alias_path
- start
);
199 __libc_lock_unlock (lock
);
208 read_alias_file (fname
, fname_len
)
215 static const char aliasfile
[] = "/locale.alias";
217 full_fname
= (char *) alloca (fname_len
+ sizeof aliasfile
);
219 mempcpy (mempcpy (full_fname
, fname
, fname_len
),
220 aliasfile
, sizeof aliasfile
);
222 memcpy (full_fname
, fname
, fname_len
);
223 memcpy (&full_fname
[fname_len
], aliasfile
, sizeof aliasfile
);
226 fp
= fopen (full_fname
, "r");
234 /* It is a reasonable approach to use a fix buffer here because
235 a) we are only interested in the first two fields
236 b) these fields must be usable as file names and so must not
244 if (fgets (buf
, sizeof buf
, fp
) == NULL
)
248 /* Possibly not the whole line fits into the buffer. Ignore
249 the rest of the line. */
250 if (strchr (buf
, '\n') == NULL
)
254 if (fgets (altbuf
, sizeof altbuf
, fp
) == NULL
)
255 /* Make sure the inner loop will be left. The outer loop
256 will exit at the `feof' test. */
258 while (strchr (altbuf
, '\n') == NULL
);
262 /* Ignore leading white space. */
263 while (isspace (cp
[0]))
266 /* A leading '#' signals a comment line. */
267 if (cp
[0] != '\0' && cp
[0] != '#')
270 while (cp
[0] != '\0' && !isspace (cp
[0]))
272 /* Terminate alias name. */
276 /* Now look for the beginning of the value. */
277 while (isspace (cp
[0]))
286 while (cp
[0] != '\0' && !isspace (cp
[0]))
288 /* Terminate value. */
291 /* This has to be done to make the following test
292 for the end of line possible. We are looking for
293 the terminating '\n' which do not overwrite here. */
297 else if (cp
[0] != '\0')
301 if (__builtin_expect (extend_alias_table (), 0))
304 alias_len
= strlen (alias
) + 1;
305 value_len
= strlen (value
) + 1;
307 if (string_space_act
+ alias_len
+ value_len
> string_space_max
)
309 /* Increase size of memory pool. */
310 size_t new_size
= (string_space_max
311 + (alias_len
+ value_len
> 1024
312 ? alias_len
+ value_len
: 1024));
313 char *new_pool
= (char *) realloc (string_space
, new_size
);
314 if (new_pool
== NULL
)
317 if (__builtin_expect (string_space
!= new_pool
, 0))
321 for (i
= 0; i
< nmap
; i
++)
323 map
[i
].alias
+= new_pool
- string_space
;
324 map
[i
].value
+= new_pool
- string_space
;
328 string_space
= new_pool
;
329 string_space_max
= new_size
;
332 map
[nmap
].alias
= memcpy (&string_space
[string_space_act
],
334 string_space_act
+= alias_len
;
336 map
[nmap
].value
= memcpy (&string_space
[string_space_act
],
338 string_space_act
+= value_len
;
346 /* Should we test for ferror()? I think we have to silently ignore
351 qsort (map
, nmap
, sizeof (struct alias_map
),
352 (int (*) PARAMS ((const void *, const void *))) alias_compare
);
359 extend_alias_table ()
362 struct alias_map
*new_map
;
364 new_size
= maxmap
== 0 ? 100 : 2 * maxmap
;
365 new_map
= (struct alias_map
*) realloc (map
, (new_size
366 * sizeof (struct alias_map
)));
368 /* Simply don't extend: we don't have any more core. */
378 static void __attribute__ ((unused
))
381 if (string_space
!= NULL
)
386 text_set_element (__libc_subfreeres
, free_mem
);
391 alias_compare (map1
, map2
)
392 const struct alias_map
*map1
;
393 const struct alias_map
*map2
;
395 #if defined _LIBC || defined HAVE_STRCASECMP
396 return strcasecmp (map1
->alias
, map2
->alias
);
398 const unsigned char *p1
= (const unsigned char *) map1
->alias
;
399 const unsigned char *p2
= (const unsigned char *) map2
->alias
;
400 unsigned char c1
, c2
;
407 /* I know this seems to be odd but the tolower() function in
408 some systems libc cannot handle nonalpha characters. */
409 c1
= isupper (*p1
) ? tolower (*p1
) : *p1
;
410 c2
= isupper (*p2
) ? tolower (*p2
) : *p2
;