OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [newlib-1.18.0/] [newlib/] [libc/] [sys/] [linux/] [iconv/] [gconv_conf.c] - Blame information for rev 207

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* Handle configuration data.
2
   Copyright (C) 1997,98,99,2000,2001 Free Software Foundation, Inc.
3
   This file is part of the GNU C Library.
4
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
 
6
   The GNU C Library is free software; you can redistribute it and/or
7
   modify it under the terms of the GNU Lesser General Public
8
   License as published by the Free Software Foundation; either
9
   version 2.1 of the License, or (at your option) any later version.
10
 
11
   The GNU C Library is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
   Lesser General Public License for more details.
15
 
16
   You should have received a copy of the GNU Lesser General Public
17
   License along with the GNU C Library; if not, write to the Free
18
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19
   02111-1307 USA.  */
20
 
21
#include <assert.h>
22
#include <ctype.h>
23
#include <errno.h>
24
#include <limits.h>
25
#include <locale.h>
26
#include <search.h>
27
#include <stddef.h>
28
#include <stdio.h>
29
#include <stdio_ext.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
#include <sys/param.h>
34
 
35
#include <dirent.h>
36
#include <gconv_int.h>
37
 
38
/* This is the default path where we look for module lists.  */
39
static const char default_gconv_path[] = GCONV_PATH;
40
 
41
/* The path elements, as determined by the __gconv_get_path function.
42
   All path elements end in a slash.  */
43
struct path_elem *__gconv_path_elem;
44
/* Maximum length of a single path element in __gconv_path_elem.  */
45
size_t __gconv_max_path_elem_len;
46
 
47
/* We use the following struct if we couldn't allocate memory.  */
48
static const struct path_elem empty_path_elem;
49
 
50
/* Name of the file containing the module information in the directories
51
   along the path.  */
52
static const char gconv_conf_filename[] = "gconv-modules";
53
 
54
/* Filename extension for the modules.  */
55
#ifndef MODULE_EXT
56
# define MODULE_EXT ".so"
57
#endif
58
static const char gconv_module_ext[] = MODULE_EXT;
59
 
60
/* We have a few builtin transformations.  */
61
static struct gconv_module builtin_modules[] =
62
{
63
#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \
64
                               MinT, MaxT) \
65
  {                                                                           \
66
    from_string: From,                                                        \
67
    to_string: To,                                                            \
68
    cost_hi: Cost,                                                            \
69
    cost_lo: INT_MAX,                                                         \
70
    module_name: Name                                                         \
71
  },
72
#define BUILTIN_ALIAS(From, To)
73
 
74
#include "gconv_builtin.h"
75
};
76
 
77
#undef BUILTIN_TRANSFORMATION
78
#undef BUILTIN_ALIAS
79
 
80
static const char *builtin_aliases[] =
81
{
82
#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \
83
                               MinT, MaxT)
84
#define BUILTIN_ALIAS(From, To) From " " To,
85
 
86
#include "gconv_builtin.h"
87
};
88
 
89
#ifdef USE_IN_LIBIO
90
# include <libio/libioP.h>
91
# define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)
92
#endif
93
 
94
 
95
/* Value of the GCONV_PATH environment variable.  */
96
const char *__gconv_path_envvar;
97
 
98
 
99
/* Test whether there is already a matching module known.  */
100
static int
101
internal_function
102
detect_conflict (const char *alias)
103
{
104
  struct gconv_module *node = __gconv_modules_db;
105
 
106
  while (node != NULL)
107
    {
108
      int cmpres = strcmp (alias, node->from_string);
109
 
110
      if (cmpres == 0)
111
        /* We have a conflict.  */
112
        return 1;
113
      else if (cmpres < 0)
114
        node = node->left;
115
      else
116
        node = node->right;
117
    }
118
 
119
  return node != NULL;
120
}
121
 
122
 
