X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fdata-in.c;h=de19d670484fd8344de1351497684386ca0d3f16;hb=38993354cabb6fc37bb882be92f9a49e9aeb4c88;hp=f0e1d364ade781ae762068a2cebeaaf28d09082d;hpb=480a0746507ce73d26f528b56dc3ed80195096e0;p=pspp
diff --git a/src/data/data-in.c b/src/data/data-in.c
index f0e1d364ad..de19d67048 100644
--- a/src/data/data-in.c
+++ b/src/data/data-in.c
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 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 the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
#include
@@ -22,31 +20,34 @@
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include "calendar.h"
+#include "dictionary.h"
+#include "format.h"
#include "identifier.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#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"
#include "value.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "c-ctype.h"
-#include "minmax.h"
-#include "size_max.h"
-#include "xalloc.h"
+#include "gl/c-ctype.h"
+#include "gl/c-strtod.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -56,7 +57,6 @@ struct data_in
{
struct substring input; /* Source. */
enum fmt_type format; /* Input format. */
- int implied_decimals; /* Number of implied decimal places. */
union value *output; /* Destination. */
int width; /* Output width. */
@@ -65,118 +65,212 @@ struct data_in
int last_column; /* Last column. */
};
-/* Integer format used for IB and PIB input. */
-static enum integer_format input_integer_format = INTEGER_NATIVE;
-
-/* Floating-point format used for RB and RBHEX input. */
-static enum float_format input_float_format = FLOAT_NATIVE_DOUBLE;
-
typedef bool 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 vdata_warning (const struct data_in *, const char *, va_list)
- PRINTF_FORMAT (2, 0);
static void data_warning (const struct data_in *, const char *, ...)
PRINTF_FORMAT (2, 3);
-static void apply_implied_decimals (struct data_in *);
static void default_result (struct data_in *);
static bool trim_spaces_and_check_missing (struct data_in *);
static int hexit_value (int c);
-/* Parses the characters in INPUT according to FORMAT. Stores
- the parsed representation in OUTPUT, which has the given WIDTH
- (0 for a numeric field, otherwise the string width).
+/* Parses the characters in INPUT, which are encoded in the given
+ INPUT_ENCODING, according to FORMAT.
- If no decimal point is included in a numeric format, then
- IMPLIED_DECIMALS decimal places are implied. Specify 0 if no
- decimal places should be implied.
-
- If FIRST_COLUMN is nonzero, then it should be the 1-based
- column number of the first character in INPUT, used in error
- messages. */
+ 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,
- enum fmt_type format, int implied_decimals,
- int first_column, union value *output, int width)
+data_in (struct substring input, const char *input_encoding,
+ enum fmt_type format, int first_column, int last_column,
+ union value *output, int width, const char *output_encoding)
{
- static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
+ static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
{
#define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
#include "format.def"
};
struct data_in i;
+
+ enum fmt_category cat;
+ const char *dest_encoding;
+ char *s;
bool ok;
assert ((width != 0) == fmt_is_string (format));
- i.input = input;
i.format = format;
- i.implied_decimals = implied_decimals;
i.output = output;
i.width = width;
i.first_column = first_column;
- i.last_column = first_column + ss_length (input) - 1;
+ i.last_column = last_column;
- if (!ss_is_empty (i.input))
+ if (ss_is_empty (input))
{
- ok = handlers[i.format] (&i);
- if (!ok)
- default_result (&i);
+ default_result (&i);
+ return true;
+ }
+
+ cat = fmt_get_category (format);
+ if (cat & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL
+ | FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))
+ {
+ /* 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
{
- default_result (&i);
- ok = true;
+ 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
+ {
+ /* Use the final output encoding. */
+ dest_encoding = output_encoding;
+ }
}
+ 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);
+ if (!ok)
+ default_result (&i);
+
+ free (s);
+
return ok;
}
-/* Returns the integer format used for IB and PIB input. */
-enum integer_format
-data_in_get_integer_format (void)
+static bool
+number_has_implied_decimals (const char *s, enum fmt_type type)
{
- return input_integer_format;
-}
+ int decimal = settings_get_style (type)->decimal;
+ bool got_digit = false;
+ for (;;)
+ {
+ switch (*s)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ got_digit = true;
+ break;
-/* Sets the integer format used for IB and PIB input to
- FORMAT. */
-void
-data_in_set_integer_format (enum integer_format format)
-{
- input_integer_format = format;
+ case '+': case '-':
+ if (got_digit)
+ return false;
+ break;
+
+ case 'e': case 'E': case 'd': case 'D':
+ return false;
+
+ case '.': case ',':
+ if (*s == decimal)
+ return false;
+ break;
+
+ case '\0':
+ return true;
+
+ default:
+ break;
+ }
+
+ s++;
+ }
}
-/* Returns the floating-point format used for RB and RBHEX
- input. */
-enum float_format
-data_in_get_float_format (void)
+static bool
+has_implied_decimals (struct substring input, const char *input_encoding,
+ enum fmt_type format)
{
- return input_float_format;
+ bool retval;
+ char *s;
+
+ switch (format)
+ {
+ case FMT_F:
+ case FMT_COMMA:
+ case FMT_DOT:
+ case FMT_DOLLAR:
+ case FMT_PCT:
+ case FMT_E:
+ case FMT_Z:
+ break;
+
+ case FMT_N:
+ case FMT_IB:
+ case FMT_PIB:
+ case FMT_P:
+ case FMT_PK:
+ return true;
+
+ default:
+ return false;
+ }
+
+ s = recode_string (LEGACY_NATIVE, input_encoding,
+ ss_data (input), ss_length (input));
+ retval = (format == FMT_Z
+ ? strchr (s, '.') == NULL
+ : number_has_implied_decimals (s, format));
+ free (s);
+
+ return retval;
}
-/* Sets the floating-point format used for RB and RBHEX input to
- FORMAT. */
+/* In some cases, when no decimal point is explicitly included in numeric
+ input, its position is implied by the number of decimal places in the input
+ format. In such a case, this function may be called just after data_in().
+ Its arguments are a subset of that function's arguments plus D, the number
+ of decimal places associated with FORMAT.
+
+ If it is appropriate, this function modifies the numeric value in OUTPUT. */
void
-data_in_set_float_format (enum float_format format)
+data_in_imply_decimals (struct substring input, const char *input_encoding,
+ enum fmt_type format, int d, union value *output)
{
- input_float_format = format;
+ if (d > 0 && output->f != SYSMIS
+ && has_implied_decimals (input, input_encoding, format))
+ output->f /= pow (10., d);
}
-/* Format parsers. */
+/* Format parsers. */
/* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
static bool
parse_number (struct data_in *i)
{
- const struct fmt_number_style *style = fmt_get_style (i->format);
+ const struct fmt_number_style *style =
+ settings_get_style (i->format);
struct string tmp;
@@ -184,7 +278,10 @@ parse_number (struct data_in *i)
int save_errno;
char *tail;
- assert (fmt_get_category (i->format) != FMT_CAT_CUSTOM);
+ if (fmt_get_category (i->format) == FMT_CAT_CUSTOM)
+ {
+ style = settings_get_style (FMT_F);
+ }
/* Trim spaces and check for missing value representation. */
if (trim_spaces_and_check_missing (i))
@@ -192,28 +289,28 @@ parse_number (struct data_in *i)
ds_init_empty (&tmp);
ds_extend (&tmp, 64);
-
+
/* Prefix character may precede sign. */
- if (!ss_is_empty (style->prefix))
+ if (!ss_is_empty (style->prefix))
{
ss_match_char (&i->input, ss_first (style->prefix));
ss_ltrim (&i->input, ss_cstr (CC_SPACES));
}
/* Sign. */
- if (ss_match_char (&i->input, '-'))
+ if (ss_match_char (&i->input, '-'))
{
ds_put_char (&tmp, '-');
ss_ltrim (&i->input, ss_cstr (CC_SPACES));
}
- else
+ else
{
ss_match_char (&i->input, '+');
ss_ltrim (&i->input, ss_cstr (CC_SPACES));
}
/* Prefix character may follow sign. */
- if (!ss_is_empty (style->prefix))
+ if (!ss_is_empty (style->prefix))
{
ss_match_char (&i->input, ss_first (style->prefix));
ss_ltrim (&i->input, ss_cstr (CC_SPACES));
@@ -228,7 +325,7 @@ parse_number (struct data_in *i)
}
/* Decimal point and following digits. */
- if (ss_match_char (&i->input, style->decimal))
+ if (ss_match_char (&i->input, style->decimal))
{
explicit_decimals = true;
ds_put_char (&tmp, '.');
@@ -244,7 +341,7 @@ parse_number (struct data_in *i)
explicit_decimals = true;
ds_put_char (&tmp, 'e');
- if (strchr ("eEdD", ss_first (i->input)))
+ if (strchr ("eEdD", ss_first (i->input)))
{
ss_advance (&i->input, 1);
ss_match_char (&i->input, ' ');
@@ -275,10 +372,10 @@ parse_number (struct data_in *i)
return false;
}
- /* Let strtod() do the conversion. */
+ /* Let c_strtod() do the conversion. */
save_errno = errno;
errno = 0;
- i->output->f = strtod (ds_cstr (&tmp), &tail);
+ i->output->f = c_strtod (ds_cstr (&tmp), &tail);
if (*tail != '\0')
{
data_warning (i, _("Invalid numeric syntax."));
@@ -286,24 +383,22 @@ parse_number (struct data_in *i)
ds_destroy (&tmp);
return false;
}
- else if (errno == ERANGE)
+ else if (errno == ERANGE)
{
if (fabs (i->output->f) > 1)
{
data_warning (i, _("Too-large number set to system-missing."));
i->output->f = SYSMIS;
}
- else
+ else
{
data_warning (i, _("Too-small number set to zero."));
- i->output->f = 0.0;
+ i->output->f = 0.0;
}
}
- else
+ else
{
errno = save_errno;
- if (!explicit_decimals)
- apply_implied_decimals (i);
}
ds_destroy (&tmp);
@@ -317,17 +412,16 @@ parse_N (struct data_in *i)
int c;
i->output->f = 0;
- while ((c = ss_get_char (&i->input)) != EOF)
+ while ((c = ss_get_char (&i->input)) != EOF)
{
if (!c_isdigit (c))
{
data_warning (i, _("All characters in field must be digits."));
return false;
}
- i->output->f = i->output->f * 10.0 + (c - '0');
+ i->output->f = i->output->f * 10.0 + (c - '0');
}
- apply_implied_decimals (i);
return true;
}
@@ -349,7 +443,7 @@ parse_PIBHEX (struct data_in *i)
}
n = n * 16.0 + hexit_value (c);
}
-
+
i->output->f = n;
return true;
}
@@ -362,7 +456,7 @@ parse_RBHEX (struct data_in *i)
size_t j;
memset (&d, 0, sizeof d);
- for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
+ for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
{
int hi = ss_get_char (&i->input);
int lo = ss_get_char (&i->input);
@@ -376,11 +470,11 @@ parse_RBHEX (struct data_in *i)
data_warning (i, _("Field must contain only hex digits."));
return false;
}
- ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
+ ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
}
-
+
i->output->f = d;
-
+
return true;
}
@@ -389,7 +483,7 @@ static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
/* Returns true if C is a Z format digit, false otherwise. */
static bool
-is_z_digit (int c)
+is_z_digit (int c)
{
return c > 0 && strchr (z_digits, c) != NULL;
}
@@ -406,7 +500,7 @@ z_digit_value (int c)
/* Returns true if Z format digit C represents a negative value,
false otherwise. */
static bool
-is_negative_z_digit (int c)
+is_negative_z_digit (int c)
{
assert (is_z_digit (c));
return (strchr (z_digits, c) - z_digits) >= 20;
@@ -422,7 +516,7 @@ parse_Z (struct data_in *i)
bool got_dot = false;
bool got_final_digit = false;
-
+
/* Trim spaces and check for missing value representation. */
if (trim_spaces_and_check_missing (i))
return true;
@@ -436,22 +530,22 @@ parse_Z (struct data_in *i)
int c = ss_get_char (&i->input);
if (c_isdigit (c) && !got_final_digit)
ds_put_char (&tmp, c);
- else if (is_z_digit (c) && !got_final_digit)
+ else if (is_z_digit (c) && !got_final_digit)
{
ds_put_char (&tmp, z_digit_value (c) + '0');
if (is_negative_z_digit (c))
ds_data (&tmp)[0] = '-';
got_final_digit = true;
}
- else if (c == '.' && !got_dot)
+ else if (c == '.' && !got_dot)
{
ds_put_char (&tmp, '.');
- got_dot = true;
+ got_dot = true;
}
- else
+ else
{
ds_destroy (&tmp);
- return false;
+ return false;
}
}
@@ -465,29 +559,25 @@ parse_Z (struct data_in *i)
return false;
}
- /* Let strtod() do the conversion. */
+ /* Let c_strtod() do the conversion. */
save_errno = errno;
errno = 0;
- i->output->f = strtod (ds_cstr (&tmp), NULL);
- if (errno == ERANGE)
+ i->output->f = c_strtod (ds_cstr (&tmp), NULL);
+ if (errno == ERANGE)
{
if (fabs (i->output->f) > 1)
{
data_warning (i, _("Too-large number set to system-missing."));
i->output->f = SYSMIS;
}
- else
+ else
{
data_warning (i, _("Too-small number set to zero."));
- i->output->f = 0.0;
+ i->output->f = 0.0;
}
}
- else
- {
- errno = save_errno;
- if (!got_dot)
- apply_implied_decimals (i);
- }
+ else
+ errno = save_errno;
ds_destroy (&tmp);
return true;
@@ -502,20 +592,18 @@ parse_IB (struct data_in *i)
uint64_t sign_bit;
bytes = MIN (8, ss_length (i->input));
- value = integer_get (input_integer_format, ss_data (i->input), bytes);
+ value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
sign_bit = UINT64_C(1) << (8 * bytes - 1);
- if (!(value & sign_bit))
+ if (!(value & sign_bit))
i->output->f = value;
- else
+ else
{
/* Sign-extend to full 64 bits. */
- value -= sign_bit << 1;
- i->output->f = -(double) -value;
+ value -= sign_bit << 1;
+ i->output->f = -(double) -value;
}
- apply_implied_decimals (i);
-
return true;
}
@@ -523,10 +611,8 @@ parse_IB (struct data_in *i)
static bool
parse_PIB (struct data_in *i)
{
- i->output->f = integer_get (input_integer_format, ss_data (i->input),
+ i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
MIN (8, ss_length (i->input)));
-
- apply_implied_decimals (i);
return true;
}
@@ -534,7 +620,7 @@ parse_PIB (struct data_in *i)
/* Consumes the first character of S. Stores its high 4 bits in
HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
static void
-get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
+get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
{
int c = ss_get_char (s);
assert (c != EOF);
@@ -547,7 +633,7 @@ static bool
parse_P (struct data_in *i)
{
int high_nibble, low_nibble;
-
+
i->output->f = 0.0;
while (ss_length (i->input) > 1)
@@ -562,13 +648,11 @@ parse_P (struct data_in *i)
if (high_nibble > 9)
return false;
i->output->f = (10 * i->output->f) + high_nibble;
- if (low_nibble < 10)
+ 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;
- apply_implied_decimals (i);
-
return true;
}
@@ -590,8 +674,6 @@ parse_PK (struct data_in *i)
i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
}
- apply_implied_decimals (i);
-
return true;
}
@@ -599,9 +681,10 @@ parse_PK (struct data_in *i)
static bool
parse_RB (struct data_in *i)
{
- size_t size = float_get_size (input_float_format);
+ enum float_format ff = settings_get_input_float_format ();
+ size_t size = float_get_size (ff);
if (ss_length (i->input) >= size)
- float_convert (input_float_format, ss_data (i->input),
+ float_convert (ff, ss_data (i->input),
FLOAT_NATIVE_DOUBLE, &i->output->f);
else
i->output->f = SYSMIS;
@@ -613,8 +696,18 @@ parse_RB (struct data_in *i)
static bool
parse_A (struct data_in *i)
{
- buf_copy_rpad (i->output->s, i->width,
- ss_data (i->input), ss_length (i->input));
+ /* This is equivalent to buf_copy_rpad, except that we posibly
+ do a character set recoding in the middle. */
+ uint8_t *dst = value_str_rw (i->output, i->width);
+ size_t dst_size = i->width;
+ const char *src = ss_data (i->input);
+ size_t src_size = ss_length (i->input);
+
+ memcpy (dst, src, MIN (src_size, dst_size));
+
+ if (dst_size > src_size)
+ memset (&dst[src_size], ' ', dst_size - src_size);
+
return true;
}
@@ -622,9 +715,10 @@ parse_A (struct data_in *i)
static bool
parse_AHEX (struct data_in *i)
{
+ uint8_t *s = value_str_rw (i->output, i->width);
size_t j;
-
- for (j = 0; ; j++)
+
+ for (j = 0; ; j++)
{
int hi = ss_get_char (&i->input);
int lo = ss_get_char (&i->input);
@@ -641,20 +735,20 @@ parse_AHEX (struct data_in *i)
data_warning (i, _("Field must contain only hex digits."));
return false;
}
-
+
if (j < i->width)
- i->output->s[j] = hexit_value (hi) * 16 + hexit_value (lo);
+ s[j] = hexit_value (hi) * 16 + hexit_value (lo);
}
- memset (i->output->s + j, ' ', i->width - j);
-
+ memset (&s[j], ' ', i->width - j);
+
return true;
}
/* Date & time format components. */
/* Sign of a time value. */
-enum time_sign
+enum time_sign
{
SIGN_NO_TIME, /* No time yet encountered. */
SIGN_POSITIVE, /* Positive time. */
@@ -670,12 +764,12 @@ parse_int (struct data_in *i, long *result, size_t max_digits)
{
struct substring head = ss_head (i->input, max_digits);
size_t n = ss_get_long (&head, result);
- if (n)
+ if (n)
{
ss_advance (&i->input, n);
return true;
}
- else
+ else
{
data_warning (i, _("Syntax error in date field."));
return false;
@@ -710,19 +804,19 @@ parse_time_units (struct data_in *i, double seconds_per_unit,
{
long units;
- if (*time_sign == SIGN_NO_TIME)
+ if (*time_sign == SIGN_NO_TIME)
{
if (ss_match_char (&i->input, '-'))
*time_sign = SIGN_NEGATIVE;
else
{
ss_match_char (&i->input, '+');
- *time_sign = SIGN_POSITIVE;
+ *time_sign = SIGN_POSITIVE;
}
}
if (!parse_int (i, &units, SIZE_MAX))
return false;
- if (units < 0)
+ if (units < 0)
{
data_warning (i, _("Syntax error in date field."));
return false;
@@ -752,7 +846,7 @@ parse_spaces (struct data_in *i)
}
static struct substring
-parse_name_token (struct data_in *i)
+parse_name_token (struct data_in *i)
{
struct substring token;
ss_get_chars (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
@@ -765,17 +859,17 @@ parse_name_token (struct data_in *i)
exact matches (except for case) are allowed.
Returns true if successful, false otherwise. */
static bool
-match_name (struct substring token, const char **names, long *output)
+match_name (struct substring token, const char *const *names, long *output)
{
int i;
- for (i = 1; *names != NULL; i++)
+ for (i = 1; *names != NULL; i++)
if (ss_equals_case (ss_cstr (*names++), token))
{
*output = i;
return true;
}
-
+
return false;
}
@@ -792,16 +886,16 @@ parse_month (struct data_in *i, long *month)
if (*month >= 1 && *month <= 12)
return true;
}
- else
+ else
{
- static const char *english_names[] =
+ static const char *const english_names[] =
{
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec",
NULL,
};
-
- static const char *roman_names[] =
+
+ static const char *const roman_names[] =
{
"i", "ii", "iii", "iv", "v", "vi",
"vii", "viii", "ix", "x", "xi", "xii",
@@ -827,16 +921,16 @@ parse_year (struct data_in *i, long *year, size_t max_digits)
{
if (!parse_int (i, year, max_digits))
return false;
-
- if (*year >= 0 && *year <= 99)
+
+ if (*year >= 0 && *year <= 99)
{
- int epoch = get_epoch ();
+ int epoch = settings_get_epoch ();
int epoch_century = ROUND_DOWN (epoch, 100);
int epoch_offset = epoch - epoch_century;
if (*year >= epoch_offset)
*year += epoch_century;
else
- *year += epoch_century + 100;
+ *year += epoch_century + 100;
}
if (*year >= 1582 || *year <= 19999)
return true;
@@ -852,8 +946,8 @@ parse_trailer (struct data_in *i)
{
if (ss_is_empty (i->input))
return true;
-
- data_warning (i, _("Trailing garbage \"%.*s\" following date."),
+
+ data_warning (i, _("Trailing garbage `%.*s' following date."),
(int) ss_length (i->input), ss_data (i->input));
return false;
}
@@ -889,13 +983,13 @@ static bool
parse_quarter (struct data_in *i, long int *month)
{
long quarter;
-
+
if (!parse_int (i, &quarter, SIZE_MAX))
return false;
- if (quarter >= 1 && quarter <= 4)
+ if (quarter >= 1 && quarter <= 4)
{
*month = (quarter - 1) * 3 + 1;
- return true;
+ return true;
}
data_warning (i, _("Quarter (%ld) must be between 1 and 4."), quarter);
@@ -909,13 +1003,13 @@ static bool
parse_week (struct data_in *i, long int *yday)
{
long week;
-
+
if (!parse_int (i, &week, SIZE_MAX))
return false;
- if (week >= 1 && week <= 53)
+ if (week >= 1 && week <= 53)
{
*yday = (week - 1) * 7 + 1;
- return true;
+ return true;
}
data_warning (i, _("Week (%ld) must be between 1 and 53."), week);
@@ -930,14 +1024,14 @@ parse_time_delimiter (struct data_in *i)
{
if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
return true;
-
+
data_warning (i, _("Delimiter expected between fields in time."));
return false;
}
/* Parses minutes and optional seconds from the beginning of I.
The time is converted into seconds, which are added to
- *TIME.
+ *TIME.
Returns true if successful, false if an error was found. */
static bool
parse_minute_second (struct data_in *i, double *time)
@@ -949,10 +1043,10 @@ parse_minute_second (struct data_in *i, double *time)
/* Parse minutes. */
if (!parse_int (i, &minute, SIZE_MAX))
return false;
- if (minute < 0 || minute > 59)
+ if (minute < 0 || minute > 59)
{
data_warning (i, _("Minute (%ld) must be between 0 and 59."), minute);
- return false;
+ return false;
}
*time += 60. * minute;
@@ -965,12 +1059,12 @@ parse_minute_second (struct data_in *i, double *time)
cp = buf;
while (c_isdigit (ss_first (i->input)))
*cp++ = ss_get_char (&i->input);
- if (ss_match_char (&i->input, fmt_decimal_char (FMT_F)))
+ if (ss_match_char (&i->input, settings_get_decimal_char (FMT_F)))
*cp++ = '.';
while (c_isdigit (ss_first (i->input)))
*cp++ = ss_get_char (&i->input);
*cp = '\0';
-
+
*time += strtod (buf, NULL);
return true;
@@ -982,7 +1076,7 @@ parse_minute_second (struct data_in *i, double *time)
static bool
parse_weekday (struct data_in *i, long *weekday)
{
- static const char *weekday_names[] =
+ static const char *const weekday_names[] =
{
"su", "mo", "tu", "we", "th", "fr", "sa",
NULL,
@@ -999,19 +1093,6 @@ parse_weekday (struct data_in *i, long *weekday)
/* Date & time formats. */
-/* Helper function for passing to
- calendar_gregorian_to_offset. */
-static void
-calendar_error (void *i_, const char *format, ...)
-{
- struct data_in *i = i_;
- va_list args;
-
- va_start (args, format);
- vdata_warning (i, format, args);
- va_end (args);
-}
-
/* Parses WKDAY format. */
static bool
parse_WKDAY (struct data_in *i)
@@ -1069,11 +1150,11 @@ parse_date (struct data_in *i)
unsigned char ch = *template;
int count = 1;
bool ok;
-
- while (template[count] == ch)
+
+ while (template[count] == ch)
count++;
template += count;
-
+
ok = true;
switch (ch)
{
@@ -1083,19 +1164,19 @@ parse_date (struct data_in *i)
case 'm':
ok = parse_month (i, &month);
break;
- case 'y':
+ case 'y':
{
size_t max_digits;
if (!c_isalpha (*template))
max_digits = SIZE_MAX;
- else
+ else
{
if (ss_length (i->input) >= template_width + 2)
max_digits = 4;
else
- max_digits = 2;
+ max_digits = 2;
}
- ok = parse_year (i, &year, max_digits);
+ ok = parse_year (i, &year, max_digits);
}
break;
case 'q':
@@ -1140,12 +1221,18 @@ parse_date (struct data_in *i)
if (!parse_trailer (i))
return false;
- if (year != INT_MIN)
+ if (year != INT_MIN)
{
- double ofs = calendar_gregorian_to_offset (year, month, day,
- calendar_error, i);
+ char *error;
+ double ofs;
+
+ ofs = calendar_gregorian_to_offset (year, month, day, &error);
if (ofs == SYSMIS)
- return false;
+ {
+ data_warning (i, "%s", error);
+ free (error);
+ return false;
+ }
date = (yday - 1 + ofs) * 60. * 60. * 24.;
}
else
@@ -1154,58 +1241,37 @@ parse_date (struct data_in *i)
return true;
}
+
/* Utility functions. */
-/* Outputs FORMAT with the given ARGS as a warning for input
- I. */
+/* Outputs FORMAT with as a warning for input I. */
static void
-vdata_warning (const struct data_in *i, const char *format, va_list args)
+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, '(');
- if (i->first_column != 0)
- {
- if (i->first_column == i->last_column)
- ds_put_format (&text, _("column %d"), i->first_column);
- else
- ds_put_format (&text, _("columns %d-%d"),
- i->first_column, i->last_column);
- ds_put_cstr (&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_DATA;
- m.severity = MSG_WARNING;
+ 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);
}
-/* Outputs FORMAT with the given ARGS as a warning for input
- I. */
-static void
-data_warning (const struct data_in *i, const char *format, ...)
-{
- va_list args;
-
- va_start (args, format);
- vdata_warning (i, format, args);
- va_end (args);
-}
-
-/* Apply implied decimal places to output. */
-static void
-apply_implied_decimals (struct data_in *i)
-{
- if (i->implied_decimals > 0)
- i->output->f /= pow (10., i->implied_decimals);
-}
-
/* 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
@@ -1214,9 +1280,9 @@ static void
default_result (struct data_in *i)
{
if (fmt_is_string (i->format))
- memset (i->output->s, ' ', i->width);
+ memset (value_str_rw (i->output, i->width), ' ', i->width);
else
- i->output->f = get_blanks ();
+ i->output->f = settings_get_blanks ();
}
/* Trims leading and trailing spaces from I.
@@ -1224,7 +1290,7 @@ default_result (struct data_in *i)
sets the default result and returns true; otherwise, returns
false. */
static bool
-trim_spaces_and_check_missing (struct data_in *i)
+trim_spaces_and_check_missing (struct data_in *i)
{
ss_trim (&i->input, ss_cstr (" "));
if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))