source: trunk/third/gaim-encryption/intl/localealias.c @ 22512

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