123
/* Add new alias.  */
124
static inline void
125
add_alias (char *rp, void *modules)
126
{
127
  /* We now expect two more string.  The strings are normalized
128
     (converted to UPPER case) and strored in the alias database.  */
129
  struct gconv_alias *new_alias;
130
  char *from, *to, *wp;
131
  char old_locale[20], *old_locale_p;
132
 
133
  /* Set locale to default C locale. */
134
  old_locale_p = setlocale(LC_ALL, "C");
135
  strncpy(old_locale, old_locale_p, 20);
136
 
137
  while (isspace (*rp))
138
    ++rp;
139
  from = wp = rp;
140
  while (*rp != '\0' && !isspace (*rp))
141
    *wp++ = toupper (*rp++);
142
  if (*rp == '\0')
143
    {
144
      setlocale(LC_ALL, old_locale);
145
      /* There is no `to' string on the line.  Ignore it.  */
146
      return;
147
    }
148
  *wp++ = '\0';
149
  to = ++rp;
150
  while (isspace (*rp))
151
    ++rp;
152
  while (*rp != '\0' && !isspace (*rp))
153
    *wp++ = toupper (*rp++);
154
  if (to == wp)
155
    {
156
      setlocale(LC_ALL, old_locale);
157
      /* No `to' string, ignore the line.  */
158
      return;
159
    }
160
  *wp++ = '\0';
161
 
162
  /* Test whether this alias conflicts with any available module.  */
163
  if (detect_conflict (from))
164
    {
165
      setlocale(LC_ALL, old_locale);
166
      /* It does conflict, don't add the alias.  */
167
      return;
168
    }
169
 
170
  new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from));
171
  if (new_alias != NULL)
172
    {
173
      void **inserted;
174
 
175
      new_alias->fromname = memcpy ((char *) new_alias
176
                                    + sizeof (struct gconv_alias),
177
                                    from, wp - from);
178
      new_alias->toname = new_alias->fromname + (to - from);
179
 
180
      inserted = (void **) tsearch (new_alias, &__gconv_alias_db,
181
                                      __gconv_alias_compare);
182
      if (inserted == NULL || *inserted != new_alias)
183
        /* Something went wrong, free this entry.  */
184
        free (new_alias);
185
    }
186
  setlocale(LC_ALL, old_locale);
187
}
188
 
189
 
190
/* Insert a data structure for a new module in the search tree.  */
191
static inline void
192
internal_function
193
insert_module (struct gconv_module *newp, int tobefreed)
194
{
195
  struct gconv_module **rootp = &__gconv_modules_db;
196
 
197
  while (*rootp != NULL)
198
    {
199
      struct gconv_module *root = *rootp;
200
      int cmpres;
201
 
202
      cmpres = strcmp (newp->from_string, root->from_string);
203
      if (cmpres == 0)
204
        {
205
          /* Both strings are identical.  Insert the string at the
206
             end of the `same' list if it is not already there.  */
207
          while (strcmp (newp->from_string, root->from_string) != 0
208
                 || strcmp (newp->to_string, root->to_string) != 0)
209
            {
210
              rootp = &root->same;
211
              root = *rootp;
212
              if (root == NULL)
213
                break;
214
            }
215
 
216
          if (root != NULL)
217
            {
218
              /* This is a no new conversion.  But maybe the cost is
219
                 better.  */
220
              if (newp->cost_hi < root->cost_hi
221
                  || (newp->cost_hi == root->cost_hi
222
                      && newp->cost_lo < root->cost_lo))
223
                {
224
                  newp->left = root->left;
225
                  newp->right = root->right;
226
                  newp->same = root->same;
227
                  *rootp = newp;
228
 
229
                  free (root);
230
                }
231
              else if (tobefreed)
232
                free (newp);
233
              return;
234
            }
235
 
236
          break;
237
        }
238
      else if (cmpres < 0)
239
        rootp = &root->left;
240
      else
241
        rootp = &root->right;
242
    }
243
 
244
  /* Plug in the new node here.  */
245
  *rootp = newp;
246
}
247
 
248
 
249
/* Add new module.  */
250
static void
251
internal_function
252
add_module (char *rp, const char *directory, size_t dir_len, void **modules,
253
            size_t *nmodules, int modcounter)
