data-in: Make data_in() parameters more uniform.
[pspp] / src / data / data-in.c
index 673ebea0599b18f42a200c42fef4c9ae75743177..de19d670484fd8344de1351497684386ca0d3f16 100644 (file)
@@ -55,7 +55,6 @@
 /* Information about parsing one data field. */
 struct data_in
   {
-    const char *src_enc;        /* Encoding of source. */
     struct substring input;     /* Source. */
     enum fmt_type format;       /* Input format. */
 
@@ -66,8 +65,6 @@ struct data_in
     int last_column;           /* Last column. */
   };
 
-
-
 typedef bool data_in_parser_func (struct data_in *);
 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
         static data_in_parser_func parse_##METHOD;
@@ -82,17 +79,16 @@ static bool trim_spaces_and_check_missing (struct data_in *);
 static int hexit_value (int c);
 \f
 /* Parses the characters in INPUT, which are encoded in the given
-   ENCODING, according to FORMAT.  Stores the parsed
-   representation in OUTPUT, which the caller must have
-   initialized with the given WIDTH (0 for a numeric field,
-   otherwise the string width).
-   Iff FORMAT is a string format, then DICT must be a pointer
-   to the dictionary associated with OUTPUT.  Otherwise, DICT
-   may be null. */
+   INPUT_ENCODING, according to FORMAT.
+
+   Stores the parsed representation in OUTPUT, which the caller must have
+   initialized with the given WIDTH (0 for a numeric field, otherwise the
+   string width).  If FORMAT is FMT_A, then OUTPUT_ENCODING must specify the
+   correct encoding for OUTPUT (normally obtained via dict_get_encoding()). */
 bool
-data_in (struct substring input, const char *encoding,
+data_in (struct substring input, const char *input_encoding,
          enum fmt_type format, int first_column, int last_column,
-         const struct dictionary *dict, union value *output, int width)
+         union value *output, int width, const char *output_encoding)
 {
   static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
     {
@@ -102,7 +98,9 @@ data_in (struct substring input, const char *encoding,
 
   struct data_in i;
 
-  char *s = NULL;
+  enum fmt_category cat;
+  const char *dest_encoding;
+  char *s;
   bool ok;
 
   assert ((width != 0) == fmt_is_string (format));
@@ -114,7 +112,6 @@ data_in (struct substring input, const char *encoding,
 
   i.first_column = first_column;
   i.last_column = last_column;
-  i.src_enc = encoding;
 
   if (ss_is_empty (input))
     {
@@ -122,24 +119,46 @@ data_in (struct substring input, const char *encoding,
       return true;
     }
 
-  if (fmt_get_category (format) & ( FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL | FMT_CAT_LEGACY))
+  cat = fmt_get_category (format);
+  if (cat & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL
+             | FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))
     {
-      i.input = input;
+      /* We're going to parse these into numbers.  For this purpose we want to
+         deal with them in the local "C" encoding.  Any character not in that
+         encoding wouldn't be valid anyhow. */
+      dest_encoding = LEGACY_NATIVE;
+    }
+  else if (cat & (FMT_CAT_BINARY | FMT_CAT_LEGACY))
+    {
+      /* Don't recode these binary formats at all, since they are not text. */
+      dest_encoding = NULL;
     }
   else
     {
-      const char *dest_encoding;
-
-      if ( dict == NULL)
-       {
-         assert (0 == (fmt_get_category (format) & (FMT_CAT_BINARY | FMT_CAT_STRING)));
-         dest_encoding = LEGACY_NATIVE;
-       }
+      assert (cat == FMT_CAT_STRING);
+      if (format == FMT_AHEX)
+        {
+          /* We want the hex digits in the local "C" encoding, even though the
+             result may not be in that encoding. */
+          dest_encoding = LEGACY_NATIVE;
+        }
       else
-       dest_encoding = dict_get_encoding (dict);
+        {
+          /* Use the final output encoding. */
+          dest_encoding = output_encoding;
+        }
+    }
 
-      s = recode_string (dest_encoding, i.src_enc, ss_data (input), ss_length (input));
-      i.input = ss_cstr (s);
+  if (dest_encoding != NULL)
+    {
+      i.input = recode_substring_pool (dest_encoding, input_encoding, input,
+                                       NULL);
+      s = i.input.string;
+    }
+  else
+    {
+      i.input = input;
+      s = NULL;
     }
 
   ok = handlers[i.format] (&i);
@@ -147,6 +166,7 @@ data_in (struct substring input, const char *encoding,
     default_result (&i);
 
   free (s);
+
   return ok;
 }
 
@@ -189,7 +209,7 @@ number_has_implied_decimals (const char *s, enum fmt_type type)
 }
 
 static bool
-has_implied_decimals (struct substring input, const char *encoding,
+has_implied_decimals (struct substring input, const char *input_encoding,
                       enum fmt_type format)
 {
   bool retval;
@@ -217,7 +237,7 @@ has_implied_decimals (struct substring input, const char *encoding,
       return false;
     }
 
-  s = recode_string (LEGACY_NATIVE, encoding,
+  s = recode_string (LEGACY_NATIVE, input_encoding,
                      ss_data (input), ss_length (input));
   retval = (format == FMT_Z
             ? strchr (s, '.') == NULL
@@ -235,11 +255,11 @@ has_implied_decimals (struct substring input, const char *encoding,
 
    If it is appropriate, this function modifies the numeric value in OUTPUT. */
 void
-data_in_imply_decimals (struct substring input, const char *encoding,
+data_in_imply_decimals (struct substring input, const char *input_encoding,
                         enum fmt_type format, int d, union value *output)
 {
   if (d > 0 && output->f != SYSMIS
-      && has_implied_decimals (input, encoding, format))
+      && has_implied_decimals (input, input_encoding, format))
     output->f /= pow (10., d);
 }
 \f
@@ -710,11 +730,6 @@ parse_AHEX (struct data_in *i)
           return false;
         }
 
-      if (0 != strcmp (i->src_enc, LEGACY_NATIVE))
-        {
-          hi = legacy_to_native (i->src_enc, hi);
-          lo = legacy_to_native (i->src_enc, lo);
-        }
       if (!c_isxdigit (hi) || !c_isxdigit (lo))
        {
          data_warning (i, _("Field must contain only hex digits."));