[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[pre-lexer 21/21] data-in: Get rid of first_column, last_column argument
From: |
Ben Pfaff |
Subject: |
[pre-lexer 21/21] data-in: Get rid of first_column, last_column arguments. |
Date: |
Thu, 23 Sep 2010 21:20:57 -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.
---
perl-module/PSPP.xs | 13 +-
src/data/data-in.c | 431 ++++++++++++++-----------------
src/data/data-in.h | 10 +-
src/language/data-io/data-parser.c | 57 +++-
src/language/data-io/data-reader.c | 18 +-
src/language/data-io/data-reader.h | 8 +-
src/language/expressions/operations.def | 13 +-
src/language/lexer/value-parser.c | 10 +-
src/language/stats/flip.c | 2 +-
src/language/xforms/recode.c | 10 +-
src/libpspp/message.c | 2 +-
src/ui/gui/helper.c | 6 +-
src/ui/gui/psppire-data-store.c | 4 +-
src/ui/gui/text-data-import-dialog.c | 18 +-
src/ui/syntax-gen.c | 12 +-
15 files changed, 309 insertions(+), 305 deletions(-)
diff --git a/perl-module/PSPP.xs b/perl-module/PSPP.xs
index bf90d98..15d3b60 100644
--- a/perl-module/PSPP.xs
+++ b/perl-module/PSPP.xs
@@ -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;
diff --git a/src/data/data-in.c b/src/data/data-in.c
index de19d67..d36aefb 100644
--- a/src/data/data-in.c
+++ b/src/data/data-in.c
@@ -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;
}
/* 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;
}
/* 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;
}
-
/* 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
diff --git a/src/data/data-in.h b/src/data/data-in.h
index dbf2fa7..ceb023e 100644
--- a/src/data/data-in.h
+++ b/src/data/data-in.h
@@ -25,9 +25,13 @@
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);
diff --git a/src/language/data-io/data-parser.c
b/src/language/data-io/data-parser.c
index 800ae57..714b2a9 100644
--- a/src/language/data-io/data-parser.c
+++ b/src/language/data-io/data-parser.c
@@ -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);
diff --git a/src/language/data-io/data-reader.c
b/src/language/data-io/data-reader.c
index e9bcbfa..061505f 100644
--- a/src/language/data-io/data-reader.c
+++ b/src/language/data-io/data-reader.c
@@ -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;
}
/* BEGIN DATA...END DATA procedure. */
diff --git a/src/language/data-io/data-reader.h
b/src/language/data-io/data-reader.h
index 308701c..7f7355d 100644
--- a/src/language/data-io/data-reader.h
+++ b/src/language/data-io/data-reader.h
@@ -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 */
diff --git a/src/language/expressions/operations.def
b/src/language/expressions/operations.def
index b778325..0286acf 100644
--- a/src/language/expressions/operations.def
+++ b/src/language/expressions/operations.def
@@ -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;
}
diff --git a/src/language/lexer/value-parser.c
b/src/language/lexer/value-parser.c
index 8cbbab4..269d24b 100644
--- a/src/language/lexer/value-parser.c
+++ b/src/language/lexer/value-parser.c
@@ -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)
diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c
index 7390b08..7788186 100644
--- a/src/language/stats/flip.c
+++ b/src/language/stats/flip.c
@@ -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++)
{
diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c
index c9787b1..5cfad0e 100644
--- a/src/language/xforms/recode.c
+++ b/src/language/xforms/recode.c
@@ -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;
}
diff --git a/src/libpspp/message.c b/src/libpspp/message.c
index 8bd6af9..0ca2749 100644
--- a/src/libpspp/message.c
+++ b/src/libpspp/message.c
@@ -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;
diff --git a/src/ui/gui/helper.c b/src/ui/gui/helper.c
index b8936e6..1ad77bc 100644
--- a/src/ui/gui/helper.c
+++ b/src/ui/gui/helper.c
@@ -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;
}
diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c
index 7d26f56..7deb102 100644
--- a/src/ui/gui/psppire-data-store.c
+++ b/src/ui/gui/psppire-data-store.c
@@ -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);
diff --git a/src/ui/gui/text-data-import-dialog.c
b/src/ui/gui/text-data-import-dialog.c
index c9227ff..13c6d96 100644
--- a/src/ui/gui/text-data-import-dialog.c
+++ b/src/ui/gui/text-data-import-dialog.c
@@ -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
{
diff --git a/src/ui/syntax-gen.c b/src/ui/syntax-gen.c
index aae8c97..b49911f 100644
--- a/src/ui/syntax-gen.c
+++ b/src/ui/syntax-gen.c
@@ -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));
--
1.7.1
- [pre-lexer 20/21] data-in: Make data_in() parameters more uniform., (continued)
- [pre-lexer 20/21] data-in: Make data_in() parameters more uniform., Ben Pfaff, 2010/09/24
- [pre-lexer 02/21] i18n: Use UTF8 macro instead of "UTF8" literal string., Ben Pfaff, 2010/09/24
- [pre-lexer 09/21] lexer: Improve translatability of lex_error()., Ben Pfaff, 2010/09/24
- [pre-lexer 15/21] message: Consistently initialize locator; use 0 for "no line number"., Ben Pfaff, 2010/09/24
- [pre-lexer 06/21] AGGREGATE: Simplify code., Ben Pfaff, 2010/09/24
- [pre-lexer 17/21] calendar: Use sensible error reporting in calendar_gregorian_to_offset()., Ben Pfaff, 2010/09/24
- [pre-lexer 16/21] message: Add column range to struct msg_locator., Ben Pfaff, 2010/09/24
- [pre-lexer 05/21] PERMISSIONS: Add missing check for string token., Ben Pfaff, 2010/09/24
- [pre-lexer 10/21] lexer: Remove DUMP_TOKENS debugging feature., Ben Pfaff, 2010/09/24
- [pre-lexer 18/21] data-in: Eliminate "implied_decimals" parameter from data_in()., Ben Pfaff, 2010/09/24
- [pre-lexer 21/21] data-in: Get rid of first_column, last_column arguments.,
Ben Pfaff <=
- [pre-lexer 07/21] HOST: Use more modern syntax., Ben Pfaff, 2010/09/24
- Re: [pre-lexer 00/21] preparation for work on lexer, John Darrington, 2010/09/24