root/trunk/intl/localealias.c

Revision 2, 9.7 kB (checked in by jordi, 2 years ago)

Added the initial source layout with autotools and gettext support. Still no code for the project.

Line 
1/* Handle aliases for locale names.
2   Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
3
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)
7   any later version.
8
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.
13
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,
17   USA.  */
18
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
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <ctype.h>
31#include <stdio.h>
32#if defined _LIBC || defined HAVE___FSETLOCKING
33# include <stdio_ext.h>
34#endif
35#include <sys/types.h>
36
37#ifdef __GNUC__
38# undef alloca
39# define alloca __builtin_alloca
40# define HAVE_ALLOCA 1
41#else
42# ifdef _MSC_VER
43include <malloc.h>
44define alloca _alloca
45# else
46if defined HAVE_ALLOCA_H || defined _LIBC
47#   include <alloca.h>
48else
49#   ifdef _AIX
50 #pragma alloca
51#   else
52#    ifndef alloca
53char *alloca ();
54#    endif
55#   endif
56endif
57# endif
58#endif
59
60#include <stdlib.h>
61#include <string.h>
62
63#include "gettextP.h"
64
65#if ENABLE_RELOCATABLE
66# include "relocatable.h"
67#else
68# define relocate(pathname) (pathname)
69#endif
70
71/* @@ end of prolog @@ */
72
73#ifdef _LIBC
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
78
79# ifndef mempcpy
80define mempcpy __mempcpy
81# endif
82# define HAVE_MEMPCPY   1
83# define HAVE___FSETLOCKING 1
84
85/* We need locking here since we can be called from different places.  */
86# include <bits/libc-lock.h>
87
88__libc_lock_define_initialized (static, lock);
89#endif
90
91#ifndef internal_function
92# define internal_function
93#endif
94
95/* Some optimizations for glibc.  */
96#ifdef _LIBC
97# define FEOF(fp)       feof_unlocked (fp)
98# define FGETS(buf, n, fp)  fgets_unlocked (buf, n, fp)
99#else
100# define FEOF(fp)       feof (fp)
101# define FGETS(buf, n, fp)  fgets (buf, n, fp)
102#endif
103
104/* For those losing systems which don't have `alloca' we have to add
105   some additional code emulating it.  */
106#ifdef HAVE_ALLOCA
107# define freea(p) /* nothing */
108#else
109# define alloca(n) malloc (n)
110# define freea(p) free (p)
111#endif
112
113#if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
114# undef fgets
115# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
116#endif
117#if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
118# undef feof
119# define feof(s) feof_unlocked (s)
120#endif
121
122
123struct alias_map
124{
125  const char *alias;
126  const char *value;
127};
128
129
130#ifndef _LIBC
131# define libc_freeres_ptr(decl) decl
132#endif
133
134libc_freeres_ptr (static char *string_space);
135static size_t string_space_act;
136static size_t string_space_max;
137libc_freeres_ptr (static struct alias_map *map);
138static size_t nmap;
139static size_t maxmap;
140
141
142/* Prototypes for local functions.  */
143static size_t read_alias_file (const char *fname, int fname_len)
144     internal_function;
145static int extend_alias_table (void);
146static int alias_compare (const struct alias_map *map1,
147              const struct alias_map *map2);
148
149
150const char *
151_nl_expand_alias (const char *name)
152{
153  static const char *locale_alias_path;
154  struct alias_map *retval;
155  const char *result = NULL;
156  size_t added;
157
158#ifdef _LIBC
159  __libc_lock_lock (lock);
160#endif
161
162  if (locale_alias_path == NULL)
163    locale_alias_path = LOCALE_ALIAS_PATH;
164
165  do
166    {
167      struct alias_map item;
168
169      item.alias = name;
170
171      if (nmap > 0)
172    retval = (struct alias_map *) bsearch (&item, map, nmap,
173                           sizeof (struct alias_map),
174                           (int (*) (const void *,
175                             const void *)
176                        ) alias_compare);
177      else
178    retval = NULL;
179
180      /* We really found an alias.  Return the value.  */
181      if (retval != NULL)
182    {
183      result = retval->value;
184      break;
185    }
186
187      /* Perhaps we can find another alias file.  */
188      added = 0;
189      while (added == 0 && locale_alias_path[0] != '\0')
190    {
191      const char *start;
192
193      while (locale_alias_path[0] == PATH_SEPARATOR)
194        ++locale_alias_path;
195      start = locale_alias_path;
196
197      while (locale_alias_path[0] != '\0'
198         && locale_alias_path[0] != PATH_SEPARATOR)
199        ++locale_alias_path;
200
201      if (start < locale_alias_path)
202        added = read_alias_file (start, locale_alias_path - start);
203    }
204    }
205  while (added != 0);
206
207#ifdef _LIBC
208  __libc_lock_unlock (lock);
209#endif
210
211  return result;
212}
213
214
215static size_t
216internal_function
217read_alias_file (const char *fname, int fname_len)
218{
219  FILE *fp;
220  char *full_fname;
221  size_t added;
222  static const char aliasfile[] = "/locale.alias";
223
224  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
225#ifdef HAVE_MEMPCPY
226  mempcpy (mempcpy (full_fname, fname, fname_len),
227       aliasfile, sizeof aliasfile);
228#else
229  memcpy (full_fname, fname, fname_len);
230  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
231#endif
232
233  fp = fopen (relocate (full_fname), "r");
234  freea (full_fname);
235  if (fp == NULL)
236    return 0;
237
238#ifdef HAVE___FSETLOCKING
239  /* No threads present.  */
240  __fsetlocking (fp, FSETLOCKING_BYCALLER);
241#endif
242
243  added = 0;
244  while (!FEOF (fp))
245    {
246      /* It is a reasonable approach to use a fix buffer here because
247     a) we are only interested in the first two fields
248     b) these fields must be usable as file names and so must not
249        be that long
250     We avoid a multi-kilobyte buffer here since this would use up
251     stack space which we might not have if the program ran out of
252     memory.  */
253      char buf[400];
254      char *alias;
255      char *value;
256      char *cp;
257
258      if (FGETS (buf, sizeof buf, fp) == NULL)
259    /* EOF reached.  */
260    break;
261
262      cp = buf;
263      /* Ignore leading white space.  */
264      while (isspace ((unsigned char) cp[0]))
265    ++cp;
266
267      /* A leading '#' signals a comment line.  */
268      if (cp[0] != '\0' && cp[0] != '#')
269    {
270      alias = cp++;
271      while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
272        ++cp;
273      /* Terminate alias name.  */
274      if (cp[0] != '\0')
275        *cp++ = '\0';
276
277      /* Now look for the beginning of the value.  */
278      while (isspace ((unsigned char) cp[0]))
279        ++cp;
280
281      if (cp[0] != '\0')
282        {
283          size_t alias_len;
284          size_t value_len;
285
286          value = cp++;
287          while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
288        ++cp;
289          /* Terminate value.  */
290          if (cp[0] == '\n')
291        {
292          /* This has to be done to make the following test
293             for the end of line possible.  We are looking for
294             the terminating '\n' which do not overwrite here.  */
295          *cp++ = '\0';
296          *cp = '\n';
297        }
298          else if (cp[0] != '\0')
299        *cp++ = '\0';
300
301          if (nmap >= maxmap)
302        if (__builtin_expect (extend_alias_table (), 0))
303          return added;
304
305          alias_len = strlen (alias) + 1;
306          value_len = strlen (value) + 1;
307
308          if (string_space_act + alias_len + value_len > string_space_max)
309        {
310          /* Increase size of memory pool.  */
311          size_t new_size = (string_space_max
312                     + (alias_len + value_len > 1024
313                    ? alias_len + value_len : 1024));
314          char *new_pool = (char *) realloc (string_space, new_size);
315          if (new_pool == NULL)
316            return added;
317
318          if (__builtin_expect (string_space != new_pool, 0))
319            {
320              size_t i;
321
322              for (i = 0; i < nmap; i++)
323            {
324              map[i].alias += new_pool - string_space;
325              map[i].value += new_pool - string_space;
326            }
327            }
328
329          string_space = new_pool;
330          string_space_max = new_size;
331        }
332
333          map[nmap].alias = memcpy (&string_space[string_space_act],
334                    alias, alias_len);
335          string_space_act += alias_len;
336
337          map[nmap].value = memcpy (&string_space[string_space_act],
338                    value, value_len);
339          string_space_act += value_len;
340
341          ++nmap;
342          ++added;
343        }
344    }
345
346      /* Possibly not the whole line fits into the buffer.  Ignore
347     the rest of the line.  */
348      while (strchr (buf, '\n') == NULL)
349    if (FGETS (buf, sizeof buf, fp) == NULL)
350      /* Make sure the inner loop will be left.  The outer loop
351         will exit at the `feof' test.  */
352      break;
353    }
354
355  /* Should we test for ferror()?  I think we have to silently ignore
356     errors.  --drepper  */
357  fclose (fp);
358
359  if (added > 0)
360    qsort (map, nmap, sizeof (struct alias_map),
361       (int (*) (const void *, const void *)) alias_compare);
362
363  return added;
364}
365
366
367static int
368extend_alias_table ()
369{
370  size_t new_size;
371  struct alias_map *new_map;
372
373  new_size = maxmap == 0 ? 100 : 2 * maxmap;
374  new_map = (struct alias_map *) realloc (map, (new_size
375                        * sizeof (struct alias_map)));
376  if (new_map == NULL)
377    /* Simply don't extend: we don't have any more core.  */
378    return -1;
379
380  map = new_map;
381  maxmap = new_size;
382  return 0;
383}
384
385
386static int
387alias_compare (const struct alias_map *map1, const struct alias_map *map2)
388{
389#if defined _LIBC || defined HAVE_STRCASECMP
390  return strcasecmp (map1->alias, map2->alias);
391#else
392  const unsigned char *p1 = (const unsigned char *) map1->alias;
393  const unsigned char *p2 = (const unsigned char *) map2->alias;
394  unsigned char c1, c2;
395
396  if (p1 == p2)
397    return 0;
398
399  do
400    {
401      /* I know this seems to be odd but the tolower() function in
402     some systems libc cannot handle nonalpha characters.  */
403      c1 = isupper (*p1) ? tolower (*p1) : *p1;
404      c2 = isupper (*p2) ? tolower (*p2) : *p2;
405      if (c1 == '\0')
406    break;
407      ++p1;
408      ++p2;
409    }
410  while (c1 == c2);
411
412  return c1 - c2;
413#endif
414}
Note: See TracBrowser for help on using the browser.