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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-newlib/] [newlib-1.17.0/] [newlib/] [libc/] [sys/] [linux/] [iconv/] [gconv_db.c] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 jlechner
/* Provide access to the collection of available transformation modules.
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 <limits.h>
22
#include <search.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <sys/param.h>
26
#include <dirent.h>
27
 
28
#include <dlfcn.h>
29
#include <gconv_int.h>
30
#include <gconv_charset.h>
31
 
32
 
33
/* Simple data structure for alias mapping.  We have two names, `from'
34
   and `to'.  */
35
void *__gconv_alias_db;
36
 
37
/* Array with available modules.  */
38
struct gconv_module *__gconv_modules_db;
39
 
40
/* We modify global data.   */
41
__LOCK_INIT(static, lock);
42
 
43
 
44
/* Function for searching alias.  */
45
int
46
__gconv_alias_compare (const void *p1, const void *p2)
47
{
48
  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
49
  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
50
  return strcmp (s1->fromname, s2->fromname);
51
}
52
 
53
 
54
/* To search for a derivation we create a list of intermediate steps.
55
   Each element contains a pointer to the element which precedes it
56
   in the derivation order.  */
57
struct derivation_step
58
{
59
  const char *result_set;
60
  size_t result_set_len;
61
  int cost_lo;
62
  int cost_hi;
63
  struct gconv_module *code;
64
  struct derivation_step *last;
65
  struct derivation_step *next;
66
};
67
 
68
#define NEW_STEP(result, hi, lo, module, last_mod) \
69
  ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
70
     newp->result_set = result;                                               \
71
     newp->result_set_len = strlen (result);                                  \
72
     newp->cost_hi = hi;                                                      \
73
     newp->cost_lo = lo;                                                      \
74
     newp->code = module;                                                     \
75
     newp->last = last_mod;                                                   \
76
     newp->next = NULL;                                                       \
77
     newp; })
78
 
79
 
80
/* If a specific transformation is used more than once we should not need
81
   to start looking for it again.  Instead cache each successful result.  */
82
struct known_derivation
83
{
84
  const char *from;
85
  const char *to;
86
  struct __gconv_step *steps;
87
  size_t nsteps;
88
};
89
 
90
/* Compare function for database of found derivations.  */
91
static int
92
derivation_compare (const void *p1, const void *p2)
93
{
94
  const struct known_derivation *s1 = (const struct known_derivation *) p1;
95
  const struct known_derivation *s2 = (const struct known_derivation *) p2;
96
  int result;
97
 
98
  result = strcmp (s1->from, s2->from);
99
  if (result == 0)
100
    result = strcmp (s1->to, s2->to);
101
  return result;
102
}
103
 
104
/* The search tree for known derivations.  */
105
static void *known_derivations;
106
 
107
/* Look up whether given transformation was already requested before.  */
108
static int
109
internal_function
110
derivation_lookup (const char *fromset, const char *toset,
111
                   struct __gconv_step **handle, size_t *nsteps)
112
{
113
  struct known_derivation key = { fromset, toset, NULL, 0 };
114
  struct known_derivation **result;
115
 
116
  result = tfind (&key, &known_derivations, derivation_compare);
117
 
118
  if (result == NULL)
119
    return __GCONV_NOCONV;
120
 
121
  *handle = (*result)->steps;
122
  *nsteps = (*result)->nsteps;
123
 
124
  /* Please note that we return GCONV_OK even if the last search for
125
     this transformation was unsuccessful.  */
126
  return __GCONV_OK;
127
}
128
 
129
/* Add new derivation to list of known ones.  */
130
static void
131
internal_function
132
add_derivation (const char *fromset, const char *toset,
133
                struct __gconv_step *handle, size_t nsteps)
134
{
135
  struct known_derivation *new_deriv;
136
  size_t fromset_len = strlen (fromset) + 1;
137
  size_t toset_len = strlen (toset) + 1;
138
 
139
  new_deriv = (struct known_derivation *)
140
    malloc (sizeof (struct known_derivation) + fromset_len + toset_len);
141
  if (new_deriv != NULL)
142
    {
143
      char *tmp;
144
      new_deriv->from = (char *) (new_deriv + 1);
145
      tmp = memcpy (new_deriv + 1, fromset, fromset_len);
146
      tmp += fromset_len;
147
 
148
      new_deriv->to = memcpy (tmp,
149
                              toset, toset_len);
150
 
151
      new_deriv->steps = handle;
152
      new_deriv->nsteps = nsteps;
153
 
154
      if (tsearch (new_deriv, &known_derivations, derivation_compare)
155
          == NULL)
156
        /* There is some kind of memory allocation problem.  */
157
        free (new_deriv);
158
    }
159
  /* Please note that we don't complain if the allocation failed.  This
160
     is not tragically but in case we use the memory debugging facilities
161
     not all memory will be freed.  */
162
}
163
 
