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

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [newlib-1.18.0/] [newlib-1.18.0-or32-1.0rc2/] [newlib/] [libc/] [sys/] [linux/] [iconv/] [gconv_db.c] - Diff between revs 207 and 520

Only display areas with differences | Details | Blame | View Log

Rev 207 Rev 520
/* Provide access to the collection of available transformation modules.
/* Provide access to the collection of available transformation modules.
   Copyright (C) 1997,98,99,2000,2001 Free Software Foundation, Inc.
   Copyright (C) 1997,98,99,2000,2001 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   This file is part of the GNU C Library.
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
 
   The GNU C Library is free software; you can redistribute it and/or
   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
   version 2.1 of the License, or (at your option) any later version.
 
 
   The GNU C Library is distributed in the hope that it will be useful,
   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
   Lesser General Public License for more details.
 
 
   You should have received a copy of the GNU Lesser General Public
   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */
   02111-1307 USA.  */
 
 
#include <limits.h>
#include <limits.h>
#include <search.h>
#include <search.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <sys/param.h>
#include <sys/param.h>
#include <dirent.h>
#include <dirent.h>
 
 
#include <dlfcn.h>
#include <dlfcn.h>
#include <gconv_int.h>
#include <gconv_int.h>
#include <gconv_charset.h>
#include <gconv_charset.h>
 
 
 
 
/* Simple data structure for alias mapping.  We have two names, `from'
/* Simple data structure for alias mapping.  We have two names, `from'
   and `to'.  */
   and `to'.  */
void *__gconv_alias_db;
void *__gconv_alias_db;
 
 
/* Array with available modules.  */
/* Array with available modules.  */
struct gconv_module *__gconv_modules_db;
struct gconv_module *__gconv_modules_db;
 
 
/* We modify global data.   */
/* We modify global data.   */
__LOCK_INIT(static, lock);
__LOCK_INIT(static, lock);
 
 
 
 
/* Function for searching alias.  */
/* Function for searching alias.  */
int
int
__gconv_alias_compare (const void *p1, const void *p2)
__gconv_alias_compare (const void *p1, const void *p2)
{
{
  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
  return strcmp (s1->fromname, s2->fromname);
  return strcmp (s1->fromname, s2->fromname);
}
}
 
 
 
 
/* To search for a derivation we create a list of intermediate steps.
/* To search for a derivation we create a list of intermediate steps.
   Each element contains a pointer to the element which precedes it
   Each element contains a pointer to the element which precedes it
   in the derivation order.  */
   in the derivation order.  */
struct derivation_step
struct derivation_step
{
{
  const char *result_set;
  const char *result_set;
  size_t result_set_len;
  size_t result_set_len;
  int cost_lo;
  int cost_lo;
  int cost_hi;
  int cost_hi;
  struct gconv_module *code;
  struct gconv_module *code;
  struct derivation_step *last;
  struct derivation_step *last;
  struct derivation_step *next;
  struct derivation_step *next;
};
};
 
 
#define NEW_STEP(result, hi, lo, module, last_mod) \
#define NEW_STEP(result, hi, lo, module, last_mod) \
  ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
  ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
     newp->result_set = result;                                               \
     newp->result_set = result;                                               \
     newp->result_set_len = strlen (result);                                  \
     newp->result_set_len = strlen (result);                                  \
     newp->cost_hi = hi;                                                      \
     newp->cost_hi = hi;                                                      \
     newp->cost_lo = lo;                                                      \
     newp->cost_lo = lo;                                                      \
     newp->code = module;                                                     \
     newp->code = module;                                                     \
     newp->last = last_mod;                                                   \
     newp->last = last_mod;                                                   \
     newp->next = NULL;                                                       \
     newp->next = NULL;                                                       \
     newp; })
     newp; })
 
 
 
 
/* If a specific transformation is used more than once we should not need
/* If a specific transformation is used more than once we should not need
   to start looking for it again.  Instead cache each successful result.  */
   to start looking for it again.  Instead cache each successful result.  */
struct known_derivation
struct known_derivation
{
{
  const char *from;
  const char *from;
  const char *to;
  const char *to;
  struct __gconv_step *steps;
  struct __gconv_step *steps;
  size_t nsteps;
  size_t nsteps;
};
};
 
 
/* Compare function for database of found derivations.  */
/* Compare function for database of found derivations.  */
static int
static int
derivation_compare (const void *p1, const void *p2)
derivation_compare (const void *p1, const void *p2)
{
{
  const struct known_derivation *s1 = (const struct known_derivation *) p1;
  const struct known_derivation *s1 = (const struct known_derivation *) p1;
  const struct known_derivation *s2 = (const struct known_derivation *) p2;
  const struct known_derivation *s2 = (const struct known_derivation *) p2;
  int result;
  int result;
 
 
  result = strcmp (s1->from, s2->from);
  result = strcmp (s1->from, s2->from);
  if (result == 0)
  if (result == 0)
    result = strcmp (s1->to, s2->to);
    result = strcmp (s1->to, s2->to);
  return result;
  return result;
}
}
 
 
/* The search tree for known derivations.  */
/* The search tree for known derivations.  */
static void *known_derivations;
static void *known_derivations;
 
 
/* Look up whether given transformation was already requested before.  */
/* Look up whether given transformation was already requested before.  */
static int
static int
internal_function
internal_function
derivation_lookup (const char *fromset, const char *toset,
derivation_lookup (const char *fromset, const char *toset,
                   struct __gconv_step **handle, size_t *nsteps)
                   struct __gconv_step **handle, size_t *nsteps)
{
{
  struct known_derivation key = { fromset, toset, NULL, 0 };
  struct known_derivation key = { fromset, toset, NULL, 0 };
  struct known_derivation **result;
  struct known_derivation **result;
 
 
  result = tfind (&key, &known_derivations, derivation_compare);
  result = tfind (&key, &known_derivations, derivation_compare);
 
 
  if (result == NULL)
  if (result == NULL)
    return __GCONV_NOCONV;
    return __GCONV_NOCONV;
 
 
  *handle = (*result)->steps;
  *handle = (*result)->steps;
  *nsteps = (*result)->nsteps;
  *nsteps = (*result)->nsteps;
 
 
  /* Please note that we return GCONV_OK even if the last search for
  /* Please note that we return GCONV_OK even if the last search for
     this transformation was unsuccessful.  */
     this transformation was unsuccessful.  */
  return __GCONV_OK;
  return __GCONV_OK;
}
}
 
 
/* Add new derivation to list of known ones.  */
/* Add new derivation to list of known ones.  */
static void
static void
internal_function
internal_function
add_derivation (const char *fromset, const char *toset,
add_derivation (const char *fromset, const char *toset,
                struct __gconv_step *handle, size_t nsteps)
                struct __gconv_step *handle, size_t nsteps)
{
{
  struct known_derivation *new_deriv;
  struct known_derivation *new_deriv;
  size_t fromset_len = strlen (fromset) + 1;
  size_t fromset_len = strlen (fromset) + 1;
  size_t toset_len = strlen (toset) + 1;
  size_t toset_len = strlen (toset) + 1;
 
 
  new_deriv = (struct known_derivation *)
  new_deriv = (struct known_derivation *)
    malloc (sizeof (struct known_derivation) + fromset_len + toset_len);
    malloc (sizeof (struct known_derivation) + fromset_len + toset_len);
  if (new_deriv != NULL)
  if (new_deriv != NULL)
    {
    {
      char *tmp;
      char *tmp;
      new_deriv->from = (char *) (new_deriv + 1);
      new_deriv->from = (char *) (new_deriv + 1);
      tmp = memcpy (new_deriv + 1, fromset, fromset_len);
      tmp = memcpy (new_deriv + 1, fromset, fromset_len);
      tmp += fromset_len;
      tmp += fromset_len;
 
 
      new_deriv->to = memcpy (tmp,
      new_deriv->to = memcpy (tmp,
                              toset, toset_len);
                              toset, toset_len);
 
 
      new_deriv->steps = handle;
      new_deriv->steps = handle;
      new_deriv->nsteps = nsteps;
      new_deriv->nsteps = nsteps;
 
 
      if (tsearch (new_deriv, &known_derivations, derivation_compare)
      if (tsearch (new_deriv, &known_derivations, derivation_compare)
          == NULL)
          == NULL)
        /* There is some kind of memory allocation problem.  */
        /* There is some kind of memory allocation problem.  */
        free (new_deriv);
        free (new_deriv);
    }
    }
  /* Please note that we don't complain if the allocation failed.  This
  /* Please note that we don't complain if the allocation failed.  This
     is not tragically but in case we use the memory debugging facilities
     is not tragically but in case we use the memory debugging facilities
     not all memory will be freed.  */
     not all memory will be freed.  */
}
}
 
 
static void
static void
free_derivation (void *p)
free_derivation (void *p)
{
{
  struct known_derivation *deriv = (struct known_derivation *) p;
  struct known_derivation *deriv = (struct known_derivation *) p;
  size_t cnt;
  size_t cnt;
 
 
  for (cnt = 0; cnt < deriv->nsteps; ++cnt)
  for (cnt = 0; cnt < deriv->nsteps; ++cnt)
    if (deriv->steps[cnt].__counter > 0
    if (deriv->steps[cnt].__counter > 0
        && deriv->steps[cnt].__end_fct != NULL)
        && deriv->steps[cnt].__end_fct != NULL)
      deriv->steps[cnt].__end_fct (&deriv->steps[cnt]);
      deriv->steps[cnt].__end_fct (&deriv->steps[cnt]);
 
 
  /* Free the name strings.  */
  /* Free the name strings.  */
  free ((char *) deriv->steps[0].__from_name);
  free ((char *) deriv->steps[0].__from_name);
  free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);
  free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);
 
 
  free ((struct __gconv_step *) deriv->steps);
  free ((struct __gconv_step *) deriv->steps);
  free (deriv);
  free (deriv);
}
}
 
 
 
 
/* Decrement the reference count for a single step in a steps array.  */
/* Decrement the reference count for a single step in a steps array.  */
void
void
internal_function
internal_function
__gconv_release_step (struct __gconv_step *step)
__gconv_release_step (struct __gconv_step *step)
{
{
  if (--step->__counter == 0)
  if (--step->__counter == 0)
    {
    {
      /* Call the destructor.  */
      /* Call the destructor.  */
      if (step->__end_fct != NULL)
      if (step->__end_fct != NULL)
        step->__end_fct (step);
        step->__end_fct (step);
 
 
#ifndef STATIC_GCONV
#ifndef STATIC_GCONV
      /* Skip builtin modules; they are not reference counted.  */
      /* Skip builtin modules; they are not reference counted.  */
      if (step->__shlib_handle != NULL)
      if (step->__shlib_handle != NULL)
        {
        {
          /* Release the loaded module.  */
          /* Release the loaded module.  */
          __gconv_release_shlib (step->__shlib_handle);
          __gconv_release_shlib (step->__shlib_handle);
          step->__shlib_handle = NULL;
          step->__shlib_handle = NULL;
        }
        }
#endif
#endif
    }
    }
}
}
 
 
static int
static int
internal_function
internal_function
gen_steps (struct derivation_step *best, const char *toset,
gen_steps (struct derivation_step *best, const char *toset,
           const char *fromset, struct __gconv_step **handle, size_t *nsteps)
           const char *fromset, struct __gconv_step **handle, size_t *nsteps)
{
{
  size_t step_cnt = 0;
  size_t step_cnt = 0;
  struct __gconv_step *result;
  struct __gconv_step *result;
  struct derivation_step *current;
  struct derivation_step *current;
  int status = __GCONV_NOMEM;
  int status = __GCONV_NOMEM;
 
 
  /* First determine number of steps.  */
  /* First determine number of steps.  */
  for (current = best; current->last != NULL; current = current->last)
  for (current = best; current->last != NULL; current = current->last)
    ++step_cnt;
    ++step_cnt;
 
 
  result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)
  result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)
                                           * step_cnt);
                                           * step_cnt);
  if (result != NULL)
  if (result != NULL)
    {
    {
      int failed = 0;
      int failed = 0;
 
 
      status = __GCONV_OK;
      status = __GCONV_OK;
      *nsteps = step_cnt;
      *nsteps = step_cnt;
      current = best;
      current = best;
      while (step_cnt-- > 0)
      while (step_cnt-- > 0)
        {
        {
          result[step_cnt].__from_name = (step_cnt == 0
          result[step_cnt].__from_name = (step_cnt == 0
                                          ? strdup (fromset)
                                          ? strdup (fromset)
                                          : (char *)current->last->result_set);
                                          : (char *)current->last->result_set);
          result[step_cnt].__to_name = (step_cnt + 1 == *nsteps
          result[step_cnt].__to_name = (step_cnt + 1 == *nsteps
                                        ? strdup (current->result_set)
                                        ? strdup (current->result_set)
                                        : result[step_cnt + 1].__from_name);
                                        : result[step_cnt + 1].__from_name);
 
 
          result[step_cnt].__counter = 1;
          result[step_cnt].__counter = 1;
          result[step_cnt].__data = NULL;
          result[step_cnt].__data = NULL;
 
 
#ifndef STATIC_GCONV
#ifndef STATIC_GCONV
          if (current->code->module_name[0] == '/')
          if (current->code->module_name[0] == '/')
            {
            {
              /* Load the module, return handle for it.  */
              /* Load the module, return handle for it.  */
              struct __gconv_loaded_object *shlib_handle =
              struct __gconv_loaded_object *shlib_handle =
                __gconv_find_shlib (current->code->module_name);
                __gconv_find_shlib (current->code->module_name);
 
 
              if (shlib_handle == NULL)
              if (shlib_handle == NULL)
                {
                {
                  failed = 1;
                  failed = 1;
                  break;
                  break;
                }
                }
 
 
              result[step_cnt].__shlib_handle = shlib_handle;
              result[step_cnt].__shlib_handle = shlib_handle;
              result[step_cnt].__modname = shlib_handle->name;
              result[step_cnt].__modname = shlib_handle->name;
              result[step_cnt].__fct = shlib_handle->fct;
              result[step_cnt].__fct = shlib_handle->fct;
              result[step_cnt].__init_fct = shlib_handle->init_fct;
              result[step_cnt].__init_fct = shlib_handle->init_fct;
              result[step_cnt].__end_fct = shlib_handle->end_fct;
              result[step_cnt].__end_fct = shlib_handle->end_fct;
 
 
              /* Call the init function.  */
              /* Call the init function.  */
              if (result[step_cnt].__init_fct != NULL)
              if (result[step_cnt].__init_fct != NULL)
                {
                {
                  status = result[step_cnt].__init_fct (&result[step_cnt]);
                  status = result[step_cnt].__init_fct (&result[step_cnt]);
 
 
                  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
                  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
                    {
                    {
                      failed = 1;
                      failed = 1;
                      /* Make sure we unload this modules.  */
                      /* Make sure we unload this modules.  */
                      --step_cnt;
                      --step_cnt;
                      result[step_cnt].__end_fct = NULL;
                      result[step_cnt].__end_fct = NULL;
                      break;
                      break;
                    }
                    }
                }
                }
            }
            }
          else
          else
#endif
#endif
            /* It's a builtin transformation.  */
            /* It's a builtin transformation.  */
            __gconv_get_builtin_trans (current->code->module_name,
            __gconv_get_builtin_trans (current->code->module_name,
                                       &result[step_cnt]);
                                       &result[step_cnt]);
 
 
          current = current->last;
          current = current->last;
        }
        }
 
 
      if (__builtin_expect (failed, 0) != 0)
      if (__builtin_expect (failed, 0) != 0)
        {
        {
          /* Something went wrong while initializing the modules.  */
          /* Something went wrong while initializing the modules.  */
          while (++step_cnt < *nsteps)
          while (++step_cnt < *nsteps)
            __gconv_release_step (&result[step_cnt]);
            __gconv_release_step (&result[step_cnt]);
          free (result);
          free (result);
          *nsteps = 0;
          *nsteps = 0;
          *handle = NULL;
          *handle = NULL;
          if (status == __GCONV_OK)
          if (status == __GCONV_OK)
            status = __GCONV_NOCONV;
            status = __GCONV_NOCONV;
        }
        }
      else
      else
        *handle = result;
        *handle = result;
    }
    }
  else
  else
    {
    {
      *nsteps = 0;
      *nsteps = 0;
      *handle = NULL;
      *handle = NULL;
    }
    }
 
 
  return status;
  return status;
}
}
 
 
 
 
#ifndef STATIC_GCONV
#ifndef STATIC_GCONV
static int
static int
internal_function
internal_function
increment_counter (struct __gconv_step *steps, size_t nsteps)
increment_counter (struct __gconv_step *steps, size_t nsteps)
{
{
  /* Increment the user counter.  */
  /* Increment the user counter.  */
  size_t cnt = nsteps;
  size_t cnt = nsteps;
  int result = __GCONV_OK;
  int result = __GCONV_OK;
 
 
  while (cnt-- > 0)
  while (cnt-- > 0)
    {
    {
      struct __gconv_step *step = &steps[cnt];
      struct __gconv_step *step = &steps[cnt];
 
 
      if (step->__counter++ == 0)
      if (step->__counter++ == 0)
        {
        {
          /* Skip builtin modules.  */
          /* Skip builtin modules.  */
          if (step->__modname != NULL)
          if (step->__modname != NULL)
            {
            {
              /* Reopen a previously used module.  */
              /* Reopen a previously used module.  */
              step->__shlib_handle = __gconv_find_shlib (step->__modname);
              step->__shlib_handle = __gconv_find_shlib (step->__modname);
              if (step->__shlib_handle == NULL)
              if (step->__shlib_handle == NULL)
                {
                {
                  /* Oops, this is the second time we use this module
                  /* Oops, this is the second time we use this module
                     (after unloading) and this time loading failed!?  */
                     (after unloading) and this time loading failed!?  */
                  --step->__counter;
                  --step->__counter;
                  while (++cnt < nsteps)
                  while (++cnt < nsteps)
                    __gconv_release_step (&steps[cnt]);
                    __gconv_release_step (&steps[cnt]);
                  result = __GCONV_NOCONV;
                  result = __GCONV_NOCONV;
                  break;
                  break;
                }
                }
 
 
              /* The function addresses defined by the module may
              /* The function addresses defined by the module may
                 have changed.  */
                 have changed.  */
              step->__fct = step->__shlib_handle->fct;
              step->__fct = step->__shlib_handle->fct;
              step->__init_fct = step->__shlib_handle->init_fct;
              step->__init_fct = step->__shlib_handle->init_fct;
              step->__end_fct = step->__shlib_handle->end_fct;
              step->__end_fct = step->__shlib_handle->end_fct;
            }
            }
 
 
          if (step->__init_fct != NULL)
          if (step->__init_fct != NULL)
            step->__init_fct (step);
            step->__init_fct (step);
        }
        }
    }
    }
  return result;
  return result;
}
}
#endif
#endif
 
 
 
 
/* The main function: find a possible derivation from the `fromset' (either
/* The main function: find a possible derivation from the `fromset' (either
   the given name or the alias) to the `toset' (again with alias).  */
   the given name or the alias) to the `toset' (again with alias).  */
static int
static int
internal_function
internal_function
find_derivation (const char *toset, const char *toset_expand,
find_derivation (const char *toset, const char *toset_expand,
                 const char *fromset, const char *fromset_expand,
                 const char *fromset, const char *fromset_expand,
                 struct __gconv_step **handle, size_t *nsteps)
                 struct __gconv_step **handle, size_t *nsteps)
{
{
  struct derivation_step *first, *current, **lastp, *solution = NULL;
  struct derivation_step *first, *current, **lastp, *solution = NULL;
  int best_cost_hi = INT_MAX;
  int best_cost_hi = INT_MAX;
  int best_cost_lo = INT_MAX;
  int best_cost_lo = INT_MAX;
  int result;
  int result;
 
 
  /* Look whether an earlier call to `find_derivation' has already
  /* Look whether an earlier call to `find_derivation' has already
     computed a possible derivation.  If so, return it immediately.  */
     computed a possible derivation.  If so, return it immediately.  */
  result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
  result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
                              handle, nsteps);
                              handle, nsteps);
  if (result == __GCONV_OK)
  if (result == __GCONV_OK)
    {
    {
#ifndef STATIC_GCONV
#ifndef STATIC_GCONV
      result = increment_counter (*handle, *nsteps);
      result = increment_counter (*handle, *nsteps);
#endif
#endif
      return result;
      return result;
    }
    }
 
 
  /* The task is to find a sequence of transformations, backed by the
  /* The task is to find a sequence of transformations, backed by the
     existing modules - whether builtin or dynamically loadable -,
     existing modules - whether builtin or dynamically loadable -,
     starting at `fromset' (or `fromset_expand') and ending at `toset'
     starting at `fromset' (or `fromset_expand') and ending at `toset'
     (or `toset_expand'), and with minimal cost.
     (or `toset_expand'), and with minimal cost.
 
 
     For computer scientists, this is a shortest path search in the
     For computer scientists, this is a shortest path search in the
     graph where the nodes are all possible charsets and the edges are
     graph where the nodes are all possible charsets and the edges are
     the transformations listed in __gconv_modules_db.
     the transformations listed in __gconv_modules_db.
 
 
     For now we use a simple algorithm with quadratic runtime behaviour.
     For now we use a simple algorithm with quadratic runtime behaviour.
     A breadth-first search, starting at `fromset' and `fromset_expand'.
     A breadth-first search, starting at `fromset' and `fromset_expand'.
     The list starting at `first' contains all nodes that have been
     The list starting at `first' contains all nodes that have been
     visited up to now, in the order in which they have been visited --
     visited up to now, in the order in which they have been visited --
     excluding the goal nodes `toset' and `toset_expand' which get
     excluding the goal nodes `toset' and `toset_expand' which get
     managed in the list starting at `solution'.
     managed in the list starting at `solution'.
     `current' walks through the list starting at `first' and looks
     `current' walks through the list starting at `first' and looks
     which nodes are reachable from the current node, adding them to
     which nodes are reachable from the current node, adding them to
     the end of the list [`first' or `solution' respectively] (if
     the end of the list [`first' or `solution' respectively] (if
     they are visited the first time) or updating them in place (if
     they are visited the first time) or updating them in place (if
     they have have already been visited).
     they have have already been visited).
     In each node of either list, cost_lo and cost_hi contain the
     In each node of either list, cost_lo and cost_hi contain the
     minimum cost over any paths found up to now, starting at `fromset'
     minimum cost over any paths found up to now, starting at `fromset'
     or `fromset_expand', ending at that node.  best_cost_lo and
     or `fromset_expand', ending at that node.  best_cost_lo and
     best_cost_hi represent the minimum over the elements of the
     best_cost_hi represent the minimum over the elements of the
     `solution' list.  */
     `solution' list.  */
 
 
  if (fromset_expand != NULL)
  if (fromset_expand != NULL)
    {
    {
      first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
      first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
      first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
      first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
      lastp = &first->next->next;
      lastp = &first->next->next;
    }
    }
  else
  else
    {
    {
      first = NEW_STEP (fromset, 0, 0, NULL, NULL);
      first = NEW_STEP (fromset, 0, 0, NULL, NULL);
      lastp = &first->next;
      lastp = &first->next;
    }
    }
 
 
  for (current = first; current != NULL; current = current->next)
  for (current = first; current != NULL; current = current->next)
    {
    {
      /* Now match all the available module specifications against the
      /* Now match all the available module specifications against the
         current charset name.  If any of them matches check whether
         current charset name.  If any of them matches check whether
         we already have a derivation for this charset.  If yes, use the
         we already have a derivation for this charset.  If yes, use the
         one with the lower costs.  Otherwise add the new charset at the
         one with the lower costs.  Otherwise add the new charset at the
         end.
         end.
 
 
         The module database is organized in a tree form which allows
         The module database is organized in a tree form which allows
         searching for prefixes.  So we search for the first entry with a
         searching for prefixes.  So we search for the first entry with a
         matching prefix and any other matching entry can be found from
         matching prefix and any other matching entry can be found from
         this place.  */
         this place.  */
      struct gconv_module *node;
      struct gconv_module *node;
 
 
      /* Maybe it is not necessary anymore to look for a solution for
      /* Maybe it is not necessary anymore to look for a solution for
         this entry since the cost is already as high (or higher) as
         this entry since the cost is already as high (or higher) as
         the cost for the best solution so far.  */
         the cost for the best solution so far.  */
      if (current->cost_hi > best_cost_hi
      if (current->cost_hi > best_cost_hi
          || (current->cost_hi == best_cost_hi
          || (current->cost_hi == best_cost_hi
              && current->cost_lo >= best_cost_lo))
              && current->cost_lo >= best_cost_lo))
        continue;
        continue;
 
 
      node = __gconv_modules_db;
      node = __gconv_modules_db;
      while (node != NULL)
      while (node != NULL)
        {
        {
          int cmpres = strcmp (current->result_set, node->from_string);
          int cmpres = strcmp (current->result_set, node->from_string);
          if (cmpres == 0)
          if (cmpres == 0)
            {
            {
              /* Walk through the list of modules with this prefix and
              /* Walk through the list of modules with this prefix and
                 try to match the name.  */
                 try to match the name.  */
              struct gconv_module *runp;
              struct gconv_module *runp;
 
 
              /* Check all the modules with this prefix.  */
              /* Check all the modules with this prefix.  */
              runp = node;
              runp = node;
              do
              do
                {
                {
                  const char *result_set = (strcmp (runp->to_string, "-") == 0
                  const char *result_set = (strcmp (runp->to_string, "-") == 0
                                            ? (toset_expand ?: toset)
                                            ? (toset_expand ?: toset)
                                            : runp->to_string);
                                            : runp->to_string);
                  int cost_hi = runp->cost_hi + current->cost_hi;
                  int cost_hi = runp->cost_hi + current->cost_hi;
                  int cost_lo = runp->cost_lo + current->cost_lo;
                  int cost_lo = runp->cost_lo + current->cost_lo;
                  struct derivation_step *step;
                  struct derivation_step *step;
 
 
                  /* We managed to find a derivation.  First see whether
                  /* We managed to find a derivation.  First see whether
                     we have reached one of the goal nodes.  */
                     we have reached one of the goal nodes.  */
                  if (strcmp (result_set, toset) == 0
                  if (strcmp (result_set, toset) == 0
                      || (toset_expand != NULL
                      || (toset_expand != NULL
                          && strcmp (result_set, toset_expand) == 0))
                          && strcmp (result_set, toset_expand) == 0))
                    {
                    {
                      /* Append to the `solution' list if there
                      /* Append to the `solution' list if there
                         is no entry with this name.  */
                         is no entry with this name.  */
                      for (step = solution; step != NULL; step = step->next)
                      for (step = solution; step != NULL; step = step->next)
                        if (strcmp (result_set, step->result_set) == 0)
                        if (strcmp (result_set, step->result_set) == 0)
                          break;
                          break;
 
 
                      if (step == NULL)
                      if (step == NULL)
                        {
                        {
                          step = NEW_STEP (result_set,
                          step = NEW_STEP (result_set,
                                           cost_hi, cost_lo,
                                           cost_hi, cost_lo,
                                           runp, current);
                                           runp, current);
                          step->next = solution;
                          step->next = solution;
                          solution = step;
                          solution = step;
                        }
                        }
                      else if (step->cost_hi > cost_hi
                      else if (step->cost_hi > cost_hi
                               || (step->cost_hi == cost_hi
                               || (step->cost_hi == cost_hi
                                   && step->cost_lo > cost_lo))
                                   && step->cost_lo > cost_lo))
                        {
                        {
                          /* A better path was found for the node,
                          /* A better path was found for the node,
                             on the `solution' list.  */
                             on the `solution' list.  */
                          step->code = runp;
                          step->code = runp;
                          step->last = current;
                          step->last = current;
                          step->cost_hi = cost_hi;
                          step->cost_hi = cost_hi;
                          step->cost_lo = cost_lo;
                          step->cost_lo = cost_lo;
                        }
                        }
 
 
                      /* Update best_cost accordingly.  */
                      /* Update best_cost accordingly.  */
                      if (cost_hi < best_cost_hi
                      if (cost_hi < best_cost_hi
                          || (cost_hi == best_cost_hi
                          || (cost_hi == best_cost_hi
                              && cost_lo < best_cost_lo))
                              && cost_lo < best_cost_lo))
                        {
                        {
                          best_cost_hi = cost_hi;
                          best_cost_hi = cost_hi;
                          best_cost_lo = cost_lo;
                          best_cost_lo = cost_lo;
                        }
                        }
                    }
                    }
                  else if (cost_hi < best_cost_hi
                  else if (cost_hi < best_cost_hi
                           || (cost_hi == best_cost_hi
                           || (cost_hi == best_cost_hi
                               && cost_lo < best_cost_lo))
                               && cost_lo < best_cost_lo))
                    {
                    {
                      /* Append at the end of the `first' list if there
                      /* Append at the end of the `first' list if there
                         is no entry with this name.  */
                         is no entry with this name.  */
                      for (step = first; step != NULL; step = step->next)
                      for (step = first; step != NULL; step = step->next)
                        if (strcmp (result_set, step->result_set) == 0)
                        if (strcmp (result_set, step->result_set) == 0)
                          break;
                          break;
 
 
                      if (step == NULL)
                      if (step == NULL)
                        {
                        {
                          *lastp = NEW_STEP (result_set,
                          *lastp = NEW_STEP (result_set,
                                             cost_hi, cost_lo,
                                             cost_hi, cost_lo,
                                             runp, current);
                                             runp, current);
                          lastp = &(*lastp)->next;
                          lastp = &(*lastp)->next;
                        }
                        }
                      else if (step->cost_hi > cost_hi
                      else if (step->cost_hi > cost_hi
                               || (step->cost_hi == cost_hi
                               || (step->cost_hi == cost_hi
                                   && step->cost_lo > cost_lo))
                                   && step->cost_lo > cost_lo))
                        {
                        {
                          /* A better path was found for the node,
                          /* A better path was found for the node,
                             on the `first' list.  */
                             on the `first' list.  */
                          step->code = runp;
                          step->code = runp;
                          step->last = current;
                          step->last = current;
 
 
                          /* Update the cost for all steps.  */
                          /* Update the cost for all steps.  */
                          for (step = first; step != NULL;
                          for (step = first; step != NULL;
                               step = step->next)
                               step = step->next)
                            /* But don't update the start nodes.  */
                            /* But don't update the start nodes.  */
                            if (step->code != NULL)
                            if (step->code != NULL)
                              {
                              {
                                struct derivation_step *back;
                                struct derivation_step *back;
                                int hi, lo;
                                int hi, lo;
 
 
                                hi = step->code->cost_hi;
                                hi = step->code->cost_hi;
                                lo = step->code->cost_lo;
                                lo = step->code->cost_lo;
 
 
                                for (back = step->last; back->code != NULL;
                                for (back = step->last; back->code != NULL;
                                     back = back->last)
                                     back = back->last)
                                  {
                                  {
                                    hi += back->code->cost_hi;
                                    hi += back->code->cost_hi;
                                    lo += back->code->cost_lo;
                                    lo += back->code->cost_lo;
                                  }
                                  }
 
 
                                step->cost_hi = hi;
                                step->cost_hi = hi;
                                step->cost_lo = lo;
                                step->cost_lo = lo;
                              }
                              }
 
 
                          /* Likewise for the nodes on the solution list.
                          /* Likewise for the nodes on the solution list.
                             Also update best_cost accordingly.  */
                             Also update best_cost accordingly.  */
                          for (step = solution; step != NULL;
                          for (step = solution; step != NULL;
                               step = step->next)
                               step = step->next)
                            {
                            {
                              step->cost_hi = (step->code->cost_hi
                              step->cost_hi = (step->code->cost_hi
                                               + step->last->cost_hi);
                                               + step->last->cost_hi);
                              step->cost_lo = (step->code->cost_lo
                              step->cost_lo = (step->code->cost_lo
                                               + step->last->cost_lo);
                                               + step->last->cost_lo);
 
 
                              if (step->cost_hi < best_cost_hi
                              if (step->cost_hi < best_cost_hi
                                  || (step->cost_hi == best_cost_hi
                                  || (step->cost_hi == best_cost_hi
                                      && step->cost_lo < best_cost_lo))
                                      && step->cost_lo < best_cost_lo))
                                {
                                {
                                  best_cost_hi = step->cost_hi;
                                  best_cost_hi = step->cost_hi;
                                  best_cost_lo = step->cost_lo;
                                  best_cost_lo = step->cost_lo;
                                }
                                }
                            }
                            }
                        }
                        }
                    }
                    }
 
 
                  runp = runp->same;
                  runp = runp->same;
                }
                }
              while (runp != NULL);
              while (runp != NULL);
 
 
              break;
              break;
            }
            }
          else if (cmpres < 0)
          else if (cmpres < 0)
            node = node->left;
            node = node->left;
          else
          else
            node = node->right;
            node = node->right;
        }
        }
    }
    }
 
 
  if (solution != NULL)
  if (solution != NULL)
    {
    {
      /* We really found a way to do the transformation.  */
      /* We really found a way to do the transformation.  */
 
 
      /* Choose the best solution.  This is easy because we know that
      /* Choose the best solution.  This is easy because we know that
         the solution list has at most length 2 (one for every possible
         the solution list has at most length 2 (one for every possible
         goal node).  */
         goal node).  */
      if (solution->next != NULL)
      if (solution->next != NULL)
        {
        {
          struct derivation_step *solution2 = solution->next;
          struct derivation_step *solution2 = solution->next;
 
 
          if (solution2->cost_hi < solution->cost_hi
          if (solution2->cost_hi < solution->cost_hi
              || (solution2->cost_hi == solution->cost_hi
              || (solution2->cost_hi == solution->cost_hi
                  && solution2->cost_lo < solution->cost_lo))
                  && solution2->cost_lo < solution->cost_lo))
            solution = solution2;
            solution = solution2;
        }
        }
 
 
      /* Now build a data structure describing the transformation steps.  */
      /* Now build a data structure describing the transformation steps.  */
      result = gen_steps (solution, toset_expand ?: toset,
      result = gen_steps (solution, toset_expand ?: toset,
                          fromset_expand ?: fromset, handle, nsteps);
                          fromset_expand ?: fromset, handle, nsteps);
    }
    }
  else
  else
    {
    {
      /* We haven't found a transformation.  Clear the result values.  */
      /* We haven't found a transformation.  Clear the result values.  */
      *handle = NULL;
      *handle = NULL;
      *nsteps = 0;
      *nsteps = 0;
    }
    }
 
 
  /* Add result in any case to list of known derivations.  */
  /* Add result in any case to list of known derivations.  */
  add_derivation (fromset_expand ?: fromset, toset_expand ?: toset,
  add_derivation (fromset_expand ?: fromset, toset_expand ?: toset,
                  *handle, *nsteps);
                  *handle, *nsteps);
 
 
  return result;
  return result;
}
}
 
 
 
 
/* Control of initialization.  */
/* Control of initialization.  */
__libc_once_define (static, once);
__libc_once_define (static, once);
 
 
 
 
static const char *
static const char *
do_lookup_alias (const char *name)
do_lookup_alias (const char *name)
{
{
  struct gconv_alias key;
  struct gconv_alias key;
  struct gconv_alias **found;
  struct gconv_alias **found;
 
 
  key.fromname = (char *) name;
  key.fromname = (char *) name;
  found = tfind (&key, &__gconv_alias_db, __gconv_alias_compare);
  found = tfind (&key, &__gconv_alias_db, __gconv_alias_compare);
  return found != NULL ? (*found)->toname : NULL;
  return found != NULL ? (*found)->toname : NULL;
}
}
 
 
 
 
int
int
internal_function
internal_function
__gconv_compare_alias (const char *name1, const char *name2)
__gconv_compare_alias (const char *name1, const char *name2)
{
{
  int result;
  int result;
 
 
  /* Ensure that the configuration data is read.  */
  /* Ensure that the configuration data is read.  */
  __libc_once (once, __gconv_read_conf);
  __libc_once (once, __gconv_read_conf);
 
 
  if (__gconv_compare_alias_cache (name1, name2, &result) != 0)
  if (__gconv_compare_alias_cache (name1, name2, &result) != 0)
    result = strcmp (do_lookup_alias (name1) ?: name1,
    result = strcmp (do_lookup_alias (name1) ?: name1,
                     do_lookup_alias (name2) ?: name2);
                     do_lookup_alias (name2) ?: name2);
 
 
  return result;
  return result;
}
}
 
 
 
 
int
int
internal_function
internal_function
__gconv_find_transform (const char *toset, const char *fromset,
__gconv_find_transform (const char *toset, const char *fromset,
                        struct __gconv_step **handle, size_t *nsteps,
                        struct __gconv_step **handle, size_t *nsteps,
                        int flags)
                        int flags)
{
{
  const char *fromset_expand;
  const char *fromset_expand;
  const char *toset_expand;
  const char *toset_expand;
  int result;
  int result;
 
 
  /* Ensure that the configuration data is read.  */
  /* Ensure that the configuration data is read.  */
  __libc_once (once, __gconv_read_conf);
  __libc_once (once, __gconv_read_conf);
 
 
  /* Acquire the lock.  */
  /* Acquire the lock.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_acquire(lock);
  __lock_acquire(lock);
#endif
#endif
 
 
  result = __gconv_lookup_cache (toset, fromset, handle, nsteps, flags);
  result = __gconv_lookup_cache (toset, fromset, handle, nsteps, flags);
  if (result != __GCONV_NODB)
  if (result != __GCONV_NODB)
    {
    {
      /* We have a cache and could resolve the request, successful or not.  */
      /* We have a cache and could resolve the request, successful or not.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
      __lock_release(lock);
      __lock_release(lock);
#endif
#endif
 
 
      return result;
      return result;
    }
    }
 
 
  /* If we don't have a module database return with an error.  */
  /* If we don't have a module database return with an error.  */
  if (__gconv_modules_db == NULL)
  if (__gconv_modules_db == NULL)
    {
    {
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_release(lock);
  __lock_release(lock);
#endif
#endif
 
 
      return __GCONV_NOCONV;
      return __GCONV_NOCONV;
    }
    }
 
 
  /* See whether the names are aliases.  */
  /* See whether the names are aliases.  */
  fromset_expand = do_lookup_alias (fromset);
  fromset_expand = do_lookup_alias (fromset);
  toset_expand = do_lookup_alias (toset);
  toset_expand = do_lookup_alias (toset);
 
 
  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0)
  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0)
      /* We are not supposed to create a pseudo transformation (means
      /* We are not supposed to create a pseudo transformation (means
         copying) when the input and output character set are the same.  */
         copying) when the input and output character set are the same.  */
      && (strcmp (toset, fromset) == 0
      && (strcmp (toset, fromset) == 0
          || (toset_expand != NULL && strcmp (toset_expand, fromset) == 0)
          || (toset_expand != NULL && strcmp (toset_expand, fromset) == 0)
          || (fromset_expand != NULL
          || (fromset_expand != NULL
              && (strcmp (toset, fromset_expand) == 0
              && (strcmp (toset, fromset_expand) == 0
                  || (toset_expand != NULL
                  || (toset_expand != NULL
                      && strcmp (toset_expand, fromset_expand) == 0)))))
                      && strcmp (toset_expand, fromset_expand) == 0)))))
    {
    {
      /* Both character sets are the same.  */
      /* Both character sets are the same.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_release(lock);
  __lock_release(lock);
#endif
#endif
 
 
      return __GCONV_NOCONV;
      return __GCONV_NOCONV;
    }
    }
 
 
  result = find_derivation (toset, toset_expand, fromset, fromset_expand,
  result = find_derivation (toset, toset_expand, fromset, fromset_expand,
                            handle, nsteps);
                            handle, nsteps);
 
 
  /* Release the lock.  */
  /* Release the lock.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_release(lock);
  __lock_release(lock);
#endif
#endif
 
 
 
 
  /* The following code is necessary since `find_derivation' will return
  /* The following code is necessary since `find_derivation' will return
     GCONV_OK even when no derivation was found but the same request
     GCONV_OK even when no derivation was found but the same request
     was processed before.  I.e., negative results will also be cached.  */
     was processed before.  I.e., negative results will also be cached.  */
  return (result == __GCONV_OK
  return (result == __GCONV_OK
          ? (*handle == NULL ? __GCONV_NOCONV : __GCONV_OK)
          ? (*handle == NULL ? __GCONV_NOCONV : __GCONV_OK)
          : result);
          : result);
}
}
 
 
 
 
/* Release the entries of the modules list.  */
/* Release the entries of the modules list.  */
int
int
internal_function
internal_function
__gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
__gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
{
{
  int result = __GCONV_OK;
  int result = __GCONV_OK;
  size_t cnt;
  size_t cnt;
 
 
  /* Acquire the lock.  */
  /* Acquire the lock.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_acquire(lock);
  __lock_acquire(lock);
#endif
#endif
 
 
 
 
#ifndef STATIC_GCONV
#ifndef STATIC_GCONV
  cnt = nsteps;
  cnt = nsteps;
  while (cnt-- > 0)
  while (cnt-- > 0)
    __gconv_release_step (&steps[cnt]);
    __gconv_release_step (&steps[cnt]);
#endif
#endif
 
 
  /* If we use the cache we free a bit more since we don't keep any
  /* If we use the cache we free a bit more since we don't keep any
     transformation records around, they are cheap enough to
     transformation records around, they are cheap enough to
     recreate.  */
     recreate.  */
  __gconv_release_cache (steps, nsteps);
  __gconv_release_cache (steps, nsteps);
 
 
  /* Release the lock.  */
  /* Release the lock.  */
#ifdef HAVE_DD_LOCK
#ifdef HAVE_DD_LOCK
  __lock_release(lock);
  __lock_release(lock);
#endif
#endif
 
 
 
 
  return result;
  return result;
}
}
 
 
 
 
/* Free the modules mentioned.  */
/* Free the modules mentioned.  */
static void
static void
internal_function
internal_function
free_modules_db (struct gconv_module *node)
free_modules_db (struct gconv_module *node)
{
{
  if (node->left != NULL)
  if (node->left != NULL)
    free_modules_db (node->left);
    free_modules_db (node->left);
  if (node->right != NULL)
  if (node->right != NULL)
    free_modules_db (node->right);
    free_modules_db (node->right);
  do
  do
    {
    {
      struct gconv_module *act = node;
      struct gconv_module *act = node;
      node = node->same;
      node = node->same;
      if (act->module_name[0] == '/')
      if (act->module_name[0] == '/')
        free (act);
        free (act);
    }
    }
  while (node != NULL);
  while (node != NULL);
}
}
 
 
 
 
/* Free all resources if necessary.  */
/* Free all resources if necessary.  */
static void __attribute__ ((unused))
static void __attribute__ ((unused))
free_mem (void)
free_mem (void)
{
{
  if (__gconv_alias_db != NULL)
  if (__gconv_alias_db != NULL)
    tdestroy (__gconv_alias_db, free);
    tdestroy (__gconv_alias_db, free);
 
 
  if (__gconv_modules_db != NULL)
  if (__gconv_modules_db != NULL)
    free_modules_db (__gconv_modules_db);
    free_modules_db (__gconv_modules_db);
 
 
  if (known_derivations != NULL)
  if (known_derivations != NULL)
    tdestroy (known_derivations, free_derivation);
    tdestroy (known_derivations, free_derivation);
}
}
 
 
text_set_element (__libc_subfreeres, free_mem);
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.