From 4e8efdc4acb80fc1a3735228d29fca0cf86fee6d Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 19 Sep 2010 20:55:06 -0700 Subject: [PATCH] data-in: Eliminate "implied_decimals" parameter from data_in(). This parameter is usually 0, so break out the associated functionality into a new function that callers can use if they really need it. --- perl-module/PSPP.xs | 2 +- src/data/data-in.c | 172 ++++++++++++++++-------- src/data/data-in.h | 22 +-- src/language/data-io/data-parser.c | 25 ++-- src/language/expressions/operations.def | 3 +- src/language/lexer/value-parser.c | 4 +- src/language/stats/flip.c | 2 +- src/language/xforms/recode.c | 2 +- src/ui/gui/helper.c | 4 +- src/ui/gui/psppire-data-store.c | 5 +- src/ui/gui/text-data-import-dialog.c | 3 +- src/ui/syntax-gen.c | 2 +- 12 files changed, 150 insertions(+), 96 deletions(-) diff --git a/perl-module/PSPP.xs b/perl-module/PSPP.xs index ca3f873ae1..0e918a9fc2 100644 --- a/perl-module/PSPP.xs +++ b/perl-module/PSPP.xs @@ -654,7 +654,7 @@ CODE: if ( ifmt ) { struct substring ss = ss_cstr (SvPV_nolen (sv)); - if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0, + if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, sfi->dict, case_data_rw (c, v), var_get_width (v)) ) diff --git a/src/data/data-in.c b/src/data/data-in.c index 2b842b8dcd..673ebea059 100644 --- a/src/data/data-in.c +++ b/src/data/data-in.c @@ -20,34 +20,34 @@ #include #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 "format.h" -#include "dictionary.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "c-ctype.h" -#include "c-strtod.h" -#include "minmax.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) @@ -58,7 +58,6 @@ struct data_in const char *src_enc; /* Encoding of source. */ 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. */ @@ -77,7 +76,6 @@ typedef bool data_in_parser_func (struct data_in *); 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 *); @@ -90,24 +88,11 @@ static int hexit_value (int c); otherwise the string width). Iff FORMAT is a string format, then DICT must be a pointer to the dictionary associated with OUTPUT. Otherwise, DICT - may be null. - - 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 and LAST_COLUMN are nonzero, then they should - be the 1-based column number of the first and - one-past-the-last-character in INPUT, for use in error - messages. (LAST_COLUMN cannot always be calculated from - FIRST_COLUMN plus the length of the input because of the - possibility of escaped quotes in strings, etc.) */ + may be null. */ bool data_in (struct substring input, const char *encoding, - enum fmt_type format, int implied_decimals, - int first_column, int last_column, - const struct dictionary *dict, - union value *output, int width) + enum fmt_type format, int first_column, int last_column, + const struct dictionary *dict, union value *output, int width) { static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] = { @@ -123,7 +108,6 @@ data_in (struct substring input, const char *encoding, assert ((width != 0) == fmt_is_string (format)); i.format = format; - i.implied_decimals = implied_decimals; i.output = output; i.width = width; @@ -166,6 +150,98 @@ data_in (struct substring input, const char *encoding, return ok; } +static bool +number_has_implied_decimals (const char *s, enum fmt_type type) +{ + 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; + + 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++; + } +} + +static bool +has_implied_decimals (struct substring input, const char *encoding, + enum fmt_type 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, encoding, + ss_data (input), ss_length (input)); + retval = (format == FMT_Z + ? strchr (s, '.') == NULL + : number_has_implied_decimals (s, format)); + free (s); + + return retval; +} + +/* 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_imply_decimals (struct substring input, const char *encoding, + enum fmt_type format, int d, union value *output) +{ + if (d > 0 && output->f != SYSMIS + && has_implied_decimals (input, encoding, format)) + output->f /= pow (10., d); +} /* Format parsers. */ @@ -303,8 +379,6 @@ parse_number (struct data_in *i) else { errno = save_errno; - if (!explicit_decimals) - apply_implied_decimals (i); } ds_destroy (&tmp); @@ -328,7 +402,6 @@ parse_N (struct data_in *i) i->output->f = i->output->f * 10.0 + (c - '0'); } - apply_implied_decimals (i); return true; } @@ -484,11 +557,7 @@ parse_Z (struct data_in *i) } } else - { - errno = save_errno; - if (!got_dot) - apply_implied_decimals (i); - } + errno = save_errno; ds_destroy (&tmp); return true; @@ -515,8 +584,6 @@ parse_IB (struct data_in *i) i->output->f = -(double) -value; } - apply_implied_decimals (i); - return true; } @@ -527,8 +594,6 @@ 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))); - apply_implied_decimals (i); - return true; } @@ -568,8 +633,6 @@ parse_P (struct data_in *i) else if (low_nibble == 0xb || low_nibble == 0xd) i->output->f = -i->output->f; - apply_implied_decimals (i); - return true; } @@ -591,8 +654,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; } @@ -1165,6 +1226,7 @@ parse_date (struct data_in *i) return true; } + /* Utility functions. */ @@ -1195,14 +1257,6 @@ data_warning (const struct data_in *i, const char *format, ...) msg_emit (&m); } -/* 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 diff --git a/src/data/data-in.h b/src/data/data-in.h index 3ebd5933c4..af62b3aecb 100644 --- a/src/data/data-in.h +++ b/src/data/data-in.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -18,19 +18,19 @@ #define DATA_DATA_IN_H 1 #include -#include -#include -#include -#include -#include +#include "data/format.h" +#include "libpspp/legacy-encoding.h" +#include "libpspp/str.h" -enum fmt_type; union value; struct dictionary; + bool data_in (struct substring input, const char *encoding, - enum fmt_type, int implied_decimals, - int first_column, int last_column, - const struct dictionary *dict, - union value *output, int width); + enum fmt_type, int first_column, int last_column, + const struct dictionary *dict, + union value *output, int width); + +void data_in_imply_decimals (struct substring input, const char *encoding, + enum fmt_type format, int d, union value *output); #endif /* data/data-in.h */ diff --git a/src/language/data-io/data-parser.c b/src/language/data-io/data-parser.c index 2d7f9f4cd4..0802bba8c5 100644 --- a/src/language/data-io/data-parser.c +++ b/src/language/data-io/data-parser.c @@ -531,13 +531,18 @@ parse_fixed (const struct data_parser *parser, struct dfm_reader *reader, line = dfm_get_record (reader); for (; f < &parser->fields[parser->field_cnt] && f->record == row; f++) - data_in (ss_substr (line, f->first_column - 1, - f->format.w), - encoding, f->format.type, f->format.d, - f->first_column, f->first_column + f->format.w, - parser->dict, - case_data_rw_idx (c, f->case_idx), - fmt_var_width (&f->format)); + { + 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, encoding, f->format.type, + f->first_column, f->first_column + f->format.w, + parser->dict, value, fmt_var_width (&f->format)); + + data_in_imply_decimals (s, encoding, f->format.type, f->format.d, + value); + } dfm_forward_record (reader); } @@ -577,8 +582,7 @@ parse_delimited_span (const struct data_parser *parser, } } - data_in (s, encoding, f->format.type, 0, - first_column, last_column, + data_in (s, encoding, f->format.type, first_column, last_column, parser->dict, case_data_rw_idx (c, f->case_idx), fmt_var_width (&f->format)); @@ -619,8 +623,7 @@ parse_delimited_no_span (const struct data_parser *parser, goto exit; } - data_in (s, encoding, f->format.type, 0, - first_column, last_column, + data_in (s, encoding, f->format.type, first_column, last_column, parser->dict, case_data_rw_idx (c, f->case_idx), fmt_var_width (&f->format)); diff --git a/src/language/expressions/operations.def b/src/language/expressions/operations.def index c25f113c31..a945f7bf99 100644 --- a/src/language/expressions/operations.def +++ b/src/language/expressions/operations.def @@ -581,7 +581,8 @@ 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, f->d, 0, 0, NULL, &out, 0); + data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, 0, 0, NULL, &out, 0); + data_in_imply_decimals (s, LEGACY_NATIVE, f->type, f->d, &out); return out.f; } diff --git a/src/language/lexer/value-parser.c b/src/language/lexer/value-parser.c index 6fa4319a65..c2020d3658 100644 --- a/src/language/lexer/value-parser.c +++ b/src/language/lexer/value-parser.c @@ -104,8 +104,8 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format) { union value v; assert (! (fmt_get_category (*format) & ( FMT_CAT_STRING ))); - data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE, - *format, 0, 0, 0, NULL, &v, 0); + data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE, *format, 0, 0, + NULL, &v, 0); lex_get (lexer); *x = v.f; if (*x == SYSMIS) diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c index a0e1e28417..3474979aa2 100644 --- a/src/language/stats/flip.c +++ b/src/language/stats/flip.c @@ -405,7 +405,7 @@ flip_casereader_read (struct casereader *reader, void *flip_) c = case_create (casereader_get_proto (reader)); data_in (ss_cstr (flip->old_names.names[flip->cases_read]), dict_get_encoding (flip->dict), - FMT_A, 0, + FMT_A, 0, 0, flip->dict, case_data_rw_idx (c, 0), 8); diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index 8c44e14697..7f45865739 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -632,7 +632,7 @@ find_src_string (struct recode_trns *trns, const uint8_t *value, msg_disable (); match = data_in (ss_buffer (CHAR_CAST_BUG (char *, value), width), - LEGACY_NATIVE, FMT_F, 0, 0, 0, trns->dst_dict, + LEGACY_NATIVE, FMT_F, 0, 0, trns->dst_dict, &uv, 0); msg_enable (); out->value.f = uv.f; diff --git a/src/ui/gui/helper.c b/src/ui/gui/helper.c index 9a1172a4db..70e3c27394 100644 --- a/src/ui/gui/helper.c +++ b/src/ui/gui/helper.c @@ -98,9 +98,7 @@ text_to_value (const gchar *text, value_init (val, width); msg_disable (); - data_in (ss_cstr (text), UTF8, format->type, 0, 0, 0, - dict->dict, - val, width); + data_in (ss_cstr (text), UTF8, format->type, 0, 0, dict->dict, val, width); msg_enable (); return val; diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c index 9a59638fc8..fb9c81797f 100644 --- a/src/ui/gui/psppire-data-store.c +++ b/src/ui/gui/psppire-data-store.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2006, 2008, 2009 Free Software Foundation + Copyright (C) 2006, 2008, 2009, 2010 Free Software Foundation 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 @@ -959,8 +959,7 @@ 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, 0, - dict->dict, &value, width) + && data_in (input, UTF8, fmt->type, 0, 0, dict->dict, &value, width) && 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 3eda12f83a..070c4f6b3c 100644 --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@ -1777,8 +1777,7 @@ parse_field (struct import_assistant *ia, { msg_disable (); - if (!data_in (field, LEGACY_NATIVE, in->type, 0, 0, 0, - ia->formats.dict, + if (!data_in (field, LEGACY_NATIVE, in->type, 0, 0, ia->formats.dict, &val, var_get_width (var))) { char fmt_string[FMT_STRING_LEN_MAX + 1]; diff --git a/src/ui/syntax-gen.c b/src/ui/syntax-gen.c index 229e478161..b204fbf6f3 100644 --- a/src/ui/syntax-gen.c +++ b/src/ui/syntax-gen.c @@ -155,7 +155,7 @@ syntax_gen_number (struct string *output, msg_disable (); /* FIXME: UTF8 encoded strings will fail here */ ok = data_in (ss_cstr (s), LEGACY_NATIVE, - format->type, false, 0, 0, NULL, &v_out, 0); + format->type, 0, 0, NULL, &v_out, 0); msg_enable (); if (ok && v_out.f == number) { -- 2.30.2