164
static void
165
free_derivation (void *p)
166
{
167
  struct known_derivation *deriv = (struct known_derivation *) p;
168
  size_t cnt;
169
 
170
  for (cnt = 0; cnt < deriv->nsteps; ++cnt)
171
    if (deriv->steps[cnt].__counter > 0
172
        && deriv->steps[cnt].__end_fct != NULL)
173
      deriv->steps[cnt].__end_fct (&deriv->steps[cnt]);
174
 
175
  /* Free the name strings.  */
176
  free ((char *) deriv->steps[0].__from_name);
177
  free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);
178
 
179
  free ((struct __gconv_step *) deriv->steps);
180
  free (deriv);
181
}
182
 
183
 
184
/* Decrement the reference count for a single step in a steps array.  */
185
void
186
internal_function
187
__gconv_release_step (struct __gconv_step *step)
188
{
189
  if (--step->__counter == 0)
190
    {
191
      /* Call the destructor.  */
192
      if (step->__end_fct != NULL)
193
        step->__end_fct (step);
194
 
195
#ifndef STATIC_GCONV
196
      /* Skip builtin modules; they are not reference counted.  */
197
      if (step->__shlib_handle != NULL)
198
        {
199
          /* Release the loaded module.  */
200
          __gconv_release_shlib (step->__shlib_handle);
201
          step->__shlib_handle = NULL;
202
        }
203
#endif
204
    }
205
}
206
 
207
static int
208
internal_function
209
gen_steps (struct derivation_step *best, const char *toset,
210
           const char *fromset, struct __gconv_step **handle, size_t *nsteps)
211
{
212
  size_t step_cnt = 0;
213
  struct __gconv_step *result;
214
  struct derivation_step *current;
215
  int status = __GCONV_NOMEM;
216
 
217
  /* First determine number of steps.  */
218
  for (current = best; current->last != NULL; current = current->last)
219
    ++step_cnt;
220
 
221
  result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)
222
                                           * step_cnt);
223
  if (result != NULL)
224
    {
225
      int failed = 0;
226
 
227
      status = __GCONV_OK;
228
      *nsteps = step_cnt;
229
      current = best;
230
      while (step_cnt-- > 0)
231
        {
232
          result[step_cnt].__from_name = (step_cnt == 0
233
                                          ? strdup (fromset)
234
                                          : (char *)current->last->result_set);
235
          result[step_cnt].__to_name = (step_cnt + 1 == *nsteps
236
                                        ? strdup (current->result_set)
237
                                        : result[step_cnt + 1].__from_name);
238
 
239
          result[step_cnt].__counter = 1;
240
          result[step_cnt].__data = NULL;
241
 
242
#ifndef STATIC_GCONV
243
          if (current->code->module_name[0] == '/')
244
            {
245
              /* Load the module, return handle for it.  */
246
              struct __gconv_loaded_object *shlib_handle =
247
                __gconv_find_shlib (current->code->module_name);
248
 
249
              if (shlib_handle == NULL)
250
                {
251
                  failed = 1;
252
                  break;
253
                }
254
 
255
              result[step_cnt].__shlib_handle = shlib_handle;
256
              result[step_cnt].__modname = shlib_handle->name;
257
              result[step_cnt].__fct = shlib_handle->fct;
258
              result[step_cnt].__init_fct = shlib_handle->init_fct;
259
              result[step_cnt].__end_fct = shlib_handle->end_fct;
260
 
261
              /* Call the init function.  */
262
              if (result[step_cnt].__init_fct != NULL)
263
                {
264
                  status = result[step_cnt].__init_fct (&result[step_cnt]);
265
 
266
                  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
267
                    {
268
                      failed = 1;
269
                      /* Make sure we unload this modules.  */
270
                      --step_cnt;
271
                      result[step_cnt].__end_fct = NULL;
272
                      break;
273
                    }
274
                }
275
            }
276
          else
277
#endif
278
            /* It's a builtin transformation.  */
279
            __gconv_get_builtin_trans (current->code->module_name,
280
                                       &result[step_cnt]);
281
 
282
          current = current->last;
283
        }
284
 
285
      if (__builtin_expect (failed, 0) != 0)
286
        {
287
          /* Something went wrong while initializing the modules.  */
288
          while (++step_cnt < *nsteps)
289
            __gconv_release_step (&result[step_cnt]);
290
          free (result);
291
          *nsteps = 0;
292
          *handle = NULL;
293
          if (status == __GCONV_OK)
294
            status = __GCONV_NOCONV;
295
        }
296
      else
297
        *handle = result;
298
    }
