data-in: Get rid of first_column, last_column arguments.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 24 Sep 2010 04:03:36 +0000 (21:03 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 24 Sep 2010 04:13:31 +0000 (21:13 -0700)
Most callers can't provide this arguments, and so in the interest of
making the data_in() interface simpler, it seems better to put the
callers in charge of dealing with error messages, since they better
know their own context.

15 files changed:
perl-module/PSPP.xs
src/data/data-in.c
src/data/data-in.h
src/language/data-io/data-parser.c
src/language/data-io/data-reader.c
src/language/data-io/data-reader.h
src/language/expressions/operations.def
src/language/lexer/value-parser.c
src/language/stats/flip.c
src/language/xforms/recode.c
src/libpspp/message.c
src/ui/gui/helper.c
src/ui/gui/psppire-data-store.c
src/ui/gui/text-data-import-dialog.c
src/ui/syntax-gen.c

index bf90d986f327b811fb5f67822d7cf5c332b0c0ca..15d3b606cbecdab2aa76ae5324b347cc094e55fa 100644 (file)
@@ -654,9 +654,16 @@ CODE:
     if ( ifmt )
       {
        struct substring ss = ss_cstr (SvPV_nolen (sv));
-       if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0,
-                       case_data_rw (c, v), var_get_width (v),
-                       dict_get_encoding (sfi->dict)))
+       char *error;
+       bool ok;
+
+       error = data_in (ss, LEGACY_NATIVE, ifmt->type,
+                        case_data_rw (c, v), var_get_width (v),
+                        dict_get_encoding (sfi->dict));
+        ok = error == NULL;
+        free (error);
+
+       if ( !ok )
          {
            RETVAL = 0;
            goto finish;
index de19d670484fd8344de1351497684386ca0d3f16..d36aefb5e8144bb1e2207fb613d2ec6d897b63c2 100644 (file)
@@ -38,7 +38,6 @@
 #include "libpspp/i18n.h"
 #include "libpspp/integer-format.h"
 #include "libpspp/legacy-encoding.h"
-#include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "libpspp/str.h"
 #include "settings.h"
@@ -60,19 +59,13 @@ struct data_in
 
     union value *output;        /* Destination. */
     int width;                  /* Output width. */
-
-    int first_column;          /* First column of field; 0 if inapplicable. */
-    int last_column;           /* Last column. */
   };
 
-typedef bool data_in_parser_func (struct data_in *);
+typedef char *data_in_parser_func (struct data_in *);
 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
         static data_in_parser_func parse_##METHOD;
 #include "format.def"
 
