~ubuntu-branches/ubuntu/lucid/mc/lucid

« back to all changes in this revision

Viewing changes to intl/localealias.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-09-16 10:38:59 UTC
  • mfrom: (3.1.6 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080916103859-2uwn8w61xk5mbxxq
Tags: 2:4.6.2~git20080311-4
Corrected fix for odt2txt issue (Closes: #492019) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <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
 
# define alloca __builtin_alloca
39
 
# define HAVE_ALLOCA 1
40
 
#else
41
 
# if defined HAVE_ALLOCA_H || defined _LIBC
42
 
#  include <alloca.h>
43
 
# else
44
 
#  ifdef _AIX
45
 
 #pragma alloca
46
 
#  else
47
 
#   ifndef alloca
48
 
char *alloca ();
49
 
#   endif
50
 
#  endif
51
 
# endif
52
 
#endif
53
 
 
54
 
#include <stdlib.h>
55
 
#include <string.h>
56
 
 
57
 
#include "gettextP.h"
58
 
 
59
 
/* @@ end of prolog @@ */
60
 
 
61
 
#ifdef _LIBC
62
 
/* Rename the non ANSI C functions.  This is required by the standard
63
 
   because some ANSI C functions will require linking with this object
64
 
   file and the name space must not be polluted.  */
65
 
# define strcasecmp __strcasecmp
66
 
 
67
 
# ifndef mempcpy
68
 
#  define mempcpy __mempcpy
69
 
# endif
70
 
# define HAVE_MEMPCPY   1
71
 
# define HAVE___FSETLOCKING     1
72
 
 
73
 
/* We need locking here since we can be called from different places.  */
74
 
# include <bits/libc-lock.h>
75
 
 
76
 
__libc_lock_define_initialized (static, lock);
77
 
#endif
78
 
 
79
 
#ifndef internal_function
80
 
# define internal_function
81
 
#endif
82
 
 
83
 
/* Some optimizations for glibc.  */
84
 
#ifdef _LIBC
85
 
# define FEOF(fp)               feof_unlocked (fp)
86
 
# define FGETS(buf, n, fp)      fgets_unlocked (buf, n, fp)
87
 
#else
88
 
# define FEOF(fp)               feof (fp)
89
 
# define FGETS(buf, n, fp)      fgets (buf, n, fp)
90
 
#endif
91
 
 
92
 
/* For those losing systems which don't have `alloca' we have to add
93
 
   some additional code emulating it.  */
94
 
#ifdef HAVE_ALLOCA
95
 
# define freea(p) /* nothing */
96
 
#else
97
 
# define alloca(n) malloc (n)
98
 
# define freea(p) free (p)
99
 
#endif
100
 
 
101
 
#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
102
 
# undef fgets
103
 
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
104
 
#endif
105
 
#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
106
 
# undef feof
107
 
# define feof(s) feof_unlocked (s)
108
 
#endif
109
 
 
110
 
 
111
 
struct alias_map
112
 
{
113
 
  const char *alias;
114
 
  const char *value;
115
 
};
116
 
 
117
 
 
118
 
static char *string_space;
119
 
static size_t string_space_act;
120
 
static size_t string_space_max;
121
 
static struct alias_map *map;
122
 
static size_t nmap;
123
 
static size_t maxmap;
124
 
 
125
 
 
126
 
/* Prototypes for local functions.  */
127
 
static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
128
 
     internal_function;
129
 
static int extend_alias_table PARAMS ((void));
130
 
static int alias_compare PARAMS ((const struct alias_map *map1,
131
 
                                  const struct alias_map *map2));
132
 
 
133
 
 
134
 
const char *
135
 
_nl_expand_alias (name)
136
 
    const char *name;
137
 
{
138
 
  static const char *locale_alias_path;
139
 
  struct alias_map *retval;
140
 
  const char *result = NULL;
141
 
  size_t added;
142
 
 
143
 
#ifdef _LIBC
144
 
  __libc_lock_lock (lock);
145
 
#endif
146
 
 
147
 
  if (locale_alias_path == NULL)
148
 
    locale_alias_path = LOCALE_ALIAS_PATH;
149
 
 
150
 
  do
151
 
    {
152
 
      struct alias_map item;
153
 
 
154
 
      item.alias = name;
155
 
 
156
 
      if (nmap > 0)
157
 
        retval = (struct alias_map *) bsearch (&item, map, nmap,
158
 
                                               sizeof (struct alias_map),
159
 
                                               (int (*) PARAMS ((const void *,
160
 
                                                                 const void *))
161
 
                                                ) alias_compare);
162
 
      else
163
 
        retval = NULL;
164
 
 
165
 
      /* We really found an alias.  Return the value.  */
166
 
      if (retval != NULL)
167
 
        {
168
 
          result = retval->value;
169
 
          break;
170
 
        }
171
 
 
172
 
      /* Perhaps we can find another alias file.  */
173
 
      added = 0;
174
 
      while (added == 0 && locale_alias_path[0] != '\0')
175
 
        {
176
 
          const char *start;
177
 
 
178
 
          while (locale_alias_path[0] == PATH_SEPARATOR)
179
 
            ++locale_alias_path;
180
 
          start = locale_alias_path;
181
 
 
182
 
          while (locale_alias_path[0] != '\0'
183
 
                 && locale_alias_path[0] != PATH_SEPARATOR)
184
 
            ++locale_alias_path;
185
 
 
186
 
          if (start < locale_alias_path)
187
 
            added = read_alias_file (start, locale_alias_path - start);
188
 
        }
189
 
    }
190
 
  while (added != 0);
191
 
 
192
 
#ifdef _LIBC
193
 
  __libc_lock_unlock (lock);
194
 
#endif
195
 
 
196
 
  return result;
197
 
}
198
 
 
199
 
 
200
 
static size_t
201
 
internal_function
202
 
read_alias_file (fname, fname_len)
203
 
     const char *fname;
204
 
     int fname_len;
205
 
{
206
 
  FILE *fp;
207
 
  char *full_fname;
208
 
  size_t added;
209
 
  static const char aliasfile[] = "/locale.alias";
210
 
 
211
 
  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
212
 
#ifdef HAVE_MEMPCPY
213
 
  mempcpy (mempcpy (full_fname, fname, fname_len),
214
 
           aliasfile, sizeof aliasfile);
215
 
#else
216
 
  memcpy (full_fname, fname, fname_len);
217
 
  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
218
 
#endif
219
 
 
220
 
  fp = fopen (full_fname, "r");
221
 
  freea (full_fname);
222
 
  if (fp == NULL)
223
 
    return 0;
224
 
 
225
 
#ifdef HAVE___FSETLOCKING
226
 
  /* No threads present.  */
227
 
  __fsetlocking (fp, FSETLOCKING_BYCALLER);
228
 
#endif
229
 
 
230
 
  added = 0;
231
 
  while (!FEOF (fp))
232
 
    {
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
237
 
       */
238
 
      char buf[BUFSIZ];
239
 
      char *alias;
240
 
      char *value;
241
 
      char *cp;
242
 
 
243
 
      if (FGETS (buf, sizeof buf, fp) == NULL)
244
 
        /* EOF reached.  */
245
 
        break;
246
 
 
247
 
      /* Possibly not the whole line fits into the buffer.  Ignore
248
 
         the rest of the line.  */
249
 
      if (strchr (buf, '\n') == NULL)
250
 
        {
251
 
          char altbuf[BUFSIZ];
252
 
          do
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);
258
 
        }
259
 
 
260
 
      cp = buf;
261
 
      /* Ignore leading white space.  */
262
 
      while (isspace ((unsigned char) cp[0]))
263
 
        ++cp;
264
 
 
265
 
      /* A leading '#' signals a comment line.  */
266
 
      if (cp[0] != '\0' && cp[0] != '#')
267
 
        {
268
 
          alias = cp++;
269
 
          while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
270
 
            ++cp;
271
 
          /* Terminate alias name.  */
272
 
          if (cp[0] != '\0')
273
 
            *cp++ = '\0';
274
 
 
275
 
          /* Now look for the beginning of the value.  */
276
 
          while (isspace ((unsigned char) cp[0]))
277
 
            ++cp;
278
 
 
279
 
          if (cp[0] != '\0')
280
 
            {
281
 
              size_t alias_len;
282
 
              size_t value_len;
283
 
 
284
 
              value = cp++;
285
 
              while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
286
 
                ++cp;
287
 
              /* Terminate value.  */
288
 
              if (cp[0] == '\n')
289
 
                {
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';
295
 
                }
296
 
              else if (cp[0] != '\0')
297
 
                *cp++ = '\0';
298
 
 
299
 
              if (nmap >= maxmap)
300
 
                if (__builtin_expect (extend_alias_table (), 0))
301
 
                  return added;
302
 
 
303
 
              alias_len = strlen (alias) + 1;
304
 
              value_len = strlen (value) + 1;
305
 
 
306
 
              if (string_space_act + alias_len + value_len > string_space_max)
307
 
                {
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;
315
 
 
316
 
                  if (__builtin_expect (string_space != new_pool, 0))
317
 
                    {
318
 
                      size_t i;
319
 
 
320
 
                      for (i = 0; i < nmap; i++)
321
 
                        {
322
 
                          map[i].alias += new_pool - string_space;
323
 
                          map[i].value += new_pool - string_space;
324
 
                        }
325
 
                    }
326
 
 
327
 
                  string_space = new_pool;
328
 
                  string_space_max = new_size;
329
 
                }
330
 
 
331
 
              map[nmap].alias = memcpy (&string_space[string_space_act],
332
 
                                        alias, alias_len);
333
 
              string_space_act += alias_len;
334
 
 
335
 
              map[nmap].value = memcpy (&string_space[string_space_act],
336
 
                                        value, value_len);
337
 
              string_space_act += value_len;
338
 
 
339
 
              ++nmap;
340
 
              ++added;
341
 
            }
342
 
        }
343
 
    }
344
 
 
345
 
  /* Should we test for ferror()?  I think we have to silently ignore
346
 
     errors.  --drepper  */
347
 
  fclose (fp);
348
 
 
349
 
  if (added > 0)
350
 
    qsort (map, nmap, sizeof (struct alias_map),
351
 
           (int (*) PARAMS ((const void *, const void *))) alias_compare);
352
 
 
353
 
  return added;
354
 
}
355
 
 
356
 
 
357
 
static int
358
 
extend_alias_table ()
359
 
{
360
 
  size_t new_size;
361
 
  struct alias_map *new_map;
362
 
 
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;
369
 
 
370
 
  map = new_map;
371
 
  maxmap = new_size;
372
 
  return 0;
373
 
}
374
 
 
375
 
 
376
 
#ifdef _LIBC
377
 
static void __attribute__ ((unused))
378
 
free_mem (void)
379
 
{
380
 
  if (string_space != NULL)
381
 
    free (string_space);
382
 
  if (map != NULL)
383
 
    free (map);
384
 
}
385
 
text_set_element (__libc_subfreeres, free_mem);
386
 
#endif
387
 
 
388
 
 
389
 
static int
390
 
alias_compare (map1, map2)
391
 
     const struct alias_map *map1;
392
 
     const struct alias_map *map2;
393
 
{
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;
400
 
 
401
 
  if (p1 == p2)
402
 
    return 0;
403
 
 
404
 
  do
405
 
    {
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;
414
 
    }
415
 
  while (c1 == c2);
416
 
 
417
 
  return c1 - c2;
418
 
#endif
419
 
}