Add ULPs for tanh (-0.7).
[glibc.git] / intl / localealias.c
blobde34b57db3e453e40eb2179b96b0f5a3b6d69f9a
1 /* Handle aliases for locale names.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library 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 the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
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. */
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE 1
24 #endif
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <sys/types.h>
34 #ifdef __GNUC__
35 # define alloca __builtin_alloca
36 # define HAVE_ALLOCA 1
37 #else
38 # if defined HAVE_ALLOCA_H || defined _LIBC
39 # include <alloca.h>
40 # else
41 # ifdef _AIX
42 #pragma alloca
43 # else
44 # ifndef alloca
45 char *alloca ();
46 # endif
47 # endif
48 # endif
49 #endif
51 #if defined STDC_HEADERS || defined _LIBC
52 # include <stdlib.h>
53 #else
54 char *getenv ();
55 # ifdef HAVE_MALLOC_H
56 # include <malloc.h>
57 # else
58 void free ();
59 # endif
60 #endif
62 #if defined HAVE_STRING_H || defined _LIBC
63 # include <string.h>
64 #else
65 # include <strings.h>
66 # ifndef memcpy
67 # define memcpy(Dst, Src, Num) (bcopy (Src, Dst, Num), (Dst))
68 # endif
69 #endif
70 #if !HAVE_STRCHR && !defined _LIBC
71 # ifndef strchr
72 # define strchr index
73 # endif
74 #endif
76 #include "gettextP.h"
78 /* @@ end of prolog @@ */
80 #ifdef _LIBC
81 /* Rename the non ANSI C functions. This is required by the standard
82 because some ANSI C functions will require linking with this object
83 file and the name space must not be polluted. */
84 # define strcasecmp __strcasecmp
86 # ifndef mempcpy
87 # define mempcpy __mempcpy
88 # endif
89 # define HAVE_MEMPCPY 1
91 /* We need locking here since we can be called from different places. */
92 # include <bits/libc-lock.h>
94 __libc_lock_define_initialized (static, lock);
95 #endif
97 #ifndef internal_function
98 # define internal_function
99 #endif
101 /* For those losing systems which don't have `alloca' we have to add
102 some additional code emulating it. */
103 #ifdef HAVE_ALLOCA
104 # define freea(p) /* nothing */
105 #else
106 # define alloca(n) malloc (n)
107 # define freea(p) free (p)
108 #endif
110 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
111 # undef fgets
112 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
113 #endif
114 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
115 # undef feof
116 # define feof(s) feof_unlocked (s)
117 #endif
120 struct alias_map
122 const char *alias;
123 const char *value;
127 static char *string_space;
128 static size_t string_space_act;
129 static size_t string_space_max;
130 static struct alias_map *map;
131 static size_t nmap;
132 static size_t maxmap;
135 /* Prototypes for local functions. */
136 static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
137 internal_function;
138 static int extend_alias_table PARAMS ((void));
139 static int alias_compare PARAMS ((const struct alias_map *map1,
140 const struct alias_map *map2));
143 const char *
144 _nl_expand_alias (name)
145 const char *name;
147 static const char *locale_alias_path = LOCALE_ALIAS_PATH;
148 struct alias_map *retval;
149 const char *result = NULL;
150 size_t added;
152 #ifdef _LIBC
153 __libc_lock_lock (lock);
154 #endif
158 struct alias_map item;
160 item.alias = name;
162 if (nmap > 0)
163 retval = (struct alias_map *) bsearch (&item, map, nmap,
164 sizeof (struct alias_map),
165 (int (*) PARAMS ((const void *,
166 const void *))
167 ) alias_compare);
168 else
169 retval = NULL;
171 /* We really found an alias. Return the value. */
172 if (retval != NULL)
174 result = retval->value;
175 break;
178 /* Perhaps we can find another alias file. */
179 added = 0;
180 while (added == 0 && locale_alias_path[0] != '\0')
182 const char *start;
184 while (locale_alias_path[0] == ':')
185 ++locale_alias_path;
186 start = locale_alias_path;
188 while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
189 ++locale_alias_path;
191 if (start < locale_alias_path)
192 added = read_alias_file (start, locale_alias_path - start);
195 while (added != 0);
197 #ifdef _LIBC
198 __libc_lock_unlock (lock);
199 #endif
201 return result;
205 static size_t
206 internal_function
207 read_alias_file (fname, fname_len)
208 const char *fname;
209 int fname_len;
211 FILE *fp;
212 char *full_fname;
213 size_t added;
214 static const char aliasfile[] = "/locale.alias";
216 full_fname = (char *) alloca (fname_len + sizeof aliasfile);
217 #ifdef HAVE_MEMPCPY
218 mempcpy (mempcpy (full_fname, fname, fname_len),
219 aliasfile, sizeof aliasfile);
220 #else
221 memcpy (full_fname, fname, fname_len);
222 memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
223 #endif
225 fp = fopen (full_fname, "r");
226 freea (full_fname);
227 if (fp == NULL)
228 return 0;
230 added = 0;
231 while (!feof (fp))
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
236 be that long
238 char buf[BUFSIZ];
239 char *alias;
240 char *value;
241 char *cp;
243 if (fgets (buf, sizeof buf, fp) == NULL)
244 /* EOF reached. */
245 break;
247 /* Possibly not the whole line fits into the buffer. Ignore
248 the rest of the line. */
249 if (strchr (buf, '\n') == NULL)
251 char altbuf[BUFSIZ];
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. */
256 break;
257 while (strchr (altbuf, '\n') == NULL);
260 cp = buf;
261 /* Ignore leading white space. */
262 while (isspace (cp[0]))
263 ++cp;
265 /* A leading '#' signals a comment line. */
266 if (cp[0] != '\0' && cp[0] != '#')
268 alias = cp++;
269 while (cp[0] != '\0' && !isspace (cp[0]))
270 ++cp;
271 /* Terminate alias name. */
272 if (cp[0] != '\0')
273 *cp++ = '\0';
275 /* Now look for the beginning of the value. */
276 while (isspace (cp[0]))
277 ++cp;
279 if (cp[0] != '\0')
281 size_t alias_len;
282 size_t value_len;
284 value = cp++;
285 while (cp[0] != '\0' && !isspace (cp[0]))
286 ++cp;
287 /* Terminate value. */
288 if (cp[0] == '\n')
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. */
293 *cp++ = '\0';
294 *cp = '\n';
296 else if (cp[0] != '\0')
297 *cp++ = '\0';
299 if (nmap >= maxmap)
300 if (__builtin_expect (extend_alias_table (), 0))
301 return added;
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)
314 return added;
316 if (__builtin_expect (string_space != new_pool, 0))
318 size_t i;
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],
332 alias, alias_len);
333 string_space_act += alias_len;
335 map[nmap].value = memcpy (&string_space[string_space_act],
336 value, value_len);
337 string_space_act += value_len;
339 ++nmap;
340 ++added;
345 /* Should we test for ferror()? I think we have to silently ignore
346 errors. --drepper */
347 fclose (fp);
349 if (added > 0)
350 qsort (map, nmap, sizeof (struct alias_map),
351 (int (*) PARAMS ((const void *, const void *))) alias_compare);
353 return added;
357 static int
358 extend_alias_table ()
360 size_t new_size;
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)));
366 if (new_map == NULL)
367 /* Simply don't extend: we don't have any more core. */
368 return -1;
370 map = new_map;
371 maxmap = new_size;
372 return 0;
376 #ifdef _LIBC
377 static void __attribute__ ((unused))
378 free_mem (void)
380 if (string_space != NULL)
381 free (string_space);
382 if (map != NULL)
383 free (map);
385 text_set_element (__libc_subfreeres, free_mem);
386 #endif
389 static int
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);
396 #else
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;
401 if (p1 == p2)
402 return 0;
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;
410 if (c1 == '\0')
411 break;
412 ++p1;
413 ++p2;
415 while (c1 == c2);
417 return c1 - c2;
418 #endif