Added a summary introduction to INSTALL, to try to make it less frightening to inexpe...
[pspp] / src / libpspp / i18n.c
index e2893f3cdc8a8bb58cecf01c6ccc1298b18c0a63..a3dc08a1ff26982171e8b9cf9c15543e74a2d506 100644 (file)
@@ -47,14 +47,15 @@ struct converter
     char *tocode;
     char *fromcode;
     iconv_t conv;
+    int error;
   };
 
 static char *default_encoding;
 static struct hmapx map;
 
 /* A wrapper around iconv_open */
-static iconv_t
-create_iconv (const char* tocode, const char* fromcode)
+static struct converter *
+create_iconv__ (const char* tocode, const char* fromcode)
 {
   size_t hash;
   struct hmapx_node *node;
@@ -65,23 +66,34 @@ create_iconv (const char* tocode, const char* fromcode)
   HMAPX_FOR_EACH_WITH_HASH (converter, node, hash, &map)
     if (!strcmp (tocode, converter->tocode)
         && !strcmp (fromcode, converter->fromcode))
-      return converter->conv;
+      return converter;
 
   converter = xmalloc (sizeof *converter);
   converter->tocode = xstrdup (tocode);
   converter->fromcode = xstrdup (fromcode);
   converter->conv = iconv_open (tocode, fromcode);
+  converter->error = converter->conv == (iconv_t) -1 ? errno : 0;
   hmapx_insert (&map, converter, hash);
 
+  return converter;
+}
+
+static iconv_t
+create_iconv (const char* tocode, const char* fromcode)
+{
+  struct converter *converter;
+
+  converter = create_iconv__ (tocode, fromcode);
+
   /* I don't think it's safe to translate this string or to use messaging
      as the converters have not yet been set up */
-  if ( (iconv_t) -1 == converter->conv && 0 != strcmp (tocode, fromcode))
+  if (converter->error && strcmp (tocode, fromcode))
     {
-      const int err = errno;
       fprintf (stderr,
                "Warning: "
                "cannot create a converter for `%s' to `%s': %s\n",
-               fromcode, tocode, strerror (err));
+               fromcode, tocode, strerror (converter->error));
+      converter->error = 0;
     }
 
   return converter->conv;
@@ -283,7 +295,7 @@ utf8_encoding_concat__ (const char *head, size_t head_len,
       else
         {
           size_t copy_len;
-          size_t prev;
+          ucs4_t prev;
           size_t ofs;
           int mblen;
 
@@ -324,7 +336,7 @@ utf8_encoding_concat__ (const char *head, size_t head_len,
         {
           bool correct_result = false;
           size_t copy_len;
-          size_t prev;
+          ucs4_t prev;
           size_t ofs;
           int mblen;
 
@@ -609,7 +621,8 @@ i18n_done (void)
     {
       free (cvtr->tocode);
       free (cvtr->fromcode);
-      iconv_close (cvtr->conv);
+      if (cvtr->conv != (iconv_t) -1)
+        iconv_close (cvtr->conv);
       free (cvtr);
     }
 
@@ -671,3 +684,61 @@ uc_name (ucs4_t uc, char buffer[16])
     snprintf (buffer, 16, "U+%04X", uc);
   return buffer;
 }
+\f
+bool
+get_encoding_info (struct encoding_info *e, const char *name)
+{
+  const struct substring in = SS_LITERAL_INITIALIZER (
+    "\t\n\v\f\r "
+    "!\"#$%&'()*+,-./0123456789:;<=>?@"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
+    "abcdefghijklmnopqrstuvwxyz{|}~");
+
+  struct substring out, cr, lf;
+  bool ok;
+
+  memset (e, 0, sizeof *e);
+
+  cr = recode_substring_pool (name, "UTF-8", ss_cstr ("\r"), NULL);
+  lf = recode_substring_pool (name, "UTF-8", ss_cstr ("\n"), NULL);
+  ok = cr.length >= 1 && cr.length <= MAX_UNIT && cr.length == lf.length;
+  if (!ok)
+    {
+      fprintf (stderr, "warning: encoding `%s' is not supported.\n", name);
+      ss_dealloc (&cr);
+      ss_dealloc (&lf);
+      ss_alloc_substring (&cr, ss_cstr ("\r"));
+      ss_alloc_substring (&lf, ss_cstr ("\n"));
+    }
+
+  e->unit = cr.length;
+  memcpy (e->cr, cr.string, e->unit);
+  memcpy (e->lf, lf.string, e->unit);
+
+  ss_dealloc (&cr);
+  ss_dealloc (&lf);
+
+  out = recode_substring_pool ("UTF-8", name, in, NULL);
+  e->is_ascii_compatible = ss_equals (in, out);
+  ss_dealloc (&out);
+
+  return ok;
+}
+
+bool
+is_encoding_ascii_compatible (const char *encoding)
+{
+  struct encoding_info e;
+
+  get_encoding_info (&e, encoding);
+  return e.is_ascii_compatible;
+}
+
+/* Returns true if iconv can convert ENCODING to and from UTF-8,
+   otherwise false. */
+bool
+is_encoding_supported (const char *encoding)
+{
+  return (create_iconv__ ("UTF-8", encoding)->conv != (iconv_t) -1
+          && create_iconv__ (encoding, "UTF-8")->conv != (iconv_t) -1);
+}