-static void data_warning (const struct data_in *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-
 static void default_result (struct data_in *);
 static bool trim_spaces_and_check_missing (struct data_in *);
 
@@ -85,9 +78,9 @@ static int hexit_value (int c);
    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
+char *
 data_in (struct substring input, const char *input_encoding,
-         enum fmt_type format, int first_column, int last_column,
+         enum fmt_type format,
          union value *output, int width, const char *output_encoding)
 {
   static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
@@ -101,7 +94,7 @@ data_in (struct substring input, const char *input_encoding,
   enum fmt_category cat;
   const char *dest_encoding;
   char *s;
-  bool ok;
+  char *error;
 
   assert ((width != 0) == fmt_is_string (format));
 
@@ -110,13 +103,10 @@ data_in (struct substring input, const char *input_encoding,
   i.output = output;
   i.width = width;
 
-  i.first_column = first_column;
-  i.last_column = last_column;
-
   if (ss_is_empty (input))
     {
       default_result (&i);
-      return true;
+      return NULL;
     }
 
   cat = fmt_get_category (format);
@@ -161,13 +151,31 @@ data_in (struct substring input, const char *input_encoding,
       s = NULL;
     }
 
-  ok = handlers[i.format] (&i);
-  if (!ok)
+  error = handlers[i.format] (&i);
+  if (error != NULL)
     default_result (&i);
 
   free (s);
 
-  return ok;
+  return error;
+}
+
+bool
+data_in_msg (struct substring input, const char *input_encoding,
+             enum fmt_type format,
+             union value *output, int width, const char *output_encoding)
+{
+  char *error = data_in (input, input_encoding, format,
+                         output, width, output_encoding);
+  if (error != NULL)
+    {
+      msg (SW,_("Data is not valid as format %s: %s"),
+           fmt_name (format), error);
+      free (error);
+      return false;
+    }
+  else
+    return true;
 }
 
 static bool
@@ -266,7 +274,7 @@ data_in_imply_decimals (struct substring input, const char *input_encoding,
 /* Format parsers. */
 
 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
-static bool
+static char *
 parse_number (struct data_in *i)
 {
   const struct fmt_number_style *style =
@@ -285,7 +293,7 @@ parse_number (struct data_in *i)
 
   /* Trim spaces and check for missing value representation. */
   if (trim_spaces_and_check_missing (i))
-    return true;
+    return NULL;
 
   ds_init_empty (&tmp);
   ds_extend (&tmp, 64);
@@ -364,12 +372,13 @@ parse_number (struct data_in *i)
 
   if (!ss_is_empty (i->input))
     {
+      char *error;
       if (ds_is_empty (&tmp))
-        data_warning (i, _("Field contents are not numeric."));
+        error = xstrdup (_("Field contents are not numeric."));
       else
-        data_warning (i, _("Number followed by garbage."));
+        error = xstrdup (_("Number followed by garbage."));
       ds_destroy (&tmp);
-      return false;
+      return error;
     }
 
   /* Let c_strtod() do the conversion. */
@@ -378,35 +387,34 @@ parse_number (struct data_in *i)
   i->output->f = c_strtod (ds_cstr (&tmp), &tail);
   if (*tail != '\0')
     {
-      data_warning (i, _("Invalid numeric syntax."));
       errno = save_errno;
       ds_destroy (&tmp);
-      return false;
+      return xstrdup (_("Invalid numeric syntax."));
     }
   else if (errno == ERANGE)
     {
       if (fabs (i->output->f) > 1)
         {
-          data_warning (i, _("Too-large number set to system-missing."));
           i->output->f = SYSMIS;
+          ds_destroy (&tmp);
+          return xstrdup (_("Too-large number set to system-missing."));
         }
       else
         {
-          data_warning (i, _("Too-small number set to zero."));
           i->output->f = 0.0;
+          ds_destroy (&tmp);
+          return xstrdup (_("Too-small number set to zero."));
         }
     }
   else
-    {
-      errno = save_errno;
-    }
+    errno = save_errno;
 
   ds_destroy (&tmp);
-  return true;
+  return NULL;
 }
 
 /* Parses N format. */
-static bool
+static char *
 parse_N (struct data_in *i)
 {
   int c;
@@ -415,18 +423,15 @@ parse_N (struct data_in *i)
   while ((c = ss_get_char (&i->input)) != EOF)
     {
       if (!c_isdigit (c))
-        {
-          data_warning (i, _("All characters in field must be digits."));
-          return false;
-        }
+        return xstrdup (_("All characters in field must be digits."));
       i->output->f = i->output->f * 10.0 + (c - '0');
     }
 
-  return true;
+  return NULL;
 }
 
 /* Parses PIBHEX format. */
-static bool
+static char *
 parse_PIBHEX (struct data_in *i)
 {
   double n;
@@ -437,19 +442,16 @@ parse_PIBHEX (struct data_in *i)
   while ((c = ss_get_char (&i->input)) != EOF)
     {
       if (!c_isxdigit (c))
-        {
-          data_warning (i, _("Unrecognized character in field."));
-          return false;
-        }
+        return xstrdup (_("Unrecognized character in field."));
       n = n * 16.0 + hexit_value (c);
     }
 
   i->output->f = n;
-  return true;
+  return NULL;
 }
 
 /* Parses RBHEX format. */
-static bool
+static char *
 parse_RBHEX (struct data_in *i)
 {
   double d;
@@ -461,21 +463,15 @@ parse_RBHEX (struct data_in *i)
       int hi = ss_get_char (&i->input);
       int lo = ss_get_char (&i->input);
       if (lo == EOF)
-        {
-          data_warning (i, _("Field must have even length."));
-          return false;
-        }
+        return xstrdup (_("Field must have even length."));
       else if (!c_isxdigit (hi) || !c_isxdigit (lo))
-       {
-         data_warning (i, _("Field must contain only hex digits."));
-         return false;
-       }
+        return xstrdup (_("Field must contain only hex digits."));
       ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
     }
 
   i->output->f = d;
 
-  return true;
+  return NULL;
 }
 
 /* Digits for Z format. */
@@ -507,7 +503,7 @@ is_negative_z_digit (int c)
 }
 
 /* Parses Z format. */
-static bool
+static char *
 parse_Z (struct data_in *i)
 {
   struct string tmp;
@@ -519,7 +515,7 @@ parse_Z (struct data_in *i)
 
   /* Trim spaces and check for missing value representation. */
   if (trim_spaces_and_check_missing (i))
-    return true;
+    return NULL;
 
   ds_init_empty (&tmp);
   ds_extend (&tmp, 64);
@@ -545,18 +541,21 @@ parse_Z (struct data_in *i)
       else
         {
           ds_destroy (&tmp);
-          return false;
+          return xstrdup (_("Invalid zoned decimal syntax."));
         }
     }
 
   if (!ss_is_empty (i->input))
     {
+      char *error;
+
       if (ds_length (&tmp) == 1)
-        data_warning (i, _("Field contents are not numeric."));
+        error = xstrdup (_("Field contents are not numeric."));
       else
-        data_warning (i, _("Number followed by garbage."));
+        error = xstrdup (_("Number followed by garbage."));
+
       ds_destroy (&tmp);
-      return false;
+      return error;
     }
 
   /* Let c_strtod() do the conversion. */
@@ -567,24 +566,26 @@ parse_Z (struct data_in *i)
     {
       if (fabs (i->output->f) > 1)
         {
-          data_warning (i, _("Too-large number set to system-missing."));
           i->output->f = SYSMIS;
+          ds_destroy (&tmp);
+          return xstrdup (_("Too-large number set to system-missing."));
         }
       else
         {
-          data_warning (i, _("Too-small number set to zero."));
           i->output->f = 0.0;
+          ds_destroy (&tmp);
+          return xstrdup (_("Too-small number set to zero."));
         }
     }
   else
     errno = save_errno;
 
   ds_destroy (&tmp);
-  return true;
+  return NULL;
 }
 
 /* Parses IB format. */
-static bool
+static char *
 parse_IB (struct data_in *i)
 {
   size_t bytes;
@@ -604,17 +605,17 @@ parse_IB (struct data_in *i)
       i->output->f = -(double) -value;
     }
 
-  return true;
+  return NULL;
 }
 
 /* Parses PIB format. */
-static bool
+static char *
 parse_PIB (struct data_in *i)
 {
   i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
                               MIN (8, ss_length (i->input)));
 
