about summary refs log tree commit diff
path: root/iconv
diff options
context:
space:
mode:
Diffstat (limited to 'iconv')
-rw-r--r--iconv/gconv_cache.c128
-rw-r--r--iconv/iconvconfig.c23
2 files changed, 94 insertions, 57 deletions
diff --git a/iconv/gconv_cache.c b/iconv/gconv_cache.c
index 42f41ef3d6..498993db82 100644
--- a/iconv/gconv_cache.c
+++ b/iconv/gconv_cache.c
@@ -178,7 +178,7 @@ find_module (const char *directory, const char *filename,
   size_t dirlen = strlen (directory);
   size_t fnamelen = strlen (filename) + 1;
   char *fullname;
-  int status = __GCONV_OK;
+  int status = __GCONV_NOCONV;
 
   fullname = (char *) malloc (dirlen + fnamelen);
   if (fullname == NULL)
@@ -187,17 +187,22 @@ find_module (const char *directory, const char *filename,
   memcpy (__mempcpy (fullname, directory, dirlen), filename, fnamelen);
 
   result->__shlib_handle = __gconv_find_shlib (fullname);
-  if (result->__shlib_handle == NULL)
-    return __GCONV_NOCONV;
+  if (result->__shlib_handle != NULL)
+    {
+      status = __GCONV_OK;
+
+      result->__modname = fullname;
+      result->__fct = result->__shlib_handle->fct;
+      result->__init_fct = result->__shlib_handle->init_fct;
+      result->__end_fct = result->__shlib_handle->end_fct;
 
-  result->__modname = fullname;
-  result->__fct = result->__shlib_handle->fct;
-  result->__init_fct = result->__shlib_handle->init_fct;
-  result->__end_fct = result->__shlib_handle->end_fct;
+      result->__data = NULL;
+      if (result->__init_fct != NULL)
+	status = DL_CALL_FCT (result->__init_fct, (result));
+    }
 
-  result->__data = NULL;
-  if (result->__init_fct != NULL)
-    status = DL_CALL_FCT (result->__init_fct, (result));
+  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
+    free (fullname);
 
   return status;
 }
@@ -235,7 +240,8 @@ __gconv_lookup_cache (const char *toset, const char *fromset,
   if (find_module_idx (toset, &toidx) != 0
       || (header->module_offset + (toidx + 1) * sizeof (struct module_entry)
 	  > cache_size))
-    return __GCONV_NOCONV;
+    {puts("toset not found");
+    return __GCONV_NOCONV;}
   to_module = &modtab[toidx];
 
   /* Avoid copy-only transformations if the user requests.   */
@@ -243,7 +249,8 @@ __gconv_lookup_cache (const char *toset, const char *fromset,
     return __GCONV_NOCONV;
 
   /* If there are special conversions available examine them first.  */
-  if (__builtin_expect (from_module->extra_offset, 0) != 0)
+  if (fromidx != 0 && toidx != 0
+      && __builtin_expect (from_module->extra_offset, 0) != 0)
     {
       /* Search through the list to see whether there is a module
 	 matching the destination character set.  */
@@ -317,8 +324,8 @@ __gconv_lookup_cache (const char *toset, const char *fromset,
 
  try_internal:
   /* See whether we can convert via the INTERNAL charset.  */
-  if (__builtin_expect (from_module->fromname_offset, 1) == 0
-      || __builtin_expect (to_module->toname_offset, 1) == 0)
+  if ((fromidx != 0 && __builtin_expect (from_module->fromname_offset, 1) == 0)
+      || (toidx != 0 && __builtin_expect (to_module->toname_offset, 1) == 0))
     /* Not possible.  Nothing we can do.  */
     return __GCONV_NOCONV;
 
@@ -328,62 +335,75 @@ __gconv_lookup_cache (const char *toset, const char *fromset,
     return __GCONV_NOMEM;
 
   *handle = result;
-  *nsteps = 2;
+  *nsteps = 0;
 
   /* Generate data structure for conversion to INTERNAL.  */
-  result[0].__from_name = (char *) strtab + from_module->canonname_offset;
-  result[0].__to_name = (char *) "INTERNAL";
+  if (fromidx != 0)
+    {
+      result[0].__from_name = (char *) strtab + from_module->canonname_offset;
+      result[0].__to_name = (char *) "INTERNAL";
 
-  result[0].__counter = 1;
-  result[0].__data = NULL;
+      result[0].__counter = 1;
+      result[0].__data = NULL;
 
 #ifndef STATIC_GCONV
-  if (strtab[from_module->todir_offset] != '\0')
-    {
-      /* Load the module, return handle for it.  */
-      int res = find_module (strtab + from_module->todir_offset,
-			     strtab + from_module->toname_offset,
-			     &result[0]);
-      if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+      if (strtab[from_module->todir_offset] != '\0')
 	{
-	  /* Something went wrong.  */
-	  free (result);
-	  return res;
+	  /* Load the module, return handle for it.  */
+	  int res = find_module (strtab + from_module->todir_offset,
+				 strtab + from_module->toname_offset,
+				 &result[0]);
+	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+	    {
+	      /* Something went wrong.  */
+	      free (result);
+	      return res;
+	    }
 	}
-    }
-  else
+      else
 #endif
-    /* It's a builtin transformation.  */
-    __gconv_get_builtin_trans (strtab + from_module->toname_offset,
-			       &result[0]);
+	/* It's a builtin transformation.  */
+	__gconv_get_builtin_trans (strtab + from_module->toname_offset,
+				   &result[0]);
+
+      ++*nsteps;
+    }
 
   /* Generate data structure for conversion from INTERNAL.  */
-  result[1].__from_name = (char *) "INTERNAL";
-  result[1].__to_name = (char *) strtab + to_module->canonname_offset;
+  if (toidx != 0)
+    {
+      int idx = *nsteps;
 
-  result[1].__counter = 1;
-  result[1].__data = NULL;
+      result[idx].__from_name = (char *) "INTERNAL";
+      result[idx].__to_name = (char *) strtab + to_module->canonname_offset;
+
+      result[idx].__counter = 1;
+      result[idx].__data = NULL;
 
 #ifndef STATIC_GCONV
-  if (strtab[to_module->fromdir_offset] != '\0')
-    {
-      /* Load the module, return handle for it.  */
-      int res = find_module (strtab + to_module->fromdir_offset,
-			     strtab + to_module->fromname_offset,
-			     &result[1]);
-      if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+      if (strtab[to_module->fromdir_offset] != '\0')
 	{
-	  /* Something went wrong.  */
-	  __gconv_release_step (&result[0]);
-	  free (result);
-	  return res;
+	  /* Load the module, return handle for it.  */
+	  int res = find_module (strtab + to_module->fromdir_offset,
+				 strtab + to_module->fromname_offset,
+				 &result[idx]);
+	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+	    {
+	      /* Something went wrong.  */
+	      if (idx != 0)
+		__gconv_release_step (&result[0]);
+	      free (result);
+	      return res;
+	    }
 	}
-    }
-  else
+      else
 #endif
-    /* It's a builtin transformation.  */
-    __gconv_get_builtin_trans (strtab + to_module->fromname_offset,
-			       &result[1]);
+	/* It's a builtin transformation.  */
+	__gconv_get_builtin_trans (strtab + to_module->fromname_offset,
+				   &result[idx]);
+
+      ++*nsteps;
+    }
 
   return __GCONV_OK;
 }
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index a8523bf25c..1d76c8f1ca 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -714,6 +714,8 @@ add_builtins (void)
 
   /* add the builtin transformations.  */
   for (cnt = 0; cnt < nbuiltin_trans; ++cnt)
+    {
+      printf("%s: %s -> %s\n", builtin_trans[cnt].module,builtin_trans[cnt].from,builtin_trans[cnt].to);
     new_module (builtin_trans[cnt].from,
 		strlen (builtin_trans[cnt].from) + 1,
 		builtin_trans[cnt].to,
@@ -721,6 +723,7 @@ add_builtins (void)
 		"", builtin_trans[cnt].module,
 		strlen (builtin_trans[cnt].module) + 1,
 		builtin_trans[cnt].cost, 0);
+    }
 }
 
 
@@ -755,6 +758,11 @@ generate_name_list (void)
 {
   size_t i;
 
+  /* A name we always need.  */
+  tsearch (new_name ("INTERNAL", strtabadd (strtab, "INTERNAL",
+					    sizeof ("INTERNAL"))),
+	   &names, name_compare);
+
   for (i = 0; i < nmodule_list; ++i)
     {
       struct module *runp;
@@ -796,10 +804,19 @@ static void
 generate_name_info (void)
 {
   size_t i;
+  int idx;
 
-  name_info = (struct name_info *) xcalloc (nmodule_list,
+  name_info = (struct name_info *) xcalloc (nmodule_list + 1,
 					    sizeof (struct name_info));
 
+  /* First add a special entry for the INTERNAL name.  This must have
+     index zero.  */
+  idx = name_to_module_idx ("INTERNAL", 1);
+  name_info[0].canonical_name = "INTERNAL";
+  name_info[0].canonical_strent = strtabadd (strtab, "INTERNAL",
+					     sizeof ("INTERNAL"));
+  assert (nname_info == 1);
+
   for (i = 0; i < nmodule_list; ++i)
     {
       struct module *runp;
@@ -807,7 +824,7 @@ generate_name_info (void)
       for (runp = module_list[i]; runp != NULL; runp = runp->next)
 	if (strcmp (runp->fromname, "INTERNAL") == 0)
 	  {
-	    int idx = name_to_module_idx (runp->toname, 1);
+	    idx = name_to_module_idx (runp->toname, 1);
 	    name_info[idx].from_internal = runp;
 	    assert (name_info[idx].canonical_name == NULL
 		    || strcmp (name_info[idx].canonical_name,
@@ -817,7 +834,7 @@ generate_name_info (void)
 	  }
 	else if (strcmp (runp->toname, "INTERNAL") == 0)
 	  {
-	    int idx = name_to_module_idx (runp->fromname, 1);
+	    idx = name_to_module_idx (runp->fromname, 1);
 	    name_info[idx].to_internal = runp;
 	    assert (name_info[idx].canonical_name == NULL
 		    || strcmp (name_info[idx].canonical_name,