254
{
255
  /* We expect now
256
     1. `from' name
257
     2. `to' name
258
     3. filename of the module
259
     4. an optional cost value
260
  */
261
  struct gconv_alias fake_alias;
262
  struct gconv_module *new_module;
263
  char *from, *to, *module, *wp;
264
  int need_ext;
265
  int cost_hi;
266
  char old_locale[20], *old_locale_p;
267
  char *old;
268
  size_t len;
269
  char *new;
270
 
271
  /* Set locale to default C locale. */
272
  old_locale_p = setlocale(LC_ALL, "C");
273
  strncpy(old_locale, old_locale_p, 20);
274
 
275
  while (isspace (*rp))
276
    ++rp;
277
  from = rp;
278
  while (*rp != '\0' && !isspace (*rp))
279
    {
280
      *rp = toupper (*rp);
281
      ++rp;
282
    }
283
  if (*rp == '\0')
284
    {
285
      setlocale(LC_ALL, old_locale);
286
      return;
287
    }
288
  *rp++ = '\0';
289
  to = wp = rp;
290
  while (isspace (*rp))
291
    {
292
      setlocale(LC_ALL, old_locale);
293
      ++rp;
294
    }
295
  while (*rp != '\0' && !isspace (*rp))
296
    *wp++ = toupper (*rp++);
297
  if (*rp == '\0')
298
    {
299
      setlocale(LC_ALL, old_locale);
300
      return;
301
    }
302
  *wp++ = '\0';
303
  do
304
    ++rp;
305
  while (isspace (*rp));
306
  module = wp;
307
  while (*rp != '\0' && !isspace (*rp))
308
    *wp++ = *rp++;
309
  if (*rp == '\0')
310
    {
311
      /* There is no cost, use one by default.  */
312
      *wp++ = '\0';
313
      cost_hi = 1;
314
    }
315
  else
316
    {
317
      /* There might be a cost value.  */
318
      char *endp;
319
 
320
      *wp++ = '\0';
321
      cost_hi = strtol (rp, &endp, 10);
322
      if (rp == endp || cost_hi < 1)
323
        /* No useful information.  */
324
        cost_hi = 1;
325
    }
326
 
327
  if (module[0] == '\0')
328
    {
329
      setlocale(LC_ALL, old_locale);
330
      /* No module name given.  */
331
      return;
332
    }
333
  if (module[0] == '/')
334
    dir_len = 0;
335
 
336
  /* See whether we must add the ending.  */
337
  need_ext = 0;
338
  if (wp - module < (ptrdiff_t) sizeof (gconv_module_ext)
339
      || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext,
340
                 sizeof (gconv_module_ext)) != 0)
341
    /* We must add the module extension.  */
342
    need_ext = sizeof (gconv_module_ext) - 1;
343
 
344
  /* See whether we have already an alias with this name defined.  */
345
  old = from;
346
  len = strnlen (old, to - from);
347
  new = (char *) alloca (len + 1);
348
  new[len] = '\0';
349
  fake_alias.fromname = (char *) memcpy (new, old, len);
350
 
351
  if (tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare) != NULL)
352
    {
353
      setlocale(LC_ALL, old_locale);
354
      /* This module duplicates an alias.  */
355
      return;
356
    }
357
 
358
  new_module = (struct gconv_module *) calloc (1,
359
                                               sizeof (struct gconv_module)
360
                                               + (wp - from)
361
                                               + dir_len + need_ext);
362
  if (new_module != NULL)
363
    {
364
      char *tmp;
365
 
366
      new_module->from_string = tmp = (char *) (new_module + 1);
367
      tmp = memcpy (tmp, from, to - from);
368
      tmp += (to - from);
369
 
370
      new_module->to_string = tmp;
371
      tmp = memcpy (tmp, to, module - to);
372
      tmp += (module - to);
373
 
374
      new_module->cost_hi = cost_hi;
375
      new_module->cost_lo = modcounter;
376
 
377
      new_module->module_name = tmp;
378
 
379
      if (dir_len != 0)
380
        {
381
          tmp = memcpy (tmp, directory, dir_len);
382
          tmp += dir_len;
383
        }
384
 
385
      tmp = memcpy (tmp, module, wp - module);
386
      tmp += (wp - module);
387
 
388
      if (need_ext)
389
        memcpy (tmp - 1, gconv_module_ext, sizeof (gconv_module_ext));
390
 
391
      /* Now insert the new module data structure in our search tree.  */
392
      insert_module (new_module, 1);
393
    }
394
  setlocale(LC_ALL, old_locale);
395
}
396
 
397
 
398
/* Read the next configuration file.  */
399
static void
400
internal_function
401
read_conf_file (const char *filename, const char *directory, size_t dir_len,
402
                void **modules, size_t *nmodules)
403
{
404
  FILE *fp = fopen (filename, "r");
405
  char *line = NULL;
406
  size_t line_len = 0;
407
  static int modcounter;
408
  char old_locale[20], *old_locale_p;
409
 
410
  /* Don't complain if a file is not present or readable, simply silently
411
     ignore it.  */
412
  if (fp == NULL)
413
    return;
414
 
415
  /* Set locale to default C locale. */
416
  old_locale_p = setlocale(LC_ALL, "C");
417
  strncpy(old_locale, old_locale_p, 20);
418
 
419
  /* Process the known entries of the file.  Comments start with `#' and
420
     end with the end of the line.  Empty lines are ignored.  */
421
  while (!feof (fp))
422
    {
423
      char *rp, *endp, *word;
424
      ssize_t n = __getdelim (&line, &line_len, '\n', fp);
425
      if (n < 0)
426
        /* An error occurred.  */
427
        break;
428
 
429
      rp = line;
430
      /* Terminate the line (excluding comments or newline) by an NUL byte
431
         to simplify the following code.  */
432
      endp = strchr (rp, '#');
433
      if (endp != NULL)
434
        *endp = '\0';
435
      else
436
        if (rp[n - 1] == '\n')
437
          rp[n - 1] = '\0';
438
 
439
      while (isspace (*rp))
440
        ++rp;
441
 
442
      /* If this is an empty line go on with the next one.  */
443
      if (rp == endp)
444
        continue;
445
 
446
      word = rp;
447
      while (*rp != '\0' && !isspace (*rp))
448
        ++rp;
449
 
450
      if (rp - word == sizeof ("alias") - 1
451
          && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
452
        add_alias (rp, *modules);
453
      else if (rp - word == sizeof ("module") - 1
454
               && memcmp (word, "module", sizeof ("module") - 1) == 0)
455
        add_module (rp, directory, dir_len, modules, nmodules, modcounter++);
456
      /* else */
457
        /* Otherwise ignore the line.  */
458
    }
459
 
460
  free (line);
461
 
462
  fclose (fp);
463
 
464
  setlocale(LC_ALL, old_locale);
465
}
466
 
467
 
468
/* Determine the directories we are looking for data in.  */
469
void
470
__gconv_get_path (void)
471
{
472
  struct path_elem *result;
473
  __LOCK_INIT(static, path_lock);
474
 
475
#ifdef HAVE_DD_LOCK
476
  __lock_acquire(path_lock);
477
#endif
478
 
479
  /* Make sure there wasn't a second thread doing it already.  */
480
  result = (struct path_elem *) __gconv_path_elem;
481
  if (result == NULL)
482
    {
483
      /* Determine the complete path first.  */
484
      char *gconv_path;
485
      size_t gconv_path_len;
486
      char *elem;
487
      char *oldp;
488
      char *cp;
489
      int nelems;
490
      char *cwd;
491
      size_t cwdlen;
492
 
493
      if (__gconv_path_envvar == NULL)
494
        {
495
          char * old = default_gconv_path;
496
          size_t len = strlen (old) + 1;
497
          char *new = (char *) alloca (len);
498
 
499
          /* No user-defined path.  Make a modifiable copy of the
500
             default path.  */
501
          gconv_path = (char *) memcpy (new, old, len);
502
          gconv_path_len = sizeof (default_gconv_path);
503
          cwd = NULL;
504
          cwdlen = 0;
505
        }
506
      else
507
        {
508
          /* Append the default path to the user-defined path.  */
509
          size_t user_len = strlen (__gconv_path_envvar);
510
          char *tmp;
511
 
512
          gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
513
          gconv_path = alloca (gconv_path_len);
514
          tmp = memcpy (gconv_path, __gconv_path_envvar,
515
                        user_len);
516
          tmp += user_len;
517
          memcpy (tmp, ":", 1);
518
          tmp += 1;
519
          memcpy (tmp,
520
                  default_gconv_path, sizeof (default_gconv_path));
521
 
522
          cwd = getcwd (NULL, 0);
523
          cwdlen = strlen (cwd);
524
        }
525
      assert (default_gconv_path[0] == '/');
526
 
527
      /* In a first pass we calculate the number of elements.  */
528
      oldp = NULL;
529
      cp = strchr (gconv_path, ':');
530
      nelems = 1;
531
      while (cp != NULL)
532
        {
533
          if (cp != oldp + 1)
534
            ++nelems;
535
          oldp = cp;
536
          cp =  strchr (cp + 1, ':');
537
        }
538
 
539
      /* Allocate the memory for the result.  */
540
      result = (struct path_elem *) malloc ((nelems + 1)
541
                                            * sizeof (struct path_elem)
542
                                            + gconv_path_len + nelems
543
                                            + (nelems - 1) * (cwdlen + 1));
544
      if (result != NULL)
545
        {
546
          char *strspace = (char *) &result[nelems + 1];
547
          int n = 0;
548
 
549
          /* Separate the individual parts.  */
550
          __gconv_max_path_elem_len = 0;
551
          elem = strtok_r (gconv_path, ":", &gconv_path);
552
          assert (elem != NULL);
553
          do
554
            {
555
              result[n].name = strspace;
556
              if (elem[0] != '/')
557
                {
558
                  assert (cwd != NULL);
559
                  strspace = memcpy (strspace, cwd, cwdlen);
560
                  strspace += cwdlen;
561
                  *strspace++ = '/';
562
                }
563
              strspace = strcpy (strspace, elem);
564
              while(*strspace != '\0') strspace++;
565
 
566
              if (strspace[-1] != '/')
567
                *strspace++ = '/';
568
 
569
              result[n].len = strspace - result[n].name;
570
              if (result[n].len > __gconv_max_path_elem_len)
571
                __gconv_max_path_elem_len = result[n].len;
572
 
573
              *strspace++ = '\0';
574
              ++n;
575
            }
576
          while ((elem = strtok_r (NULL, ":", &gconv_path)) != NULL);
577
 
578
          result[n].name = NULL;
579
          result[n].len = 0;
580
        }
581
 
582
      __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;
583
 
584
      if (cwd != NULL)
585
        free (cwd);
586
    }
587
 
588
#ifdef HAVE_DD_LOCK
589
  __lock_release(path_lock);
590
#endif
591
}
592
 
593
 
594
/* Read all configuration files found in the user-specified and the default
595
   path.  */
596
void
597
__gconv_read_conf (void)
598
{
599
  void *modules = NULL;
600
  size_t nmodules = 0;
601
  int save_errno = errno;
602
  size_t cnt;
603
  char *filename;
604
  char *tmp;
605
  const char *elem;
606
  size_t elem_len;
607
 
608
  /* First see whether we should use the cache.  */
609
  if (__gconv_load_cache () == 0)
610
    {
611
      /* Yes, we are done.  */
612
      __set_errno (save_errno);
613
      return;
614
    }
615
 
616
#ifndef STATIC_GCONV
617
  /* Find out where we have to look.  */
618
  if (__gconv_path_elem == NULL)
619
    __gconv_get_path ();
620
 
621
  for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
622
    {
623
      elem = __gconv_path_elem[cnt].name;
624
      elem_len = __gconv_path_elem[cnt].len;
625
 
626
      /* No slash needs to be inserted between elem and gconv_conf_filename;
627
         elem already ends in a slash.  */
628
      filename = alloca (elem_len + sizeof (gconv_conf_filename));
629
      tmp = memcpy (filename, elem, elem_len);
630
      tmp += elem_len;
631
      memcpy (tmp, gconv_conf_filename, sizeof (gconv_conf_filename));
632
 
633
      /* Read the next configuration file.  */
634
      read_conf_file (filename, elem, elem_len, &modules, &nmodules);
635
    }
636
#endif
637
 
638
  /* Add the internal modules.  */
639
  for (cnt = 0; cnt < sizeof (builtin_modules) / sizeof (builtin_modules[0]);
640
       ++cnt)
641
    {
642
      struct gconv_alias fake_alias;
643
 
644
      fake_alias.fromname = (char *) builtin_modules[cnt].from_string;
645
 
646
      if (tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare)
647
          != NULL)
648
        /* It'll conflict so don't add it.  */
649
        continue;
650
 
651
      insert_module (&builtin_modules[cnt], 0);
652
    }
653
 
654
  /* Add aliases for builtin conversions.  */
655
  cnt = sizeof (builtin_aliases) / sizeof (builtin_aliases[0]);
656
  while (cnt > 0)
657
    {
658
      char * old = builtin_aliases[--cnt];
659
      size_t len = strlen (old) + 1;
660
      char *new = (char *) alloca (len);
661
      char *copy = (char *) memcpy (new, old, len);
662
 
663
      add_alias (copy, modules);
664
    }
665
 
666
  /* Restore the error number.  */
667
  __set_errno (save_errno);
668
}
669
 
670
 
671
 
672
/* Free all resources if necessary.  */
673
static void __attribute__ ((unused))
674
free_mem (void)
675
{
676
  if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem)
677
    free ((void *) __gconv_path_elem);
678
}
679
 
680
text_set_element (__libc_subfreeres, free_mem);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.