-  return true;
+  return NULL;
 }
 
 /* Consumes the first character of S.  Stores its high 4 bits in
@@ -629,7 +630,7 @@ get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
 }
 
 /* Parses P format. */
-static bool
+static char *
 parse_P (struct data_in *i)
 {
   int high_nibble, low_nibble;
@@ -640,24 +641,24 @@ parse_P (struct data_in *i)
     {
       get_nibbles (&i->input, &high_nibble, &low_nibble);
       if (high_nibble > 9 || low_nibble > 9)
-        return false;
+        return xstrdup (_("Invalid syntax for P field."));
       i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
     }
 
   get_nibbles (&i->input, &high_nibble, &low_nibble);
   if (high_nibble > 9)
-    return false;
+    return xstrdup (_("Invalid syntax for P field."));
   i->output->f = (10 * i->output->f) + high_nibble;
   if (low_nibble < 10)
     i->output->f = (10 * i->output->f) + low_nibble;
   else if (low_nibble == 0xb || low_nibble == 0xd)
     i->output->f = -i->output->f;
 
-  return true;
+  return NULL;
 }
 
 /* Parses PK format. */
-static bool
+static char *
 parse_PK (struct data_in *i)
 {
   i->output->f = 0.0;
@@ -669,16 +670,16 @@ parse_PK (struct data_in *i)
       if (high_nibble > 9 || low_nibble > 9)
         {
           i->output->f = SYSMIS;
-          return true;
+          return NULL;
         }
       i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
     }
 
-  return true;
+  return NULL;
 }
 
 /* Parses RB format. */
-static bool
+static char *
 parse_RB (struct data_in *i)
 {
   enum float_format ff = settings_get_input_float_format ();
@@ -689,11 +690,11 @@ parse_RB (struct data_in *i)
   else
     i->output->f = SYSMIS;
 
-  return true;
+  return NULL;
 }
 
 /* Parses A format. */
-static bool
+static char *
 parse_A (struct data_in *i)
 {
   /* This is equivalent to buf_copy_rpad, except that we posibly
@@ -708,11 +709,11 @@ parse_A (struct data_in *i)
   if (dst_size > src_size)
     memset (&dst[src_size], ' ', dst_size - src_size);
 
-  return true;
+  return NULL;
 }
 
 /* Parses AHEX format. */
-static bool
+static char *
 parse_AHEX (struct data_in *i)
 {
   uint8_t *s = value_str_rw (i->output, i->width);
@@ -725,16 +726,10 @@ parse_AHEX (struct data_in *i)
       if (hi == EOF)
         break;
       else if (lo == EOF)
-        {
-          data_warning (i, _("Field must have even length."));
-          return false;
-        }
+        return xstrdup (_("Field must have even length."));
 
       if (!c_isxdigit (hi) || !c_isxdigit (lo))
-       {
-         data_warning (i, _("Field must contain only hex digits."));
-         return false;
-       }
+        return xstrdup (_("Field must contain only hex digits."));
 
       if (j < i->width)
         s[j] = hexit_value (hi) * 16 + hexit_value (lo);
@@ -742,7 +737,7 @@ parse_AHEX (struct data_in *i)
 
   memset (&s[j], ' ', i->width - j);
 
-  return true;
+  return NULL;
 }
 \f
 /* Date & time format components. */
@@ -759,7 +754,7 @@ enum time_sign
    MAX_DIGITS characters in I, storing the result into *RESULT.
    Returns true if successful, false if no integer was
    present. */
-static bool
+static char * WARN_UNUSED_RESULT
 parse_int (struct data_in *i, long *result, size_t max_digits)
 {
   struct substring head = ss_head (i->input, max_digits);
@@ -767,28 +762,25 @@ parse_int (struct data_in *i, long *result, size_t max_digits)
   if (n)
     {
       ss_advance (&i->input, n);
-      return true;
+      return NULL;
     }
   else
-    {
-      data_warning (i, _("Syntax error in date field."));
-      return false;
-    }
+    return xstrdup (_("Syntax error in date field."));
 }
 
 /* Parses a date integer between 1 and 31 from I, storing it into
    *DAY.
    Returns true if successful, false if no date was present. */
-static bool
+static char *
 parse_day (struct data_in *i, long *day)
 {
-  if (!parse_int (i, day, SIZE_MAX))
-    return false;
+  char *error = parse_int (i, day, SIZE_MAX);
+  if (error != NULL)
+    return error;
   if (*day >= 1 && *day <= 31)
-    return true;
+    return NULL;
 
-  data_warning (i, _("Day (%ld) must be between 1 and 31."), *day);
-  return false;
+  return xasprintf (_("Day (%ld) must be between 1 and 31."), *day);
 }
 
 /* Parses an integer from the beginning of I.
@@ -797,11 +789,12 @@ parse_day (struct data_in *i, long *day)
    If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
    time and sets *TIME_SIGN.  Otherwise, does not allow a sign.
    Returns true if successful, false if no integer was present. */
-static bool
+static char *
 parse_time_units (struct data_in *i, double seconds_per_unit,
                   enum time_sign *time_sign, double *time)
 
 {
+  char *error;
   long units;
 
   if (*time_sign == SIGN_NO_TIME)
@@ -814,28 +807,25 @@ parse_time_units (struct data_in *i, double seconds_per_unit,
           *time_sign = SIGN_POSITIVE;
         }
     }
-  if (!parse_int (i, &units, SIZE_MAX))
-    return false;
+  error = parse_int (i, &units, SIZE_MAX);
+  if (error != NULL)
+    return error;
   if (units < 0)
-    {
-      data_warning (i, _("Syntax error in date field."));
-      return false;
-    }
+    return xstrdup (_("Syntax error in date field."));
   *time += units * seconds_per_unit;
-  return true;
+  return NULL;
 }
 
 /* Parses a data delimiter from the beginning of I.
    Returns true if successful, false if no delimiter was
    present. */
