Make create_iconv() properly distinguish converters by name.
authorBen Pfaff <blp@gnu.org>
Wed, 8 Apr 2009 04:15:40 +0000 (21:15 -0700)
committerBen Pfaff <blp@gnu.org>
Wed, 8 Apr 2009 04:15:40 +0000 (21:15 -0700)
The code in create_iconv() assumed that every pair of different converters
had a different hash value.  This is a bad assumption: eventually, we will
be unlucky, and two different converters will hash to the same value, and
we will get a bad conversion.  So we have to compare (and store) the
names of the codes that each converters converts to and from.

Also, compute the hash value without making an extra copy of fromcode
and tocode.

src/libpspp/i18n.c

index a4e9b63f755ed8e6abd6b611567c03e1d02b5fea..74ec1f1fdeb18c0116c95d8e30b6e12cd57381e6 100644 (file)
 #include <langinfo.h>
 #endif
 
+struct converter
+  {
+    const char *tocode;
+    const char *fromcode;
+    iconv_t conv;
+  };
+
 static char *default_encoding;
 static struct hmapx map;
 
@@ -46,42 +53,34 @@ static struct hmapx map;
 static iconv_t
 create_iconv (const char* tocode, const char* fromcode)
 {
-  iconv_t conv;
+  size_t hash;
   struct hmapx_node *node;
-  size_t hash ;
-  char *key = alloca (strlen (tocode) + strlen (fromcode) + 2);
-
-  strcpy (key, tocode);
-  strcat (key, "\n"); /* hopefully no encoding names contain '\n' */
-  strcat (key, fromcode);
-
-  hash = hsh_hash_string (key);
-
-  node = hmapx_first_with_hash (&map, hash);
-
-  if (!node)
-    {
-      conv = iconv_open (tocode, fromcode);
-
-      /* I don't think it's safe to translate this string or to use messaging
-        as the convertors have not yet been set up */
-      if ( (iconv_t) -1 == conv && 0 != strcmp (tocode, fromcode))
-       {
-         const int err = errno;
-         fprintf (stderr,
-                  "Warning: "
-                  "cannot create a convertor for \"%s\" to \"%s\": %s\n",
-                  fromcode, tocode, strerror (err));
-       }
-
-      hmapx_insert (&map, conv, hash);
-    }
-  else
+  struct converter *converter;
+
+  hash = hsh_hash_string (tocode) ^ hsh_hash_string (fromcode);
+  HMAPX_FOR_EACH_WITH_HASH (converter, node, hash, &map)
+    if (!strcmp (tocode, converter->tocode)
+        && !strcmp (fromcode, converter->fromcode))
+      return converter->conv;
+
+  converter = xmalloc (sizeof *converter);
+  converter->tocode = xstrdup (tocode);
+  converter->fromcode = xstrdup (fromcode);
+  converter->conv = iconv_open (tocode, fromcode);
+  hmapx_insert (&map, converter, hash);
+  
+  /* I don't think it's safe to translate this string or to use messaging
+     as the convertors have not yet been set up */
+  if ( (iconv_t) -1 == converter->conv && 0 != strcmp (tocode, fromcode))
     {
-      conv = hmapx_node_data (node);
+      const int err = errno;
+      fprintf (stderr,
+               "Warning: "
+               "cannot create a convertor for \"%s\" to \"%s\": %s\n",
+               fromcode, tocode, strerror (err));
     }
 
-  return conv;
+  return converter->conv;
 }
 
 /* Return a string based on TEXT converted according to HOW.