299
  else
300
    {
301
      *nsteps = 0;
302
      *handle = NULL;
303
    }
304
 
305
  return status;
306
}
307
 
308
 
309
#ifndef STATIC_GCONV
310
static int
311
internal_function
312
increment_counter (struct __gconv_step *steps, size_t nsteps)
313
{
314
  /* Increment the user counter.  */
315
  size_t cnt = nsteps;
316
  int result = __GCONV_OK;
317
 
318
  while (cnt-- > 0)
319
    {
320
      struct __gconv_step *step = &steps[cnt];
321
 
322
      if (step->__counter++ == 0)
323
        {
324
          /* Skip builtin modules.  */
325
          if (step->__modname != NULL)
326
            {
327
              /* Reopen a previously used module.  */
328
              step->__shlib_handle = __gconv_find_shlib (step->__modname);
329
              if (step->__shlib_handle == NULL)
330
                {
331
                  /* Oops, this is the second time we use this module
332
                     (after unloading) and this time loading failed!?  */
333
                  --step->__counter;
334
                  while (++cnt < nsteps)
335
                    __gconv_release_step (&steps[cnt]);
336
                  result = __GCONV_NOCONV;
337
                  break;
338
                }
339
 
340
              /* The function addresses defined by the module may
341
                 have changed.  */
342
              step->__fct = step->__shlib_handle->fct;
343
              step->__init_fct = step->__shlib_handle->init_fct;
344
              step->__end_fct = step->__shlib_handle->end_fct;
345
            }
346
 
347
          if (step->__init_fct != NULL)
348
            step->__init_fct (step);
349
        }
350
    }
351
  return result;
352
}
353
#endif
354
 
355
 
356
/* The main function: find a possible derivation from the `fromset' (either
357
   the given name or the alias) to the `toset' (again with alias).  */
358
static int
359
internal_function
360
find_derivation (const char *toset, const char *toset_expand,
361
                 const char *fromset, const char *fromset_expand,
362
                 struct __gconv_step **handle, size_t *nsteps)
363
{
364
  struct derivation_step *first, *current, **lastp, *solution = NULL;
365
  int best_cost_hi = INT_MAX;
366
  int best_cost_lo = INT_MAX;
367
  int result;
368
 
369
  /* Look whether an earlier call to `find_derivation' has already
370
     computed a possible derivation.  If so, return it immediately.  */
371
  result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
372
                              handle, nsteps);
373
  if (result == __GCONV_OK)
374
    {
375
#ifndef STATIC_GCONV
376
      result = increment_counter (*handle, *nsteps);
377
#endif
378
      return result;
379
    }
380
 
381
  /* The task is to find a sequence of transformations, backed by the
382
     existing modules - whether builtin or dynamically loadable -,
383
     starting at `fromset' (or `fromset_expand') and ending at `toset'
384
     (or `toset_expand'), and with minimal cost.
385
 
386
     For computer scientists, this is a shortest path search in the
387
     graph where the nodes are all possible charsets and the edges are
388
     the transformations listed in __gconv_modules_db.
389
 
390
     For now we use a simple algorithm with quadratic runtime behaviour.
391
     A breadth-first search, starting at `fromset' and `fromset_expand'.
392
     The list starting at `first' contains all nodes that have been
393
     visited up to now, in the order in which they have been visited --
394
     excluding the goal nodes `toset' and `toset_expand' which get
395
     managed in the list starting at `solution'.
396
     `current' walks through the list starting at `first' and looks
397
     which nodes are reachable from the current node, adding them to
398
     the end of the list [`first' or `solution' respectively] (if
399
     they are visited the first time) or updating them in place (if
400
     they have have already been visited).
401
     In each node of either list, cost_lo and cost_hi contain the
402
     minimum cost over any paths found up to now, starting at `fromset'
403
     or `fromset_expand', ending at that node.  best_cost_lo and
404
     best_cost_hi represent the minimum over the elements of the
405
     `solution' list.  */
