X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fmis-val.c;h=7aedc10b87e077e62d31e7e85f6ee9d73527d628;hb=9ca8b579de593d1df5b6ff45db222aac050ae700;hp=23d803fcf05e884ed33286d534625eb22caf9718;hpb=fcb9e49b2a2d57af7c001ae5d2eda9ac443ba36b;p=pspp-builds.git diff --git a/src/mis-val.c b/src/mis-val.c index 23d803fc..7aedc10b 100644 --- a/src/mis-val.c +++ b/src/mis-val.c @@ -14,390 +14,142 @@ 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ #include -#include +#include "error.h" #include #include "command.h" +#include "data-in.h" #include "error.h" #include "lexer.h" #include "magic.h" +#include "range-prs.h" #include "str.h" #include "var.h" -#include "debug-print.h" - -#if DEBUGGING -static void debug_print (); -#endif - -/* Variables on MIS VAL. */ -static struct variable **v; -static int nv; - -/* Type of the variables on MIS VAL. */ -static int type; - -/* Width of string variables on MIS VAL. */ -static size_t width; +#include "gettext.h" +#define _(msgid) gettext (msgid) -/* Items to fill-in var structs with. */ -static int miss_type; -static union value missing[3]; - -static int parse_varnames (void); -static int parse_numeric (void); -static int parse_alpha (void); +#include "debug-print.h" int cmd_missing_values (void) { - int i; + struct variable **v; + size_t nv; + + int retval = CMD_PART_SUCCESS_MAYBE; + bool deferred_errors = false; - lex_match_id ("MISSING"); - lex_match_id ("VALUES"); while (token != '.') { - if (!parse_varnames ()) - goto fail; + size_t i; - if (token != ')') - { - if ((type == NUMERIC && !parse_numeric ()) - || (type == ALPHA && !parse_alpha ())) - goto fail; - } - else - miss_type = MISSING_NONE; + if (!parse_variables (default_dict, &v, &nv, PV_NONE)) + goto done; - if (!lex_match (')')) - { - msg (SE, _("`)' expected after value specification.")); - goto fail; - } + if (!lex_match ('(')) + { + lex_error (_("expecting `('")); + goto done; + } for (i = 0; i < nv; i++) - { - v[i]->miss_type = miss_type; - memcpy (v[i]->missing, missing, sizeof v[i]->missing); - } + mv_init (&v[i]->miss, v[i]->width); + + if (!lex_match (')')) + { + struct missing_values mv; + + for (i = 0; i < nv; i++) + if (v[i]->type != v[0]->type) + { + const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i]; + const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0]; + msg (SE, _("Cannot mix numeric variables (e.g. %s) and " + "string variables (e.g. %s) within a single list."), + n->name, s->name); + goto done; + } + + if (v[0]->type == NUMERIC) + { + mv_init (&mv, 0); + while (!lex_match (')')) + { + double x, y; + bool ok; + + if (!parse_num_range (&x, &y, &v[0]->print)) + goto done; + + ok = (x == y + ? mv_add_num (&mv, x) + : mv_add_num_range (&mv, x, y)); + if (!ok) + deferred_errors = true; + + lex_match (','); + } + } + else + { + mv_init (&mv, MAX_SHORT_STRING); + while (!lex_match (')')) + { + if (!lex_force_string ()) + { + deferred_errors = true; + break; + } + + if (ds_length (&tokstr) > MAX_SHORT_STRING) + { + ds_truncate (&tokstr, MAX_SHORT_STRING); + msg (SE, _("Truncating missing value to short string " + "length (%d characters)."), + MAX_SHORT_STRING); + } + else + ds_rpad (&tokstr, MAX_SHORT_STRING, ' '); + + if (!mv_add_str (&mv, ds_data (&tokstr))) + deferred_errors = true; + + lex_get (); + lex_match (','); + } + } + + for (i = 0; i < nv; i++) + { + if (!mv_is_resizable (&mv, v[i]->width)) + { + msg (SE, _("Missing values provided are too long to assign " + "to variable of width %d."), + v[i]->width); + deferred_errors = true; + } + else + { + mv_copy (&v[i]->miss, &mv); + mv_resize (&v[i]->miss, v[i]->width); + } + } + } lex_match ('/'); free (v); + v = NULL; } - -#if 0 && DEBUGGING - debug_print (); -#endif - - return lex_end_of_command (); - -fail: - free (v); - return CMD_PART_SUCCESS_MAYBE; -} - -static int -parse_varnames (void) -{ - int i; - - if (!parse_variables (NULL, &v, &nv, PV_SAME_TYPE)) - return 0; - if (!lex_match ('(')) - { - msg (SE, _("`(' expected after variable name%s."), nv > 1 ? "s" : ""); - return 0; - } - - type = v[0]->type; - if (type == NUMERIC) - return 1; - - width = v[0]->width; - for (i = 1; i < nv; i++) - if (v[i]->type == ALPHA && v[i]->nv != 1) - { - msg (SE, _("Long string value specified.")); - return 0; - } - else if (v[i]->type == ALPHA && (int) width != v[i]->width) - { - msg (SE, _("Short strings must be of equal width.")); - return 0; - } - - return 1; -} - -/* Number or range? */ -enum - { - MV_NOR_NOTHING, /* Empty. */ - MV_NOR_NUMBER, /* Single number. */ - MV_NOR_RANGE /* Range. */ - }; - -/* A single value or a range. */ -struct num_or_range - { - int type; /* One of NOR_*. */ - double d[2]; /* d[0]=lower bound or value, d[1]=upper bound. */ - }; - -/* Parses something of the form , or LO[WEST] THRU , or - THRU HI[GHEST], or THRU , and sets the appropriate - members of NOR. Returns success. */ -static int -parse_num_or_range (struct num_or_range * nor) -{ - if (lex_match_id ("LO") || lex_match_id ("LOWEST")) - { - nor->type = MV_NOR_RANGE; - if (!lex_force_match_id ("THRU")) - return 0; - if (!lex_force_num ()) - return 0; - nor->d[0] = LOWEST; - nor->d[1] = tokval; - } - else if (token == T_NUM) - { - nor->d[0] = tokval; - lex_get (); - - if (lex_match_id ("THRU")) - { - nor->type = MV_NOR_RANGE; - if (lex_match_id ("HI") || lex_match_id ("HIGHEST")) - nor->d[1] = HIGHEST; - else - { - if (!lex_force_num ()) - return 0; - nor->d[1] = tokval; - lex_get (); - - if (nor->d[0] > nor->d[1]) - { - msg (SE, _("Range %g THRU %g is not valid because %g is " - "greater than %g."), - nor->d[0], nor->d[1], nor->d[0], nor->d[1]); - return 0; - } - } - } - else - nor->type = MV_NOR_NUMBER; - } - else - return -1; - - return 1; -} - -/* Parses a set of numeric missing values and stores them into - `missing[]' and `miss_type' global variables. */ -static int -parse_numeric (void) -{ - struct num_or_range set[3]; - int r; - - set[1].type = set[2].type = MV_NOR_NOTHING; - - /* Get first number or range. */ - r = parse_num_or_range (&set[0]); - if (r < 1) - { - if (r == -1) - msg (SE, _("Number or range expected.")); - return 0; - } - - /* Get second and third optional number or range. */ - lex_match (','); - r = parse_num_or_range (&set[1]); - if (r == 1) - { - lex_match (','); - r = parse_num_or_range (&set[2]); - } - if (r == 0) - return 0; - - /* Force range, if present, into set[0]. */ - if (set[1].type == MV_NOR_RANGE) - { - struct num_or_range t = set[1]; - set[1] = set[0]; - set[0] = t; - } - if (set[2].type == MV_NOR_RANGE) - { - struct num_or_range t = set[2]; - set[2] = set[0]; - set[0] = t; - } + retval = lex_end_of_command (); - /* Ensure there's not more than one range, or one range - plus one value. */ - if (set[1].type == MV_NOR_RANGE || set[2].type == MV_NOR_RANGE) - { - msg (SE, _("At most one range can exist in the missing values " - "for any one variable.")); - return 0; - } - if (set[0].type == MV_NOR_RANGE && set[2].type != MV_NOR_NOTHING) - { - msg (SE, _("At most one individual value can be missing along " - "with one range.")); - return 0; - } - - /* Set missing[] from set[]. */ - if (set[0].type == MV_NOR_RANGE) - { - int x = 0; - - if (set[0].d[0] == LOWEST) - { - miss_type = MISSING_LOW; - missing[x++].f = set[0].d[1]; - } - else if (set[0].d[1] == HIGHEST) - { - miss_type = MISSING_HIGH; - missing[x++].f = set[0].d[0]; - } - else - { - miss_type = MISSING_RANGE; - missing[x++].f = set[0].d[0]; - missing[x++].f = set[0].d[1]; - } - - if (set[1].type == MV_NOR_NUMBER) - { - miss_type += 3; - missing[x].f = set[1].d[0]; - } - } - else - { - if (set[0].type == MV_NOR_NUMBER) - { - miss_type = MISSING_1; - missing[0].f = set[0].d[0]; - } - if (set[1].type == MV_NOR_NUMBER) - { - miss_type = MISSING_2; - missing[1].f = set[1].d[0]; - } - if (set[2].type == MV_NOR_NUMBER) - { - miss_type = MISSING_3; - missing[2].f = set[2].d[0]; - } - } - - return 1; -} - -static int -parse_alpha (void) -{ - for (miss_type = 0; token == T_STRING && miss_type < 3; miss_type++) - { - if (ds_length (&tokstr) != width) - { - msg (SE, _("String is not of proper length.")); - return 0; - } - strncpy (missing[miss_type].s, ds_value (&tokstr), MAX_SHORT_STRING); - lex_get (); - lex_match (','); - } - if (miss_type < 1) - { - msg (SE, _("String expected.")); - return 0; - } - - return 1; -} - -/* Copy the missing values from variable SRC to variable DEST. */ -void -copy_missing_values (struct variable *dest, const struct variable *src) -{ - static const int n_values[MISSING_COUNT] = - { - 0, 1, 2, 3, 2, 1, 1, 3, 2, 2, - }; - - assert (dest->width == src->width); - assert (src->miss_type >= 0 && src->miss_type < MISSING_COUNT); - - { - int i; - - dest->miss_type = src->miss_type; - for (i = 0; i < n_values[src->miss_type]; i++) - if (src->type == NUMERIC) - dest->missing[i].f = src->missing[i].f; - else - memcpy (dest->missing[i].s, src->missing[i].s, src->width); - } + done: + free (v); + if (deferred_errors) + retval = CMD_PART_SUCCESS_MAYBE; + return retval; } - -/* Debug output. */ - -#if 0 && DEBUGGING -static void -debug_print (void) -{ - int i, j; - - puts (_("Missing value:")); - for (i = 0; i < nvar; i++) - { - printf (" %8s: ", var[i]->name); - if (var[i]->type == ALPHA && var[i]->nv > 1) - puts (_("(long string variable)")); - else - switch (var[i]->miss_type) - { - case MISSING_NONE: - printf (_("(no missing values)\n")); - break; - case MISSING_1: - case MISSING_2: - case MISSING_3: - printf ("(MISSING_%d)", var[i]->miss_type); - for (j = 0; j < var[i]->miss_type; j++) - if (var[i]->type == ALPHA) - printf (" \"%.*s\"", var[i]->width, var[i]->missing[j].s); - else - printf (" %.2g", var[i]->missing[j].f); - printf ("\n"); - break; - case MISSING_RANGE: - printf ("(MISSING_RANGE) %.2g THRU %.2g\n", - var[i]->missing[0].f, var[i]->missing[1].f); - break; - case MISSING_RANGE_1: - printf ("(MISSING_RANGE_1) %.2g THRU %.2g, %.2g\n", - var[i]->missing[0].f, var[i]->missing[1].f, - var[i]->missing[2].f); - break; - default: - printf (_("(!!!INTERNAL ERROR--%d!!!)\n"), var[i]->miss_type); - } - } -} -#endif /* DEBUGGING */