* sysdeps/unix/sysv/linux/m68k/sys/procfs.h: New file.
[glibc.git] / intl / localealias.c
blob381264ba03504d9206b50bb24e51476ac08f3c6e
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
18 02111-1307 USA. */
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. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <sys/types.h>
35 #ifdef __GNUC__
36 # define alloca __builtin_alloca
37 # define HAVE_ALLOCA 1
38 #else
39 # if defined HAVE_ALLOCA_H || defined _LIBC
40 # include <alloca.h>
41 # else
42 # ifdef _AIX
43 #pragma alloca
44 # else
45 # ifndef alloca
46 char *alloca ();
47 # endif
48 # endif
49 # endif
50 #endif
52 #if defined STDC_HEADERS || defined _LIBC
53 # include <stdlib.h>
54 #else
55 char *getenv ();
56 # ifdef HAVE_MALLOC_H
57 # include <malloc.h>
58 # else
59 void free ();
60 # endif
61 #endif
63 #if defined HAVE_STRING_H || defined _LIBC
64 # include <string.h>
65 #else
66 # include <strings.h>
67 # ifndef memcpy
68 # define memcpy(Dst, Src, Num) (bcopy (Src, Dst, Num), (Dst))
69 # endif
70 #endif
71 #if !HAVE_STRCHR && !defined _LIBC
72 # ifndef strchr
73 # define strchr index
74 # endif
75 #endif
77 #include "gettextP.h"
79 /* @@ end of prolog @@ */
81 #ifdef _LIBC
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
87 # ifndef mempcpy
88 # define mempcpy __mempcpy
89 # endif
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);
96 #endif
98 #ifndef internal_function
99 # define internal_function
100 #endif
102 /* For those losing systems which don't have `alloca' we have to add
103 some additional code emulating it. */
104 #ifdef HAVE_ALLOCA
105 # define freea(p) /* nothing */
106 #else
107 # define alloca(n) malloc (n)
108 # define freea(p) free (p)
109 #endif
111 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
112 # undef fgets
113 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
114 #endif
115 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
116 # undef feof
117 # define feof(s) feof_unlocked (s)
118 #endif
121 struct alias_map
123 const char *alias;
124 const char *value;
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;
132 static size_t nmap;
133 static size_t maxmap;
136 /* Prototypes for local functions. */
137 static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
138 internal_function;
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));
144 const char *
145 _nl_expand_alias (name)
146 const char *name;
148 static const char *locale_alias_path = LOCALE_ALIAS_PATH;
149 struct alias_map *retval;
150 const char *result = NULL;
151 size_t added;
153 #ifdef _LIBC
154 __libc_lock_lock (lock);
155 #endif
159 struct alias_map item;
161 item.alias = name;
163 if (nmap > 0)
164 retval = (struct alias_map *) bsearch (&item, map, nmap,
165 sizeof (struct alias_map),
166 (int (*) PARAMS ((const void *,
167 const void *))
168 ) alias_compare);
169 else
170 retval = NULL;
172 /* We really found an alias. Return the value. */
173 if (retval != NULL)
175 result = retval->value;
176 break;
179 /* Perhaps we can find another alias file. */
180 added = 0;
181 while (added == 0 && locale_alias_path[0] != '\0')
183 const char *start;
185 while (locale_alias_path[0] == ':')
186 ++locale_alias_path;
187 start = locale_alias_path;
189 while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
190 ++locale_alias_path;
192 if (start < locale_alias_path)
193 added = read_alias_file (start, locale_alias_path - start);
196 while (added != 0);
198 #ifdef _LIBC
199 __libc_lock_unlock (lock);
200 #endif
202 return result;
206 static size_t
207 internal_function
208 read_alias_file (fname, fname_len)
209 const char *fname;
210 int fname_len;
212 FILE *fp;
213 char *full_fname;
214 size_t added;
215 static const char aliasfile[] = "/locale.alias";
217 full_fname = (char *) alloca (fname_len + sizeof aliasfile);
218 #ifdef HAVE_MEMPCPY
219 mempcpy (mempcpy (full_fname, fname, fname_len),
220 aliasfile, sizeof aliasfile);
221 #else
222 memcpy (full_fname, fname, fname_len);
223 memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
224 #endif
226 fp = fopen (full_fname, "r");
227 freea (full_fname);
228 if (fp == NULL)
229 return 0;
231 added = 0;
232 while (!feof (fp))
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
237 be that long
239 char buf[BUFSIZ];
240 char *alias;
241 char *value;
242 char *cp;
244 if (fgets (buf, sizeof buf, fp) == NULL)
245 /* EOF reached. */
246 break;
248 /* Possibly not the whole line fits into the buffer. Ignore
249 the rest of the line. */
250 if (strchr (buf, '\n') == NULL)
252 char altbuf[BUFSIZ];
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. */
257 break;
258 while (strchr (altbuf, '\n') == NULL);
261 cp = buf;
262 /* Ignore leading white space. */
263 while (isspace (cp[0]))
264 ++cp;
266 /* A leading '#' signals a comment line. */
267 if (cp[0] != '\0' && cp[0] != '#')
269 alias = cp++;
270 while (cp[0] != '\0' && !isspace (cp[0]))
271 ++cp;
272 /* Terminate alias name. */
273 if (cp[0] != '\0')
274 *cp++ = '\0';
276 /* Now look for the beginning of the value. */
277 while (isspace (cp[0]))
278 ++cp;
280 if (cp[0] != '\0')
282 size_t alias_len;
283 size_t value_len;
285 value = cp++;
286 while (cp[0] != '\0' && !isspace (cp[0]))
287 ++cp;
288 /* Terminate value. */
289 if (cp[0] == '\n')
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. */
294 *cp++ = '\0';
295 *cp = '\n';
297 else if (cp[0] != '\0')
298 *cp++ = '\0';
300 if (nmap >= maxmap)
301 if (__builtin_expect (extend_alias_table (), 0))
302 return added;
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)
315 return added;
317 if (__builtin_expect (string_space != new_pool, 0))
319 size_t i;
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],
333 alias, alias_len);
334 string_space_act += alias_len;
336 map[nmap].value = memcpy (&string_space[string_space_act],
337 value, value_len);
338 string_space_act += value_len;
340 ++nmap;
341 ++added;
346 /* Should we test for ferror()? I think we have to silently ignore
347 errors. --drepper */
348 fclose (fp);
350 if (added > 0)
351 qsort (map, nmap, sizeof (struct alias_map),
352 (int (*) PARAMS ((const void *, const void *))) alias_compare);
354 return added;
358 static int
359 extend_alias_table ()
361 size_t new_size;
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)));
367 if (new_map == NULL)
368 /* Simply don't extend: we don't have any more core. */
369 return -1;
371 map = new_map;
372 maxmap = new_size;
373 return 0;
377 #ifdef _LIBC
378 static void __attribute__ ((unused))
379 free_mem (void)
381 if (string_space != NULL)
382 free (string_space);
383 if (map != NULL)
384 free (map);
386 text_set_element (__libc_subfreeres, free_mem);
387 #endif
390 static int
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);
397 #else
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;
402 if (p1 == p2)
403 return 0;
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;
411 if (c1 == '\0')
412 break;
413 ++p1;
414 ++p2;
416 while (c1 == c2);
418 return c1 - c2;
419 #endif