406
 
407
  if (fromset_expand != NULL)
408
    {
409
      first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
410
      first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
411
      lastp = &first->next->next;
412
    }
413
  else
414
    {
415
      first = NEW_STEP (fromset, 0, 0, NULL, NULL);
416
      lastp = &first->next;
417
    }
418
 
419
  for (current = first; current != NULL; current = current->next)
420
    {
421
      /* Now match all the available module specifications against the
422
         current charset name.  If any of them matches check whether
423
         we already have a derivation for this charset.  If yes, use the
424
         one with the lower costs.  Otherwise add the new charset at the
425
         end.
426
 
427
         The module database is organized in a tree form which allows
428
         searching for prefixes.  So we search for the first entry with a
429
         matching prefix and any other matching entry can be found from
430
         this place.  */
431
      struct gconv_module *node;
432
 
433
      /* Maybe it is not necessary anymore to look for a solution for
434
         this entry since the cost is already as high (or higher) as
435
         the cost for the best solution so far.  */
436
      if (current->cost_hi > best_cost_hi
437
          || (current->cost_hi == best_cost_hi
438
              && current->cost_lo >= best_cost_lo))
439
        continue;
440
 
441
      node = __gconv_modules_db;
442
      while (node != NULL)
443
        {
444
          int cmpres = strcmp (current->result_set, node->from_string);
445
          if (cmpres == 0)
446
            {
447
              /* Walk through the list of modules with this prefix and
448
                 try to match the name.  */
449
              struct gconv_module *runp;
450
 
451
              /* Check all the modules with this prefix.  */
452
              runp = node;
453
              do
454
                {
455
                  const char *result_set = (strcmp (runp->to_string, "-") == 0
456
                                            ? (toset_expand ?: toset)
457
                                            : runp->to_string);
458
                  int cost_hi = runp->cost_hi + current->cost_hi;
459
                  int cost_lo = runp->cost_lo + current->cost_lo;
460
                  struct derivation_step *step;
461
 
462
                  /* We managed to find a derivation.  First see whether
463
                     we have reached one of the goal nodes.  */
464
                  if (strcmp (result_set, toset) == 0
465
                      || (toset_expand != NULL
466
                          && strcmp (result_set, toset_expand) == 0))
467
                    {
468
                      /* Append to the `solution' list if there
469
                         is no entry with this name.  */
470
                      for (step = solution; step != NULL; step = step->next)
471
                        if (strcmp (result_set, step->result_set) == 0)
472
                          break;
473
 
474
                      if (step == NULL)
475
                        {
476
                          step = NEW_STEP (result_set,
477
                                           cost_hi, cost_lo,
478
                                           runp, current);
479
                          step->next = solution;
480
                          solution = step;
481
                        }
482
                      else if (step->cost_hi > cost_hi
483
                               || (step->cost_hi == cost_hi
484
                                   && step->cost_lo > cost_lo))
485
                        {
486
                          /* A better path was found for the node,
487
                             on the `solution' list.  */
488
                          step->code = runp;
489
                          step->last = current;
490
                          step->cost_hi = cost_hi;
491
                          step->cost_lo = cost_lo;
492
                        }
493
 
494
                      /* Update best_cost accordingly.  */
495
                      if (cost_hi < best_cost_hi
496
                          || (cost_hi == best_cost_hi
497
                              && cost_lo < best_cost_lo))
498
                        {
499
                          best_cost_hi = cost_hi;
500
                          best_cost_lo = cost_lo;
501
                        }
502
                    }
503
                  else if (cost_hi < best_cost_hi
504
                           || (cost_hi == best_cost_hi
505
                               && cost_lo < best_cost_lo))
506
                    {
507
                      /* Append at the end of the `first' list if there
508
                         is no entry with this name.  */
509
                      for (step = first; step != NULL; step = step->next)
510
                        if (strcmp (result_set, step->result_set) == 0)
511
                          break;
512
 
513
                      if (step == NULL)
514
                        {
515
                          *lastp = NEW_STEP (result_set,
516
                                             cost_hi, cost_lo,
517
                                             runp, current);
518
                          lastp = &(*lastp)->next;
519
                        }
520
                      else if (step->cost_hi > cost_hi
521
                               || (step->cost_hi == cost_hi
522
                                   && step->cost_lo > cost_lo))
523
                        {
524
                          /* A better path was found for the node,
525
                             on the `first' list.  */
526
                          step->code = runp;
527
                          step->last = current;
528
 
529
                          /* Update the cost for all steps.  */
530
                          for (step = first; step != NULL;
531
                               step = step->next)
532
                            /* But don't update the start nodes.  */
533
                            if (step->code != NULL)
534
                              {
535
                                struct derivation_step *back;
536
                                int hi, lo;
537
 
538
                                hi = step->code->cost_hi;
539
                                lo = step->code->cost_lo;
540
 
541
                                for (back = step->last; back->code != NULL;
542
                                     back = back->last)
543
                                  {
544
                                    hi += back->code->cost_hi;
545
                                    lo += back->code->cost_lo;
546
                                  }
547
 
548
                                step->cost_hi = hi;
549
                                step->cost_lo = lo;
550
                              }
551
 
552
                          /* Likewise for the nodes on the solution list.
553
                             Also update best_cost accordingly.  */
554
                          for (step = solution; step != NULL;
555
                               step = step->next)
556
                            {
557
                              step->cost_hi = (step->code->cost_hi
558
                                               + step->last->cost_hi);
559
                              step->cost_lo = (step->code->cost_lo
560
                                               + step->last->cost_lo);
561
 
562
                              if (step->cost_hi < best_cost_hi
563
                                  || (step->cost_hi == best_cost_hi
564
                                      && step->cost_lo < best_cost_lo))
565
                                {
566
                                  best_cost_hi = step->cost_hi;
567
                                  best_cost_lo = step->cost_lo;
568
                                }
569
                            }
570
                        }
571
                    }
572
 
573
                  runp = runp->same;
574
                }
575
              while (runp != NULL);
576
 
577
              break;
578
            }
579
          else if (cmpres < 0)
580
            node = node->left;
581
          else
582
            node = node->right;
583
        }
584
    }
585
 
586
  if (solution != NULL)
587
    {
588
      /* We really found a way to do the transformation.  */
589
 
590
      /* Choose the best solution.  This is easy because we know that
591
         the solution list has at most length 2 (one for every possible
592
         goal node).  */
593
      if (solution->next != NULL)
594
        {
595
          struct derivation_step *solution2 = solution->next;
596
 
597
          if (solution2->cost_hi < solution->cost_hi
598
              || (solution2->cost_hi == solution->cost_hi
599
                  && solution2->cost_lo < solution->cost_lo))
600
            solution = solution2;
601
        }
602
 
603
      /* Now build a data structure describing the transformation steps.  */
604
      result = gen_steps (solution, toset_expand ?: toset,
605
                          fromset_expand ?: fromset, handle, nsteps);
606
    }
607
  else
608
    {
609
      /* We haven't found a transformation.  Clear the result values.  */
610
      *handle = NULL;
611
      *nsteps = 0;
612
    }
613
 
614
  /* Add result in any case to list of known derivations.  */
615
  add_derivation (fromset_expand ?: fromset, toset_expand ?: toset,
616
                  *handle, *nsteps);
617
 
618
  return result;
619
}
620
 
621
 
622
/* Control of initialization.  */
623
__libc_once_define (static, once);
624
 
625
 
626
static const char *
627
do_lookup_alias (const char *name)
628
{
629
  struct gconv_alias key;
630
  struct gconv_alias **found;
631
 
632
  key.fromname = (char *) name;
633
  found = tfind (&key, &__gconv_alias_db, __gconv_alias_compare);
634
  return found != NULL ? (*found)->toname : NULL;
635
}
636
 
637
 
638
int
639
internal_function
640
__gconv_compare_alias (const char *name1, const char *name2)
641
{
642
  int result;
643
 
644
  /* Ensure that the configuration data is read.  */
645
  __libc_once (once, __gconv_read_conf);
646
 
647
  if (__gconv_compare_alias_cache (name1, name2, &result) != 0)
648
    result = strcmp (do_lookup_alias (name1) ?: name1,
649
                     do_lookup_alias (name2) ?: name2);
650
 
651
  return result;
652
}
653
 
654
 
655
int
656
internal_function
657
__gconv_find_transform (const char *toset, const char *fromset,
658
                        struct __gconv_step **handle, size_t *nsteps,
659
                        int flags)
