⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gconv_db.c

📁 Newlib 嵌入式 C库 标准实现代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Provide access to the collection of available transformation modules.   Copyright (C) 1997,98,99,2000,2001 Free Software Foundation, Inc.   This file is part of the GNU C Library.   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   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,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Lesser General Public License for more details.   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   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.  */#include <limits.h>#include <search.h>#include <stdlib.h>#include <string.h>#include <sys/param.h>#include <dirent.h>#include <dlfcn.h>#include <gconv_int.h>#include <gconv_charset.h>/* Simple data structure for alias mapping.  We have two names, `from'   and `to'.  */void *__gconv_alias_db;/* Array with available modules.  */struct gconv_module *__gconv_modules_db;/* We modify global data.   */__LOCK_INIT(static, lock);/* Function for searching alias.  */int__gconv_alias_compare (const void *p1, const void *p2){  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;  return strcmp (s1->fromname, s2->fromname);}/* To search for a derivation we create a list of intermediate steps.   Each element contains a pointer to the element which precedes it   in the derivation order.  */struct derivation_step{  const char *result_set;  size_t result_set_len;  int cost_lo;  int cost_hi;  struct gconv_module *code;  struct derivation_step *last;  struct derivation_step *next;};#define NEW_STEP(result, hi, lo, module, last_mod) \  ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \     newp->result_set = result;						      \     newp->result_set_len = strlen (result);				      \     newp->cost_hi = hi;						      \     newp->cost_lo = lo;						      \     newp->code = module;						      \     newp->last = last_mod;						      \     newp->next = NULL;							      \     newp; })/* If a specific transformation is used more than once we should not need   to start looking for it again.  Instead cache each successful result.  */struct known_derivation{  const char *from;  const char *to;  struct __gconv_step *steps;  size_t nsteps;};/* Compare function for database of found derivations.  */static intderivation_compare (const void *p1, const void *p2){  const struct known_derivation *s1 = (const struct known_derivation *) p1;  const struct known_derivation *s2 = (const struct known_derivation *) p2;  int result;  result = strcmp (s1->from, s2->from);  if (result == 0)    result = strcmp (s1->to, s2->to);  return result;}/* The search tree for known derivations.  */static void *known_derivations;/* Look up whether given transformation was already requested before.  */static intinternal_functionderivation_lookup (const char *fromset, const char *toset,		   struct __gconv_step **handle, size_t *nsteps){  struct known_derivation key = { fromset, toset, NULL, 0 };  struct known_derivation **result;  result = tfind (&key, &known_derivations, derivation_compare);  if (result == NULL)    return __GCONV_NOCONV;  *handle = (*result)->steps;  *nsteps = (*result)->nsteps;  /* Please note that we return GCONV_OK even if the last search for     this transformation was unsuccessful.  */  return __GCONV_OK;}/* Add new derivation to list of known ones.  */static voidinternal_functionadd_derivation (const char *fromset, const char *toset,		struct __gconv_step *handle, size_t nsteps){  struct known_derivation *new_deriv;  size_t fromset_len = strlen (fromset) + 1;  size_t toset_len = strlen (toset) + 1;  new_deriv = (struct known_derivation *)    malloc (sizeof (struct known_derivation) + fromset_len + toset_len);  if (new_deriv != NULL)    {      char *tmp;      new_deriv->from = (char *) (new_deriv + 1);      tmp = memcpy (new_deriv + 1, fromset, fromset_len);      tmp += fromset_len;      new_deriv->to = memcpy (tmp,			      toset, toset_len);      new_deriv->steps = handle;      new_deriv->nsteps = nsteps;      if (tsearch (new_deriv, &known_derivations, derivation_compare)	  == NULL)	/* There is some kind of memory allocation problem.  */	free (new_deriv);    }  /* Please note that we don't complain if the allocation failed.  This     is not tragically but in case we use the memory debugging facilities     not all memory will be freed.  */}static voidfree_derivation (void *p){  struct known_derivation *deriv = (struct known_derivation *) p;  size_t cnt;  for (cnt = 0; cnt < deriv->nsteps; ++cnt)    if (deriv->steps[cnt].__counter > 0	&& deriv->steps[cnt].__end_fct != NULL)      deriv->steps[cnt].__end_fct (&deriv->steps[cnt]);  /* Free the name strings.  */  free ((char *) deriv->steps[0].__from_name);  free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);  free ((struct __gconv_step *) deriv->steps);  free (deriv);}/* Decrement the reference count for a single step in a steps array.  */voidinternal_function__gconv_release_step (struct __gconv_step *step){  if (--step->__counter == 0)    {      /* Call the destructor.  */      if (step->__end_fct != NULL)	step->__end_fct (step);#ifndef STATIC_GCONV      /* Skip builtin modules; they are not reference counted.  */      if (step->__shlib_handle != NULL)	{	  /* Release the loaded module.  */	  __gconv_release_shlib (step->__shlib_handle);	  step->__shlib_handle = NULL;	}#endif    }}static intinternal_functiongen_steps (struct derivation_step *best, const char *toset,	   const char *fromset, struct __gconv_step **handle, size_t *nsteps){  size_t step_cnt = 0;  struct __gconv_step *result;  struct derivation_step *current;  int status = __GCONV_NOMEM;  /* First determine number of steps.  */  for (current = best; current->last != NULL; current = current->last)    ++step_cnt;  result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)					   * step_cnt);  if (result != NULL)    {      int failed = 0;      status = __GCONV_OK;      *nsteps = step_cnt;      current = best;      while (step_cnt-- > 0)	{	  result[step_cnt].__from_name = (step_cnt == 0					  ? strdup (fromset)					  : (char *)current->last->result_set);	  result[step_cnt].__to_name = (step_cnt + 1 == *nsteps					? strdup (current->result_set)					: result[step_cnt + 1].__from_name);	  result[step_cnt].__counter = 1;	  result[step_cnt].__data = NULL;#ifndef STATIC_GCONV	  if (current->code->module_name[0] == '/')	    {	      /* Load the module, return handle for it.  */	      struct __gconv_loaded_object *shlib_handle =		__gconv_find_shlib (current->code->module_name);	      if (shlib_handle == NULL)		{		  failed = 1;		  break;		}	      result[step_cnt].__shlib_handle = shlib_handle;	      result[step_cnt].__modname = shlib_handle->name;	      result[step_cnt].__fct = shlib_handle->fct;	      result[step_cnt].__init_fct = shlib_handle->init_fct;	      result[step_cnt].__end_fct = shlib_handle->end_fct;	      /* Call the init function.  */	      if (result[step_cnt].__init_fct != NULL)		{		  status = result[step_cnt].__init_fct (&result[step_cnt]);		  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)		    {		      failed = 1;		      /* Make sure we unload this modules.  */		      --step_cnt;		      result[step_cnt].__end_fct = NULL;		      break;		    }		}	    }	  else#endif	    /* It's a builtin transformation.  */	    __gconv_get_builtin_trans (current->code->module_name,				       &result[step_cnt]);	  current = current->last;	}      if (__builtin_expect (failed, 0) != 0)	{	  /* Something went wrong while initializing the modules.  */	  while (++step_cnt < *nsteps)	    __gconv_release_step (&result[step_cnt]);	  free (result);	  *nsteps = 0;	  *handle = NULL;	  if (status == __GCONV_OK)	    status = __GCONV_NOCONV;	}      else	*handle = result;    }  else    {      *nsteps = 0;      *handle = NULL;    }  return status;}#ifndef STATIC_GCONVstatic intinternal_functionincrement_counter (struct __gconv_step *steps, size_t nsteps){  /* Increment the user counter.  */  size_t cnt = nsteps;  int result = __GCONV_OK;  while (cnt-- > 0)    {      struct __gconv_step *step = &steps[cnt];      if (step->__counter++ == 0)	{	  /* Skip builtin modules.  */	  if (step->__modname != NULL)	    {	      /* Reopen a previously used module.  */	      step->__shlib_handle = __gconv_find_shlib (step->__modname);	      if (step->__shlib_handle == NULL)		{		  /* Oops, this is the second time we use this module		     (after unloading) and this time loading failed!?  */		  --step->__counter;		  while (++cnt < nsteps)		    __gconv_release_step (&steps[cnt]);		  result = __GCONV_NOCONV;		  break;		}	      /* The function addresses defined by the module may		 have changed.  */	      step->__fct = step->__shlib_handle->fct;	      step->__init_fct = step->__shlib_handle->init_fct;	      step->__end_fct = step->__shlib_handle->end_fct;	    }	  if (step->__init_fct != NULL)	    step->__init_fct (step);	}    }  return result;}#endif/* The main function: find a possible derivation from the `fromset' (either   the given name or the alias) to the `toset' (again with alias).  */static intinternal_functionfind_derivation (const char *toset, const char *toset_expand,		 const char *fromset, const char *fromset_expand,		 struct __gconv_step **handle, size_t *nsteps){  struct derivation_step *first, *current, **lastp, *solution = NULL;  int best_cost_hi = INT_MAX;  int best_cost_lo = INT_MAX;  int result;  /* Look whether an earlier call to `find_derivation' has already     computed a possible derivation.  If so, return it immediately.  */  result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,			      handle, nsteps);  if (result == __GCONV_OK)    {#ifndef STATIC_GCONV      result = increment_counter (*handle, *nsteps);#endif      return result;    }  /* The task is to find a sequence of transformations, backed by the     existing modules - whether builtin or dynamically loadable -,     starting at `fromset' (or `fromset_expand') and ending at `toset'     (or `toset_expand'), and with minimal cost.     For computer scientists, this is a shortest path search in the     graph where the nodes are all possible charsets and the edges are     the transformations listed in __gconv_modules_db.     For now we use a simple algorithm with quadratic runtime behaviour.     A breadth-first search, starting at `fromset' and `fromset_expand'.     The list starting at `first' contains all nodes that have been     visited up to now, in the order in which they have been visited --     excluding the goal nodes `toset' and `toset_expand' which get     managed in the list starting at `solution'.     `current' walks through the list starting at `first' and looks     which nodes are reachable from the current node, adding them to     the end of the list [`first' or `solution' respectively] (if     they are visited the first time) or updating them in place (if     they have have already been visited).     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'

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -