X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdictionary%2Fvector.c;h=b0d696154b7f212a5c790a87efe7d69b1debd31a;hb=2be9bee9da6a2ce27715e58128569594319abfa2;hp=82870d9d447f8e881a80e202e47c26f8413d0b8d;hpb=81fff61a96bece351e381ad3fef8ab1248a952ba;p=pspp-builds.git diff --git a/src/language/dictionary/vector.c b/src/language/dictionary/vector.c index 82870d9d..b0d69615 100644 --- a/src/language/dictionary/vector.c +++ b/src/language/dictionary/vector.c @@ -1,207 +1,207 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2010, 2011 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 #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "data/dataset.h" +#include "data/format.h" +#include "data/dictionary.h" +#include "data/variable.h" +#include "language/command.h" +#include "language/lexer/format-parser.h" +#include "language/lexer/lexer.h" +#include "language/lexer/variable-parser.h" +#include "libpspp/assertion.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" + +#include "gl/intprops.h" +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) int -cmd_vector (void) +cmd_vector (struct lexer *lexer, struct dataset *ds) { - /* Just to be different, points to a set of null terminated strings - containing the names of the vectors to be created. The list - itself is terminated by a empty string. So a list of three - elements, A B C, would look like this: "A\0B\0C\0\0". */ - char *vecnames; + struct dictionary *dict = dataset_dict (ds); + struct pool *pool = pool_create (); - /* vecnames iterators. */ - char *cp, *cp2; - - /* Maximum allocated position for vecnames, plus one position. */ - char *endp = NULL; - - cp = vecnames = xmalloc (256); - endp = &vecnames[256]; do { + char **vectors; + size_t vector_cnt, vector_cap; + /* Get the name(s) of the new vector(s). */ - if (!lex_force_id ()) + if (!lex_force_id (lexer) + || !dict_id_is_valid (dict, lex_tokcstr (lexer), true)) return CMD_CASCADING_FAILURE; - while (token == T_ID) + + vectors = NULL; + vector_cnt = vector_cap = 0; + while (lex_token (lexer) == T_ID) { - if (cp + 16 > endp) + size_t i; + + if (dict_lookup_vector (dict, lex_tokcstr (lexer))) { - char *old_vecnames = vecnames; - vecnames = xrealloc (vecnames, endp - vecnames + 256); - cp = (cp - old_vecnames) + vecnames; - endp = (endp - old_vecnames) + vecnames + 256; + msg (SE, _("A vector named %s already exists."), + lex_tokcstr (lexer)); + goto fail; } - for (cp2 = cp; cp2 < cp; cp2 += strlen (cp)) - if (!strcasecmp (cp2, tokid)) + for (i = 0; i < vector_cnt; i++) + if (!strcasecmp (vectors[i], lex_tokcstr (lexer))) { - msg (SE, _("Vector name %s is given twice."), tokid); + msg (SE, _("Vector name %s is given twice."), + lex_tokcstr (lexer)); goto fail; } - if (dict_lookup_vector (default_dict, tokid)) - { - msg (SE, _("There is already a vector with name %s."), tokid); - goto fail; - } + if (vector_cnt == vector_cap) + vectors = pool_2nrealloc (pool, + vectors, &vector_cap, sizeof *vectors); + vectors[vector_cnt++] = pool_strdup (pool, lex_tokcstr (lexer)); - cp = stpcpy (cp, tokid) + 1; - lex_get (); - lex_match (','); + lex_get (lexer); + lex_match (lexer, T_COMMA); } - *cp++ = 0; /* Now that we have the names it's time to check for the short or long forms. */ - if (lex_match ('=')) + if (lex_match (lexer, T_EQUALS)) { /* Long form. */ struct variable **v; size_t nv; - if (strchr (vecnames, '\0')[1]) + if (vector_cnt > 1) { - /* There's more than one vector name. */ - msg (SE, _("A slash must be used to separate each vector " - "specification when using the long form. Commands " - "such as VECTOR A,B=Q1 TO Q20 are not supported.")); + msg (SE, _("A slash must separate each vector " + "specification in VECTOR's long form.")); goto fail; } - if (!parse_variables (default_dict, &v, &nv, - PV_SAME_TYPE | PV_DUPLICATE)) + if (!parse_variables_pool (lexer, pool, dict, &v, &nv, + PV_SAME_WIDTH | PV_DUPLICATE)) goto fail; - dict_create_vector (default_dict, vecnames, v, nv); - free (v); + dict_create_vector (dict, vectors[0], v, nv); } - else if (lex_match ('(')) + else if (lex_match (lexer, T_LPAREN)) { - int i; - - /* Maximum number of digits in a number to add to the base - vecname. */ - int ndig; - - /* Name of an individual variable to be created. */ - char name[SHORT_NAME_LEN + 1]; - - /* Vector variables. */ - struct variable **v; - int nv; - - if (!lex_force_int ()) - return CMD_CASCADING_FAILURE; - nv = lex_integer (); - lex_get (); - if (nv <= 0) + /* Short form. */ + struct fmt_spec format; + bool seen_format = false; + + struct variable **vars; + int var_cnt; + + size_t i; + + var_cnt = 0; + format = fmt_for_output (FMT_F, 8, 2); + seen_format = false; + while (!lex_match (lexer, T_RPAREN)) + { + if (lex_is_integer (lexer) && var_cnt == 0) + { + var_cnt = lex_integer (lexer); + lex_get (lexer); + if (var_cnt <= 0) + { + msg (SE, _("Vectors must have at least one element.")); + goto fail; + } + } + else if (lex_token (lexer) == T_ID && !seen_format) + { + seen_format = true; + if (!parse_format_specifier (lexer, &format) + || !fmt_check_output (&format) + || !fmt_check_type_compat (&format, VAL_NUMERIC)) + goto fail; + } + else + { + lex_error (lexer, NULL); + goto fail; + } + lex_match (lexer, T_COMMA); + } + if (var_cnt == 0) + { + lex_error (lexer, _("expecting vector length")); + goto fail; + } + + /* Check that none of the variables exist and that their names are + not excessively long. */ + for (i = 0; i < vector_cnt; i++) { - msg (SE, _("Vectors must have at least one element.")); - goto fail; - } - if (!lex_force_match (')')) - goto fail; - - /* First check that all the generated variable names - are LONG_NAME_LEN characters or shorter. */ - ndig = intlog10 (nv); - for (cp = vecnames; *cp;) - { - int len = strlen (cp); - if (len + ndig > LONG_NAME_LEN) + int j; + for (j = 0; j < var_cnt; j++) { - msg (SE, _("%s%d is too long for a variable name."), cp, nv); - goto fail; - } - cp += len + 1; - } - - /* Next check that none of the variables exist. */ - for (cp = vecnames; *cp;) - { - for (i = 0; i < nv; i++) - { - sprintf (name, "%s%d", cp, i + 1); - if (dict_lookup_var (default_dict, name)) + char *name = xasprintf ("%s%d", vectors[i], j + 1); + if (!dict_id_is_valid (dict, name, true)) + { + free (name); + goto fail; + } + if (dict_lookup_var (dict, name)) { - msg (SE, _("There is already a variable named %s."), - name); + free (name); + msg (SE, _("%s is an existing variable name."), name); goto fail; } + free (name); } - cp += strlen (cp) + 1; } /* Finally create the variables and vectors. */ - v = xmalloc (nv * sizeof *v); - for (cp = vecnames; *cp;) + vars = pool_nmalloc (pool, var_cnt, sizeof *vars); + for (i = 0; i < vector_cnt; i++) { - for (i = 0; i < nv; i++) + int j; + for (j = 0; j < var_cnt; j++) { - sprintf (name, "%s%d", cp, i + 1); - v[i] = dict_create_var_assert (default_dict, name, 0); + char *name = xasprintf ("%s%d", vectors[i], j + 1); + vars[j] = dict_create_var_assert (dict, name, 0); + var_set_both_formats (vars[j], &format); + free (name); } - if (!dict_create_vector (default_dict, cp, v, nv)) - assert (0); - cp += strlen (cp) + 1; + dict_create_vector_assert (dict, vectors[i], vars, var_cnt); } - free (v); } else { - msg (SE, _("The syntax for this command does not match " - "the expected syntax for either the long form " - "or the short form of VECTOR.")); + lex_error (lexer, NULL); goto fail; } - - free (vecnames); - vecnames = NULL; } - while (lex_match ('/')); + while (lex_match (lexer, T_SLASH)); - if (token != '.') - { - lex_error (_("expecting end of command")); - goto fail; - } + pool_destroy (pool); return CMD_SUCCESS; fail: - free (vecnames); + pool_destroy (pool); return CMD_FAILURE; }