660
{
661
  const char *fromset_expand;
662
  const char *toset_expand;
663
  int result;
664
 
665
  /* Ensure that the configuration data is read.  */
666
  __libc_once (once, __gconv_read_conf);
667
 
668
  /* Acquire the lock.  */
669
#ifdef HAVE_DD_LOCK
670
  __lock_acquire(lock);
671
#endif
672
 
673
  result = __gconv_lookup_cache (toset, fromset, handle, nsteps, flags);
674
  if (result != __GCONV_NODB)
675
    {
676
      /* We have a cache and could resolve the request, successful or not.  */
677
#ifdef HAVE_DD_LOCK
678
      __lock_release(lock);
679
#endif
680
 
681
      return result;
682
    }
683
 
684
  /* If we don't have a module database return with an error.  */
685
  if (__gconv_modules_db == NULL)
686
    {
687
#ifdef HAVE_DD_LOCK
688
  __lock_release(lock);
689
#endif
690
 
691
      return __GCONV_NOCONV;
692
    }
693
 
694
  /* See whether the names are aliases.  */
695
  fromset_expand = do_lookup_alias (fromset);
696
  toset_expand = do_lookup_alias (toset);
697
 
698
  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0)
699
      /* We are not supposed to create a pseudo transformation (means
700
         copying) when the input and output character set are the same.  */
701
      && (strcmp (toset, fromset) == 0
702
          || (toset_expand != NULL && strcmp (toset_expand, fromset) == 0)
703
          || (fromset_expand != NULL
704
              && (strcmp (toset, fromset_expand) == 0
705
                  || (toset_expand != NULL
706
                      && strcmp (toset_expand, fromset_expand) == 0)))))
707
    {
708
      /* Both character sets are the same.  */
709
#ifdef HAVE_DD_LOCK
710
  __lock_release(lock);
711
#endif
712
 
713
      return __GCONV_NOCONV;
714
    }
715
 
716
  result = find_derivation (toset, toset_expand, fromset, fromset_expand,
717
                            handle, nsteps);
718
 
719
  /* Release the lock.  */
720
#ifdef HAVE_DD_LOCK
721
  __lock_release(lock);
722
#endif
723
 
724
 
725
  /* The following code is necessary since `find_derivation' will return
726
     GCONV_OK even when no derivation was found but the same request
727
     was processed before.  I.e., negative results will also be cached.  */
728
  return (result == __GCONV_OK
729
          ? (*handle == NULL ? __GCONV_NOCONV : __GCONV_OK)
730
          : result);
731
}
732
 
733
 
734
/* Release the entries of the modules list.  */
735
int
736
internal_function
737
__gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
738
{
739
  int result = __GCONV_OK;
740
  size_t cnt;
741
 
742
  /* Acquire the lock.  */
743
#ifdef HAVE_DD_LOCK
744
  __lock_acquire(lock);
745
#endif
746
 
747
 
748
#ifndef STATIC_GCONV
749
  cnt = nsteps;
750
  while (cnt-- > 0)
751
    __gconv_release_step (&steps[cnt]);
752
#endif
753
 
754
  /* If we use the cache we free a bit more since we don't keep any
755
     transformation records around, they are cheap enough to
756
     recreate.  */
757
  __gconv_release_cache (steps, nsteps);
758
 
759
  /* Release the lock.  */
760
#ifdef HAVE_DD_LOCK
761
  __lock_release(lock);
762
#endif
763
 
764
 
765
  return result;
766
}
767
 
768
 
769
/* Free the modules mentioned.  */
770
static void
771
internal_function
772
free_modules_db (struct gconv_module *node)
773
{
774
  if (node->left != NULL)
775
    free_modules_db (node->left);
776
  if (node->right != NULL)
777
    free_modules_db (node->right);
778
  do
779
    {
780
      struct gconv_module *act = node;
781
      node = node->same;
782
      if (act->module_name[0] == '/')
783
        free (act);
784
    }
785
  while (node != NULL);
786
}
787
 
788
 
789
/* Free all resources if necessary.  */
790
static void __attribute__ ((unused))
791
free_mem (void)
792
{
793
  if (__gconv_alias_db != NULL)
794
    tdestroy (__gconv_alias_db, free);
795
 
796
  if (__gconv_modules_db != NULL)
797
    free_modules_db (__gconv_modules_db);
798
 
799
  if (known_derivations != NULL)
800
    tdestroy (known_derivations, free_derivation);
801
}
802
 
803
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.