-static bool
+static char *
 parse_date_delimiter (struct data_in *i)
 {
   if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
-    return true;
+    return NULL;
 
-  data_warning (i, _("Delimiter expected between fields in date."));
-  return false;
+  return xstrdup (_("Delimiter expected between fields in date."));
 }
 
 /* Parses spaces at the beginning of I. */
@@ -876,15 +866,16 @@ match_name (struct substring token, const char *const *names, long *output)
 /* Parses a month name or number from the beginning of I,
    storing the month (in range 1...12) into *MONTH.
    Returns true if successful, false if no month was present. */
-static bool
+static char *
 parse_month (struct data_in *i, long *month)
 {
   if (c_isdigit (ss_first (i->input)))
     {
-      if (!parse_int (i, month, SIZE_MAX))
-       return false;
+      char *error = parse_int (i, month, SIZE_MAX);
+      if (error != NULL)
+       return error;
       if (*month >= 1 && *month <= 12)
-        return true;
+        return NULL;
     }
   else
     {
@@ -905,22 +896,22 @@ parse_month (struct data_in *i, long *month)
       struct substring token = parse_name_token (i);
       if (match_name (ss_head (token, 3), english_names, month)
           || match_name (ss_head (token, 4), roman_names, month))
-        return true;
+        return NULL;
     }
 
-  data_warning (i, _("Unrecognized month format.  Months may be specified "
-                     "as Arabic or Roman numerals or as at least 3 letters "
-                     "of their English names."));
-  return false;
+  return xstrdup (_("Unrecognized month format.  Months may be specified "
+                    "as Arabic or Roman numerals or as at least 3 letters "
+                    "of their English names."));
 }
 
 /* Parses a year of at most MAX_DIGITS from the beginning of I,
    storing a "4-digit" year into *YEAR. */
-static bool
+static char *
 parse_year (struct data_in *i, long *year, size_t max_digits)
 {
-  if (!parse_int (i, year, max_digits))
-    return false;
+  char *error = parse_int (i, year, max_digits);
+  if (error != NULL)
+    return error;
 
   if (*year >= 0 && *year <= 99)
     {
@@ -933,28 +924,26 @@ parse_year (struct data_in *i, long *year, size_t max_digits)
         *year += epoch_century + 100;
     }
   if (*year >= 1582 || *year <= 19999)
-    return true;
+    return NULL;
 
-  data_warning (i, _("Year (%ld) must be between 1582 and 19999."), *year);
-  return false;
+  return xasprintf (_("Year (%ld) must be between 1582 and 19999."), *year);
 }
 
 /* Returns true if input in I has been exhausted,
    false otherwise. */
-static bool
+static char *
 parse_trailer (struct data_in *i)
 {
   if (ss_is_empty (i->input))
-    return true;
+    return NULL;
 
-  data_warning (i, _("Trailing garbage `%.*s' following date."),
-              (int) ss_length (i->input), ss_data (i->input));
-  return false;
+  return xasprintf (_("Trailing garbage `%.*s' following date."),
+                    (int) ss_length (i->input), ss_data (i->input));
 }
 
 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
    Returns true if successful, false on failure. */
-static bool
+static char *
 parse_yday (struct data_in *i, long *yday)
 {
   struct substring num_s;
@@ -962,98 +951,92 @@ parse_yday (struct data_in *i, long *yday)
 
   ss_get_chars (&i->input, 3, &num_s);
   if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
-    {
-      data_warning (i, _("Julian day must have exactly three digits."));
-      return false;
-    }
+    return xstrdup (_("Julian day must have exactly three digits."));
   else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
-    {
-      data_warning (i, _("Julian day (%ld) must be between 1 and 366."), num);
-      return false;
-    }
+    return xasprintf (_("Julian day (%ld) must be between 1 and 366."), num);
 
   *yday = num;
-  return true;
+  return NULL;
 }
 
 /* Parses a quarter-of-year integer between 1 and 4 from I.
    Stores the corresponding month into *MONTH.
    Returns true if successful, false if no quarter was present. */
-static bool
+static char *
 parse_quarter (struct data_in *i, long int *month)
 {
   long quarter;
+  char *error;
 
-  if (!parse_int (i, &quarter, SIZE_MAX))
-    return false;
+  error = parse_int (i, &quarter, SIZE_MAX);
+  if (error != NULL)
+    return error;
   if (quarter >= 1 && quarter <= 4)
     {
       *month = (quarter - 1) * 3 + 1;
-      return true;
+      return NULL;
     }
 
-  data_warning (i, _("Quarter (%ld) must be between 1 and 4."), quarter);
-  return false;
+  return xasprintf (_("Quarter (%ld) must be between 1 and 4."), quarter);
 }
 
 /* Parses a week-of-year integer between 1 and 53 from I,
    Stores the corresponding year-of-day into *YDAY.
    Returns true if successful, false if no week was present. */
-static bool
+static char *
 parse_week (struct data_in *i, long int *yday)
 {
+  char *error;
   long week;
 
-  if (!parse_int (i, &week, SIZE_MAX))
-    return false;
+  error = parse_int (i, &week, SIZE_MAX);
+  if (error != NULL)
+    return error;
   if (week >= 1 && week <= 53)
     {
       *yday = (week - 1) * 7 + 1;
-      return true;
+      return NULL;
     }
 
-  data_warning (i, _("Week (%ld) must be between 1 and 53."), week);
-  return false;
+  return xasprintf (_("Week (%ld) must be between 1 and 53."), week);
 }
 
 /* Parses a time delimiter from the beginning of I.
    Returns true if successful, false if no delimiter was
    present. */
-static bool
+static char *
 parse_time_delimiter (struct data_in *i)
 {
   if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
-    return true;
+    return NULL;
 
-  data_warning (i, _("Delimiter expected between fields in time."));
-  return false;
+  return xstrdup (_("Delimiter expected between fields in time."));
 }
 
 /* Parses minutes and optional seconds from the beginning of I.
    The time is converted into seconds, which are added to
    *TIME.
    Returns true if successful, false if an error was found. */
-static bool
+static char *
 parse_minute_second (struct data_in *i, double *time)
 {
   long minute;
   char buf[64];
+  char *error;
   char *cp;
 
   /* Parse minutes. */
-  if (!parse_int (i, &minute, SIZE_MAX))
-    return false;
+  error = parse_int (i, &minute, SIZE_MAX);
+  if (error != NULL)
+    return error;
   if (minute < 0 || minute > 59)
-    {
-      data_warning (i, _("Minute (%ld) must be between 0 and 59."), minute);
-      return false;
-    }
+    return xasprintf (_("Minute (%ld) must be between 0 and 59."), minute);
   *time += 60. * minute;
 
   /* Check for seconds. */
   if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
       || !c_isdigit (ss_first (i->input)))
-   return true;
+   return NULL;
 
   /* Parse seconds. */
   cp = buf;
@@ -1067,13 +1050,13 @@ parse_minute_second (struct data_in *i, double *time)
 
   *time += strtod (buf, NULL);
 
-  return true;
+  return NULL;
 }
 
 /* Parses a weekday name from the beginning of I,
    storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
    Returns true if successful, false if an error was found. */
-static bool
+static char *
 parse_weekday (struct data_in *i, long *weekday)
 {
   static const char *const weekday_names[] =
@@ -1085,51 +1068,53 @@ parse_weekday (struct data_in *i, long *weekday)
   struct substring token = parse_name_token (i);
   bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
   if (!ok)
-    data_warning (i, _("Unrecognized weekday name.  At least the first two "
-                       "letters of an English weekday name must be "
-                       "specified."));
-  return ok;
+    return xstrdup (_("Unrecognized weekday name.  At least the first two "
+                      "letters of an English weekday name must be "
+                      "specified."));
+  return NULL;
 }
 \f
 /* Date & time formats. */
 
 /* Parses WKDAY format. */
-static bool
+static char *
 parse_WKDAY (struct data_in *i)
 {
   long weekday;
+  char *error;
 
   if (trim_spaces_and_check_missing (i))
-    return true;
+    return NULL;
 
-  if (!parse_weekday (i, &weekday)
-      || !parse_trailer (i))
-    return false;
+  error = parse_weekday (i, &weekday);
+  if (error == NULL)
+    error = parse_trailer (i);
 
   i->output->f = weekday;
-  return true;
+  return error;
 }
 
 /* Parses MONTH format. */
-static bool
+static char *
 parse_MONTH (struct data_in *i)
 {
   long month;
+  char *error;
 
   if (trim_spaces_and_check_missing (i))
-    return true;
+    return NULL;
 
-  if (!parse_month (i, &month)
-      || !parse_trailer (i))
-    return false;
+  error = parse_month (i, &month);
+  if (error == NULL)
+    error = parse_trailer (i);
 
   i->output->f = month;
-  return true;
+  return error;
 }
 
 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
    DATETIME, TIME and DTIME formats. */
-static bool
+static char *
 parse_date (struct data_in *i)
 {
   long int year = INT_MIN;
@@ -1141,28 +1126,27 @@ parse_date (struct data_in *i)
 
   const char *template = fmt_date_template (i->format);
   size_t template_width = strlen (template);
+  char *error;
 
   if (trim_spaces_and_check_missing (i))
-    return true;
+    return NULL;
 
   while (*template != '\0')
     {
       unsigned char ch = *template;
       int count = 1;
-      bool ok;
 
       while (template[count] == ch)
         count++;
       template += count;
 
-      ok = true;
       switch (ch)
         {
         case 'd':
-          ok = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
+          error = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
           break;
         case 'm':
-          ok = parse_month (i, &month);
+          error = parse_month (i, &month);
           break;
         case 'y':
           {
@@ -1176,50 +1160,51 @@ parse_date (struct data_in *i)
                 else
                   max_digits = 2;
               }
-            ok = parse_year (i, &year, max_digits);
+            error = parse_year (i, &year, max_digits);
           }
           break;
         case 'q':
-          ok = parse_quarter (i, &month);
+          error = parse_quarter (i, &month);
           break;
         case 'w':
-          ok = parse_week (i, &yday);
+          error = parse_week (i, &yday);
           break;
         case 'D':
-          ok = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
+          error = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
           break;
         case 'H':
-          ok = parse_time_units (i, 60. * 60., &time_sign, &time);
+          error = parse_time_units (i, 60. * 60., &time_sign, &time);
           break;
         case 'M':
-          ok = parse_minute_second (i, &time);
+          error = parse_minute_second (i, &time);
           break;
         case '-':
         case '/':
         case '.':
         case 'X':
-          ok = parse_date_delimiter (i);
+          error = parse_date_delimiter (i);
           break;
         case ':':
-          ok = parse_time_delimiter (i);
+          error = parse_time_delimiter (i);
         case ' ':
           parse_spaces (i);
+          error = NULL;
           break;
         default:
           assert (count == 1);
           if (!ss_match_char (&i->input, c_toupper (ch))
               && !ss_match_char (&i->input, c_tolower (ch)))
-            {
-              data_warning (i, _("`%c' expected in date field."), ch);
-              return false;
-            }
+            error = xasprintf (_("`%c' expected in date field."), ch);
+          else
+            error = NULL;
           break;
         }
-      if (!ok)
-        return false;
+      if (error != NULL)
+        return error;
     }
-  if (!parse_trailer (i))
-    return false;
+  error = parse_trailer (i);
+  if (error != NULL)
+    return error;
 
   if (year != INT_MIN)
     {
@@ -1228,50 +1213,18 @@ parse_date (struct data_in *i)
 
       ofs = calendar_gregorian_to_offset (year, month, day, &error);
       if (ofs == SYSMIS)
-        {
-          data_warning (i, "%s", error);
-          free (error);
-          return false;
-        }
+        return error;
       date = (yday - 1 + ofs) * 60. * 60. * 24.;
     }
   else
     date = 0.;
   i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
 
-  return true;
+  return NULL;
 }
-
 \f
 /* Utility functions. */
 
-/* Outputs FORMAT with as a warning for input I. */
-static void
-data_warning (const struct data_in *i, const char *format, ...)
-{
-  va_list args;
-  struct msg m;
-  struct string text;
-
-  ds_init_empty (&text);
-  ds_put_char (&text, '(');
-  ds_put_format (&text, _("%s field) "), fmt_name (i->format));
-
-  va_start (args, format);
-  ds_put_vformat (&text, format, args);
-  va_end (args);
-
-  m.category = MSG_C_DATA;
-  m.severity = MSG_S_WARNING;
-  m.text = ds_cstr (&text);
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = i->first_column;
-  m.where.last_column = i->last_column;
-
-  msg_emit (&m);
-}
-
 /* Sets the default result for I.
    For a numeric format, this is the value set on SET BLANKS
    (typically system-missing); for a string format, it is all
index dbf2fa7caa82f5bf9d5c841db9e590bbeeacb973..ceb023e99887a75028a7a6cf3c764face86357f0 100644 (file)
 union value;
 struct dictionary;
 
-bool data_in (struct substring input, const char *input_encoding,
-              enum fmt_type, int first_column, int last_column,
-              union value *output, int width, const char *output_encoding);
+char *data_in (struct substring input, const char *input_encoding,
+               enum fmt_type, 
+               union value *output, int width, const char *output_encoding);
+
+bool data_in_msg (struct substring input, const char *input_encoding,
+                  enum fmt_type,
+                  union value *output, int width, const char *output_encoding);
 
 void data_in_imply_decimals (struct substring input, const char *encoding,
                              enum fmt_type format, int d, union value *output);
index 800ae57b50db3e027a82396ce243e4604cf45f5f..714b2a952e32c8d96d29af7c958e6e2c64e40a79 100644 (file)
@@ -395,7 +395,6 @@ data_parser_parse (struct data_parser *parser, struct dfm_reader *reader,
       && dfm_get_percent_read (reader) >= parser->percent_cases)
     return false;
 
-  dfm_push (reader);
   if (parser->type == DP_DELIMITED)
     {
       if (parser->span)
@@ -405,7 +404,6 @@ data_parser_parse (struct data_parser *parser, struct dfm_reader *reader,
     }
   else
     retval = parse_fixed (parser, reader, c);
-  dfm_pop (reader);
 
   return retval;
 }
@@ -502,6 +500,25 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
   return true;
 }
 
+static void
+parse_error (const struct dfm_reader *reader, const struct field *field,
+             int first_column, int last_column, char *error)
+{
+  struct msg m;
+
+  m.category = MSG_C_DATA;
+  m.severity = MSG_S_WARNING;
+  m.where.file_name = CONST_CAST (char *, dfm_get_file_name (reader));
+  m.where.line_number = dfm_get_line_number (reader);
+  m.where.first_column = first_column;
+  m.where.last_column = last_column;
+  m.text = xasprintf (_("Data for variable %s is not valid as format %s: %s"),
+                      field->name, fmt_name (field->format.type), error);
+  msg_emit (&m);
+
+  free (error);
+}
+
 /* Reads a case from READER into C, parsing it according to
    fixed-format syntax rules in PARSER.
    Returns true if successful, false at end of file or on I/O error. */
@@ -536,13 +553,16 @@ parse_fixed (const struct data_parser *parser, struct dfm_reader *reader,
           struct substring s = ss_substr (line, f->first_column - 1,
                                           f->format.w);
           union value *value = case_data_rw_idx (c, f->case_idx);
-
-          data_in (s, input_encoding, f->format.type,
-                   f->first_column, f->first_column + f->format.w,
-                   value, fmt_var_width (&f->format), output_encoding);
-
-          data_in_imply_decimals (s, input_encoding, f->format.type,
-                                  f->format.d, value);
+          char *error = data_in (s, input_encoding, f->format.type,
+                                 value, fmt_var_width (&f->format),
+                                 output_encoding);
+
+          if (error == NULL)
+            data_in_imply_decimals (s, input_encoding, f->format.type,
+                                    f->format.d, value);
+          else
+            parse_error (reader, f, f->first_column,
+                         f->first_column + f->format.w, error);
         }
 
       dfm_forward_record (reader);
@@ -567,6 +587,7 @@ parse_delimited_span (const struct data_parser *parser,
     {
       struct substring s;
       int first_column, last_column;
+      char *error;
 
       /* Cut out a field and read in a new record if necessary. */
       while (!cut_field (parser, reader,
@@ -584,9 +605,11 @@ parse_delimited_span (const struct data_parser *parser,
            }
        }
 
-      data_in (s, input_encoding, f->format.type, first_column, last_column,
-               case_data_rw_idx (c, f->case_idx),
-               fmt_var_width (&f->format), output_encoding);
+      error = data_in (s, input_encoding, f->format.type,
+                       case_data_rw_idx (c, f->case_idx),
+                       fmt_var_width (&f->format), output_encoding);
+      if (error != NULL)
+        parse_error (reader, f, first_column, last_column, error);
     }
   ds_destroy (&tmp);
   return true;
@@ -612,6 +635,8 @@ parse_delimited_no_span (const struct data_parser *parser,
   for (f = parser->fields; f < end; f++)
     {
       int first_column, last_column;
+      char *error;
+
       if (!cut_field (parser, reader, &first_column, &last_column, &tmp, &s))
        {
          if (f < end - 1 && settings_get_undefined ())
@@ -625,9 +650,11 @@ parse_delimited_no_span (const struct data_parser *parser,
           goto exit;
        }
 
-      data_in (s, input_encoding, f->format.type, first_column, last_column,
-               case_data_rw_idx (c, f->case_idx),
-               fmt_var_width (&f->format), output_encoding);
+      error = data_in (s, input_encoding, f->format.type,
+                       case_data_rw_idx (c, f->case_idx),
+                       fmt_var_width (&f->format), output_encoding);
+      if (error != NULL)
+        parse_error (reader, f, first_column, last_column, error);
     }
 
   s = dfm_get_record (reader);
index e9bcbfa9dc38d6a77aaffc9ee0b7a06476d28bb9..061505f889075cf2ea66d5709c1bc1e5563ad344 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-2004, 2006, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -677,20 +677,16 @@ dfm_get_column (const struct dfm_reader *r, const char *p)
   return ds_pointer_to_position (&r->line, p) + 1;
 }
 
-/* Pushes the file name and line number on the fn/ln stack. */
-void
-dfm_push (struct dfm_reader *r)
+const char *
+dfm_get_file_name (const struct dfm_reader *r)
 {
-  if (r->fh != fh_inline_file ())
-    msg_push_msg_locator (&r->where);
+  return fh_get_referent (r->fh) == FH_REF_FILE ? r->where.file_name : NULL;
 }
 
-/* Pops the file name and line number from the fn/ln stack. */
-void
-dfm_pop (struct dfm_reader *r)
+int
+dfm_get_line_number (const struct dfm_reader *r)
 {
-  if (r->fh != fh_inline_file ())
-    msg_pop_msg_locator (&r->where);
+  return fh_get_referent (r->fh) == FH_REF_FILE ? r->where.line_number : -1;
 }
 \f
 /* BEGIN DATA...END DATA procedure. */
index 308701c253147d48863a01bdb159c002e5fbf52a..7f7355da07fef98725608c403ccc01e1790ff288 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -49,8 +49,8 @@ size_t dfm_column_start (const struct dfm_reader *);
 size_t dfm_columns_past_end (const struct dfm_reader *);
 size_t dfm_get_column (const struct dfm_reader *, const char *);
 
-/* File stack. */
-void dfm_push (struct dfm_reader *);
-void dfm_pop (struct dfm_reader *);
+/* Information. */
+const char *dfm_get_file_name (const struct dfm_reader *);
+int dfm_get_line_number (const struct dfm_reader *);
 
 #endif /* data-reader.h */
index b7783257cdd990548541ee68b60c638bcf0476e7..0286acf91e393d917a1259181165d4c8c88c8934 100644 (file)
@@ -581,8 +581,19 @@ string function RTRIM (string s, string c)
 function NUMBER (string s, ni_format f)
 {
   union value out;
-  data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, 0, 0, &out, 0, NULL);
+  char *error;
+
+  if (s.length > f->w)
+    s.length = f->w;
+  error = data_in (s, LEGACY_NATIVE, f->type, &out, 0, NULL);
+  if (error == NULL)
   data_in_imply_decimals (s, LEGACY_NATIVE, f->type, f->d, &out);
+  else
+    {
+      msg (SE, "Cannot parse \"%.*s\" as format %s: %s",
+           (int) s.length, s.string, fmt_name (f->type), error);
+      free (error);
+    }
   return out.f;
 }
 
index 8cbbab4c82bfa3d0e262d865d8975c72794c9bee..269d24bca48d04b13da5c7a054b08fcdb281d4fd 100644 (file)
@@ -103,9 +103,13 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
   else if (lex_is_string (lexer) && format != NULL)
     {
       union value v;
-      assert (! (fmt_get_category (*format) & ( FMT_CAT_STRING )));
-      data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE, *format, 0, 0,
-               &v, 0, NULL);
+
+      assert (fmt_get_category (*format) != FMT_CAT_STRING);
+
+      if (!data_in_msg (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE,
+                        *format, &v, 0, NULL))
+        return false;
+
       lex_get (lexer);
       *x = v.f;
       if (*x == SYSMIS)
index 7390b08c0a5fcd5fd84e355b0b5c74a58756e269..77881868b0c3fcc0fd3b8fa29ead25b117882b95 100644 (file)
@@ -407,7 +407,7 @@ flip_casereader_read (struct casereader *reader, void *flip_)
   c = case_create (casereader_get_proto (reader));
   encoding = dict_get_encoding (flip->dict);
   data_in (ss_cstr (flip->old_names.names[flip->cases_read]), encoding,
-           FMT_A, 0, 0, case_data_rw_idx (c, 0), 8, encoding);
+           FMT_A, case_data_rw_idx (c, 0), 8, encoding);
 
   for (i = 0; i < flip->n_cases; i++)
     {
index c9787b11bdfeaf3094b1650a76daa50dabedb76e..5cfad0ed766ec2376429c32b3dc1bbb83e212271 100644 (file)
@@ -629,11 +629,13 @@ find_src_string (struct recode_trns *trns, const uint8_t *value,
         case MAP_CONVERT:
           {
             union value uv;
+            char *error;
+
+            error = data_in (ss_buffer (CHAR_CAST_BUG (char *, value), width),
+                             LEGACY_NATIVE, FMT_F, &uv, 0, encoding);
+            match = error == NULL;
+            free (error);
 
-            msg_disable ();
-            match = data_in (ss_buffer (CHAR_CAST_BUG (char *, value), width),
-                             LEGACY_NATIVE, FMT_F, 0, 0, &uv, 0, encoding);
-            msg_enable ();
             out->value.f = uv.f;
             break;
           }
index 8bd6af956ddf55153df8cbbf11c4220f24a0c450..0ca2749d6713b4ec245bae604cdd2e00e7e66c36 100644 (file)
@@ -271,7 +271,7 @@ process_msg (const struct msg *m)
 void
 msg_emit (struct msg *m)
 {
-  if ( s_stream )
+  if ( s_stream && m->where.file_name == NULL )
     {
       struct msg_locator loc;
 
index b8936e6c3b091427521a81a209192207b953ccaf..1ad77bc96ebf0190a633ca02b70179970980e3fb 100644 (file)
@@ -97,10 +97,8 @@ text_to_value (const gchar *text,
     }
 
   value_init (val, width);
-  msg_disable ();
-  data_in (ss_cstr (text), UTF8, format->type, 0, 0, val, width,
-           dict_get_encoding (dict->dict));
-  msg_enable ();
+  free (data_in (ss_cstr (text), UTF8, format->type, val, width,
+                 dict_get_encoding (dict->dict)));
 
   return val;
 }
index 7d26f5629b67b3c0bb0da77f09f5963027c9e7e6..7deb1022868ac4e548e9773d1dd236bd1c3e60b0 100644 (file)
@@ -959,8 +959,8 @@ psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
                         FALSE);
   value_init (&value, width);
   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
-        && data_in (input, UTF8, fmt->type, 0, 0, &value, width,
-                    dict_get_encoding (dict->dict))
+        && data_in_msg (input, UTF8, fmt->type, &value, width,
+                        dict_get_encoding (dict->dict))
         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
   value_destroy (&value, width);
 
index c9227ff8549b9b99b107e2664bd0b85aa1cff242..13c6d96804e48903a72cf37e16699c0e788d0e3b 100644 (file)
@@ -1775,19 +1775,19 @@ parse_field (struct import_assistant *ia,
   tooltip = NULL;
   if (field.string != NULL)
     {
-      msg_disable ();
+      char *error;
 
-      if (!data_in (field, LEGACY_NATIVE, in->type, 0, 0, &val,
-                    var_get_width (var), dict_get_encoding (ia->formats.dict)))
+      error = data_in (field, LEGACY_NATIVE, in->type, &val,
+                       var_get_width (var),
+                       dict_get_encoding (ia->formats.dict));
+      if (error != NULL)
         {
-          char fmt_string[FMT_STRING_LEN_MAX + 1];
-          fmt_to_string (in, fmt_string);
-          tooltip = xasprintf (_("Field content `%.*s' cannot be parsed in "
-                                 "format %s."),
+          tooltip = xasprintf (_("Cannot parse field content `%.*s' as "
+                                 "format %s: %s"),
                                (int) field.length, field.string,
-                               fmt_string);
+                               fmt_name (in->type), error);
+          free (error);
         }
-      msg_enable ();
     }
   else
     {
index aae8c972f95ac324c1da897b02fb83be7794691a..b49911f5e8f06fd81a2726a1a0bc67b51e68f558 100644 (file)
@@ -147,16 +147,18 @@ syntax_gen_number (struct string *output,
           & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
     {
       union value v_in, v_out;
-      char *s;
+      char *s, *error;
       bool ok;
 
       v_in.f = number;
       s = data_out (&v_in, "FIXME",  format);
-      msg_disable ();
+
       /* FIXME: UTF8 encoded strings will fail here */
-      ok = data_in (ss_cstr (s), LEGACY_NATIVE,
-                    format->type, 0, 0, &v_out, 0, NULL);
-      msg_enable ();
+      error = data_in (ss_cstr (s), LEGACY_NATIVE,
+                       format->type, &v_out, 0, NULL);
+      ok = error == NULL;
+      free (error);
+
       if (ok && v_out.f == number)
         {
           syntax_gen_string (output, ss_cstr (s));