X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fvars-prs.c;h=920f8c9147ad2dee992b69588e929b90af399052;hb=8cf495e615e4feca5777f3592de98321d4fcdc0b;hp=143ad171bccd044c687de56eae05f1c254f89bfb;hpb=205ac3afa4c2b19c85819d8695abf3975bb11807;p=pspp diff --git a/src/vars-prs.c b/src/vars-prs.c index 143ad171bc..920f8c9147 100644 --- a/src/vars-prs.c +++ b/src/vars-prs.c @@ -14,48 +14,67 @@ 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 "var.h" #include +#include #include #include "alloc.h" #include "bitvector.h" +#include "dictionary.h" #include "error.h" #include "hash.h" #include "lexer.h" #include "misc.h" +#include "size_max.h" #include "str.h" -/* Parses a name as a variable within VS and returns the variable - if successful. On failure emits an error message and returns - a null pointer. */ -static struct variable * -parse_vs_variable (struct var_set *vs) -{ - struct variable *vp; +#include "gettext.h" +#define _(msgid) gettext (msgid) +/* Parses a name as a variable within VS. Sets *IDX to the + variable's index and returns true if successful. On failure + emits an error message and returns false. */ +static bool +parse_vs_variable_idx (const struct var_set *vs, size_t *idx) +{ + assert (idx != NULL); + if (token != T_ID) { - lex_error ("expecting variable name"); - return NULL; + lex_error (_("expecting variable name")); + return false; } + else if (var_set_lookup_var_idx (vs, tokid, idx)) + { + lex_get (); + return true; + } + else + { + msg (SE, _("%s is not a variable name."), tokid); + return false; + } +} - vp = var_set_lookup_var (vs, tokid); - if (vp == NULL) - msg (SE, _("%s is not a variable name."), tokid); - lex_get (); - - return vp; +/* Parses a name as a variable within VS and returns the variable + if successful. On failure emits an error message and returns + a null pointer. */ +static struct variable * +parse_vs_variable (const struct var_set *vs) +{ + size_t idx; + return parse_vs_variable_idx (vs, &idx) ? var_set_get_var (vs, idx) : NULL; } /* Parses a variable name in dictionary D and returns the variable if successful. On failure emits an error message and returns a null pointer. */ struct variable * -parse_dict_variable (struct dictionary *d) +parse_dict_variable (const struct dictionary *d) { struct var_set *vs = var_set_create_from_dict (d); struct variable *var = parse_vs_variable (vs); @@ -72,47 +91,14 @@ parse_variable (void) return parse_dict_variable (default_dict); } -/* Returns the dictionary class corresponding to a variable named - NAME. */ -enum dict_class -dict_class_from_id (const char *name) -{ - assert (name != NULL); - - switch (name[0]) - { - default: - return DC_ORDINARY; - case '$': - return DC_SYSTEM; - case '#': - return DC_SCRATCH; - } -} - -/* Returns the name of dictionary class DICT_CLASS. */ -const char * -dict_class_to_name (enum dict_class dict_class) -{ - switch (dict_class) - { - case DC_ORDINARY: - return _("ordinary"); - case DC_SYSTEM: - return _("system"); - case DC_SCRATCH: - return _("scratch"); - default: - assert (0); - } -} /* Parses a set of variables from dictionary D given options OPTS. Resulting list of variables stored in *VAR and the - number of variables into *CNT. */ + number of variables into *CNT. Returns nonzero only if + successful. */ int -parse_variables (struct dictionary *d, struct variable ***var, int *cnt, - int opts) +parse_variables (const struct dictionary *d, struct variable ***var, + size_t *cnt, int opts) { struct var_set *vs; int success; @@ -123,25 +109,101 @@ parse_variables (struct dictionary *d, struct variable ***var, int *cnt, vs = var_set_create_from_dict (d); success = parse_var_set_vars (vs, var, cnt, opts); + if ( success == 0 ) + free ( *var ) ; var_set_destroy (vs); return success; } +/* Parses a variable name from VS. If successful, sets *IDX to + the variable's index in VS, *CLASS to the variable's + dictionary class, and returns nonzero. Returns zero on + failure. */ +static int +parse_var_idx_class (const struct var_set *vs, size_t *idx, + enum dict_class *class) +{ + if (!parse_vs_variable_idx (vs, idx)) + return 0; + + *class = dict_class_from_id (var_set_get_var (vs, *idx)->name); + return 1; +} + +/* Add the variable from VS with index IDX to the list of + variables V that has *NV elements and room for *MV. + Uses and updates INCLUDED to avoid duplicates if indicated by + PV_OPTS, which also affects what variables are allowed in + appropriate ways. */ +static void +add_variable (struct variable ***v, size_t *nv, size_t *mv, + char *included, int pv_opts, + const struct var_set *vs, size_t idx) +{ + struct variable *add = var_set_get_var (vs, idx); + + if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) + msg (SW, _("%s is not a numeric variable. It will not be " + "included in the variable list."), add->name); + else if ((pv_opts & PV_STRING) && add->type != ALPHA) + msg (SE, _("%s is not a string variable. It will not be " + "included in the variable list."), add->name); + else if ((pv_opts & PV_NO_SCRATCH) + && dict_class_from_id (add->name) == DC_SCRATCH) + msg (SE, _("Scratch variables (such as %s) are not allowed " + "here."), add->name); + else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) + msg (SE, _("%s and %s are not the same type. All variables in " + "this variable list must be of the same type. %s " + "will be omitted from list."), + (*v)[0]->name, add->name, add->name); + else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) + msg (SE, _("Variable %s appears twice in variable list."), add->name); + else + { + if (*nv >= *mv) + { + *mv = 2 * (*nv + 1); + *v = xnrealloc (*v, *mv, sizeof **v); + } + + if ((pv_opts & PV_DUPLICATE) || !included[idx]) + { + (*v)[(*nv)++] = add; + if (!(pv_opts & PV_DUPLICATE)) + included[idx] = 1; + } + } +} + +/* Adds the variables in VS with indexes FIRST_IDX through + LAST_IDX, inclusive, to the list of variables V that has *NV + elements and room for *MV. Uses and updates INCLUDED to avoid + duplicates if indicated by PV_OPTS, which also affects what + variables are allowed in appropriate ways. */ +static void +add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included, + int pv_opts, + const struct var_set *vs, int first_idx, int last_idx, + enum dict_class class) +{ + size_t i; + + for (i = first_idx; i <= last_idx; i++) + if (dict_class_from_id (var_set_get_var (vs, i)->name) == class) + add_variable (v, nv, mv, included, pv_opts, vs, i); +} + /* Note that if parse_variables() returns 0, *v is free()'d. Conversely, if parse_variables() returns non-zero, then *nv is nonzero and *v is non-NULL. */ int -parse_var_set_vars (struct var_set *vs, - struct variable ***v, int *nv, +parse_var_set_vars (const struct var_set *vs, + struct variable ***v, size_t *nv, int pv_opts) { - size_t vs_var_cnt; - int i; - char *included = NULL; - - struct variable *v1, *v2; - int count, mv; - enum dict_class dict_class; + size_t mv; + char *included; assert (vs != NULL); assert (v != NULL); @@ -156,8 +218,6 @@ parse_var_set_vars (struct var_set *vs, /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */ assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE)); - vs_var_cnt = var_set_get_cnt (vs); - if (!(pv_opts & PV_APPEND)) { *v = NULL; @@ -169,144 +229,84 @@ parse_var_set_vars (struct var_set *vs, if (!(pv_opts & PV_DUPLICATE)) { - included = xmalloc (vs_var_cnt); - memset (included, 0, vs_var_cnt); + size_t i; + + included = xcalloc (var_set_get_cnt (vs), sizeof *included); for (i = 0; i < *nv; i++) included[(*v)[i]->index] = 1; } + else + included = NULL; - do + if (lex_match (T_ALL)) + add_variables (v, nv, &mv, included, pv_opts, + vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY); + else { - if (lex_match (T_ALL)) - { - v1 = var_set_get_var (vs, 0); - v2 = var_set_get_var (vs, vs_var_cnt - 1); - count = vs_var_cnt; - dict_class = DC_ORDINARY; - } - else - { - v1 = parse_vs_variable (vs); - if (!v1) - goto fail; + do + { + enum dict_class class; + size_t first_idx; + + if (!parse_var_idx_class (vs, &first_idx, &class)) + goto fail; - if (lex_match (T_TO)) - { - enum dict_class dict_class_2; - - v2 = parse_vs_variable (vs); - if (!v2) - { - lex_error ("expecting variable name"); - goto fail; - } - - count = v2->index - v1->index + 1; - if (count < 1) - { - msg (SE, _("%s TO %s is not valid syntax since %s " - "precedes %s in the dictionary."), - v1->name, v2->name, v2->name, v1->name); - goto fail; - } - - dict_class = dict_class_from_id (v1->name); - dict_class_2 = dict_class_from_id (v2->name); - if (dict_class != dict_class_2) - { - msg (SE, _("When using the TO keyword to specify several " + if (!lex_match (T_TO)) + add_variable (v, nv, &mv, included, pv_opts, vs, first_idx); + else + { + size_t last_idx; + enum dict_class last_class; + struct variable *first_var, *last_var; + + if (!parse_var_idx_class (vs, &last_idx, &last_class)) + goto fail; + + first_var = var_set_get_var (vs, first_idx); + last_var = var_set_get_var (vs, last_idx); + + if (last_idx < first_idx) + { + msg (SE, _("%s TO %s is not valid syntax since %s " + "precedes %s in the dictionary."), + first_var->name, last_var->name, + first_var->name, last_var->name); + goto fail; + } + + if (class != last_class) + { + msg (SE, _("When using the TO keyword to specify several " "variables, both variables must be from " "the same variable dictionaries, of either " "ordinary, scratch, or system variables. " "%s is a %s variable, whereas %s is %s."), - v1->name, dict_class_to_name (dict_class), - v2->name, dict_class_to_name (dict_class_2)); - goto fail; - } - } - else - { - v2 = v1; - count = 1; - dict_class = dict_class_from_id (v1->name); - } - if (dict_class == DC_SCRATCH && (pv_opts & PV_NO_SCRATCH)) - { - msg (SE, _("Scratch variables (such as %s) are not allowed " - "here."), v1->name); - goto fail; - } - } - - if (*nv + count > mv) - { - mv += ROUND_UP (count, 16); - *v = xrealloc (*v, mv * sizeof **v); - } - - /* Add v1...v2 to the list. */ - for (i = v1->index; i <= v2->index; i++) - { - struct variable *add = var_set_get_var (vs, i); - - /* Skip over other dictionaries. */ - if (dict_class != dict_class_from_id (add->name)) - continue; - - /* Different kinds of errors. */ - if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) - msg (SW, _("%s is not a numeric variable. It will not be " - "included in the variable list."), add->name); - else if ((pv_opts & PV_STRING) && add->type != ALPHA) - msg (SE, _("%s is not a string variable. It will not be " - "included in the variable list."), add->name); - else if ((pv_opts & PV_SAME_TYPE) && *nv - && add->type != (*v)[0]->type) - msg (SE, _("%s and %s are not the same type. All variables in " - "this variable list must be of the same type. %s " - "will be omitted from list."), - (*v)[0]->name, add->name, add->name); - else if ((pv_opts & PV_NO_DUPLICATE) && included[add->index]) - msg (SE, _("Variable %s appears twice in variable list."), - add->name); - else { - /* Success--add the variable to the list. */ - if ((pv_opts & PV_DUPLICATE) || !included[add->index]) - { - (*v)[(*nv)++] = var_set_get_var (vs, i); - if (!(pv_opts & PV_DUPLICATE)) - included[add->index] = 1; - } - - /* Next. */ - continue; - } - - /* Arrive here only on failure. */ + first_var->name, dict_class_to_name (class), + last_var->name, dict_class_to_name (last_class)); + goto fail; + } + + add_variables (v, nv, &mv, included, pv_opts, + vs, first_idx, last_idx, class); + } if (pv_opts & PV_SINGLE) - goto fail; - } - - /* We finished adding v1...v2 to the list. */ - if (pv_opts & PV_SINGLE) - return 1; - lex_match (','); + break; + lex_match (','); + } + while (token == T_ID && var_set_lookup_var (vs, tokid) != NULL); } - while ((token == T_ID && var_set_lookup_var (vs, tokid) != NULL) - || token == T_ALL); - - if (!(pv_opts & PV_DUPLICATE)) - free (included); - if (!*nv) + + if (*nv == 0) goto fail; + + free (included); return 1; fail: + free (included); free (*v); *v = NULL; *nv = 0; - if (!(pv_opts & PV_DUPLICATE)) - free (included); return 0; } @@ -356,14 +356,14 @@ extract_num (char *s, char *r, int *n, int *d) /* Parses a list of variable names according to the DATA LIST version of the TO convention. */ int -parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) +parse_DATA_LIST_vars (char ***names, size_t *nnames, int pv_opts) { int n1, n2; int d1, d2; int n; - int nvar, mvar; - char *name1, *name2; - char *root1, *root2; + size_t nvar, mvar; + char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1]; + char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1]; int success = 0; assert (names != NULL); @@ -380,10 +380,6 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) *names = NULL; } - name1 = xmalloc (36); - name2 = &name1[1 * 9]; - root1 = &name1[2 * 9]; - root2 = &name1[3 * 9]; do { if (token != T_ID) @@ -414,7 +410,7 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) || !extract_num (name2, root2, &n2, &d2)) goto fail; - if (strcmp (root1, root2)) + if (strcasecmp (root1, root2)) { msg (SE, _("Prefixes don't match in use of TO convention.")); goto fail; @@ -430,13 +426,14 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) if (mvar < nvar + (n2 - n1 + 1)) { mvar += ROUND_UP (n2 - n1 + 1, 16); - *names = xrealloc (*names, mvar * sizeof **names); + *names = xnrealloc (*names, mvar, sizeof **names); } for (n = n1; n <= n2; n++) { - (*names)[nvar] = xmalloc (9); - sprintf ((*names)[nvar], "%s%0*d", root1, d1, n); + char name[LONG_NAME_LEN + 1]; + sprintf (name, "%s%0*d", root1, d1, n); + (*names)[nvar] = xstrdup (name); nvar++; } } @@ -445,7 +442,7 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) if (nvar >= mvar) { mvar += 16; - *names = xrealloc (*names, mvar * sizeof **names); + *names = xnrealloc (*names, mvar, sizeof **names); } (*names)[nvar++] = xstrdup (name1); } @@ -460,7 +457,6 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) fail: *nnames = nvar; - free (name1); if (!success) { int i; @@ -477,9 +473,9 @@ fail: existing and the rest are to be created. Same args as parse_DATA_LIST_vars(). */ int -parse_mixed_vars (char ***names, int *nnames, int pv_opts) +parse_mixed_vars (char ***names, size_t *nnames, int pv_opts) { - int i; + size_t i; assert (names != NULL); assert (nnames != NULL); @@ -495,11 +491,11 @@ parse_mixed_vars (char ***names, int *nnames, int pv_opts) if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL) { struct variable **v; - int nv; + size_t nv; if (!parse_variables (default_dict, &v, &nv, PV_NONE)) goto fail; - *names = xrealloc (*names, (*nnames + nv) * sizeof **names); + *names = xnrealloc (*names, *nnames + nv, sizeof **names); for (i = 0; i < nv; i++) (*names)[*nnames + i] = xstrdup (v[i]->name); free (v); @@ -522,16 +518,16 @@ fail: /* A set of variables. */ struct var_set { - size_t (*get_cnt) (struct var_set *); - struct variable *(*get_var) (struct var_set *, size_t idx); - struct variable *(*lookup_var) (struct var_set *, const char *); + size_t (*get_cnt) (const struct var_set *); + struct variable *(*get_var) (const struct var_set *, size_t idx); + bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *); void (*destroy) (struct var_set *); void *aux; }; /* Returns the number of variables in VS. */ size_t -var_set_get_cnt (struct var_set *vs) +var_set_get_cnt (const struct var_set *vs) { assert (vs != NULL); @@ -541,7 +537,7 @@ var_set_get_cnt (struct var_set *vs) /* Return variable with index IDX in VS. IDX must be less than the number of variables in VS. */ struct variable * -var_set_get_var (struct var_set *vs, size_t idx) +var_set_get_var (const struct var_set *vs, size_t idx) { assert (vs != NULL); assert (idx < var_set_get_cnt (vs)); @@ -552,13 +548,25 @@ var_set_get_var (struct var_set *vs, size_t idx) /* Returns the variable in VS named NAME, or a null pointer if VS contains no variable with that name. */ struct variable * -var_set_lookup_var (struct var_set *vs, const char *name) +var_set_lookup_var (const struct var_set *vs, const char *name) +{ + size_t idx; + return (var_set_lookup_var_idx (vs, name, &idx) + ? var_set_get_var (vs, idx) + : NULL); +} + +/* If VS contains a variable named NAME, sets *IDX to its index + and returns true. Otherwise, returns false. */ +bool +var_set_lookup_var_idx (const struct var_set *vs, const char *name, + size_t *idx) { assert (vs != NULL); assert (name != NULL); - assert (strlen (name) < 9); + assert (strlen (name) <= LONG_NAME_LEN); - return vs->lookup_var (vs, name); + return vs->lookup_var_idx (vs, name, idx); } /* Destroys VS. */ @@ -571,7 +579,7 @@ var_set_destroy (struct var_set *vs) /* Returns the number of variables in VS. */ static size_t -dict_var_set_get_cnt (struct var_set *vs) +dict_var_set_get_cnt (const struct var_set *vs) { struct dictionary *d = vs->aux; @@ -581,21 +589,28 @@ dict_var_set_get_cnt (struct var_set *vs) /* Return variable with index IDX in VS. IDX must be less than the number of variables in VS. */ static struct variable * -dict_var_set_get_var (struct var_set *vs, size_t idx) +dict_var_set_get_var (const struct var_set *vs, size_t idx) { struct dictionary *d = vs->aux; return dict_get_var (d, idx); } -/* Returns the variable in VS named NAME, or a null pointer if VS - contains no variable with that name. */ -static struct variable * -dict_var_set_lookup_var (struct var_set *vs, const char *name) +/* If VS contains a variable named NAME, sets *IDX to its index + and returns true. Otherwise, returns false. */ +static bool +dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name, + size_t *idx) { struct dictionary *d = vs->aux; - - return dict_lookup_var (d, name); + struct variable *v = dict_lookup_var (d, name); + if (v != NULL) + { + *idx = v->index; + return true; + } + else + return false; } /* Destroys VS. */ @@ -607,28 +622,28 @@ dict_var_set_destroy (struct var_set *vs) /* Returns a variable set based on D. */ struct var_set * -var_set_create_from_dict (struct dictionary *d) +var_set_create_from_dict (const struct dictionary *d) { struct var_set *vs = xmalloc (sizeof *vs); vs->get_cnt = dict_var_set_get_cnt; vs->get_var = dict_var_set_get_var; - vs->lookup_var = dict_var_set_lookup_var; + vs->lookup_var_idx = dict_var_set_lookup_var_idx; vs->destroy = dict_var_set_destroy; - vs->aux = d; + vs->aux = (void *) d; return vs; } /* A variable set based on an array. */ struct array_var_set { - struct variable **var; /* Array of variables. */ + struct variable *const *var;/* Array of variables. */ size_t var_cnt; /* Number of elements in var. */ struct hsh_table *name_tab; /* Hash from variable names to variables. */ }; /* Returns the number of variables in VS. */ static size_t -array_var_set_get_cnt (struct var_set *vs) +array_var_set_get_cnt (const struct var_set *vs) { struct array_var_set *avs = vs->aux; @@ -638,24 +653,32 @@ array_var_set_get_cnt (struct var_set *vs) /* Return variable with index IDX in VS. IDX must be less than the number of variables in VS. */ static struct variable * -array_var_set_get_var (struct var_set *vs, size_t idx) +array_var_set_get_var (const struct var_set *vs, size_t idx) { struct array_var_set *avs = vs->aux; - return avs->var[idx]; + return (struct variable *) avs->var[idx]; } -/* Returns the variable in VS named NAME, or a null pointer if VS - contains no variable with that name. */ -static struct variable * -array_var_set_lookup_var (struct var_set *vs, const char *name) +/* If VS contains a variable named NAME, sets *IDX to its index + and returns true. Otherwise, returns false. */ +static bool +array_var_set_lookup_var_idx (const struct var_set *vs, const char *name, + size_t *idx) { struct array_var_set *avs = vs->aux; - struct variable v; + struct variable v, *vp, *const *vpp; strcpy (v.name, name); - - return hsh_find (avs->name_tab, &v); + vp = &v; + vpp = hsh_find (avs->name_tab, &vp); + if (vpp != NULL) + { + *idx = vpp - avs->var; + return true; + } + else + return false; } /* Destroys VS. */ @@ -672,7 +695,7 @@ array_var_set_destroy (struct var_set *vs) /* Returns a variable set based on the VAR_CNT variables in VAR. */ struct var_set * -var_set_create_from_array (struct variable **var, size_t var_cnt) +var_set_create_from_array (struct variable *const *var, size_t var_cnt) { struct var_set *vs; struct array_var_set *avs; @@ -681,16 +704,16 @@ var_set_create_from_array (struct variable **var, size_t var_cnt) vs = xmalloc (sizeof *vs); vs->get_cnt = array_var_set_get_cnt; vs->get_var = array_var_set_get_var; - vs->lookup_var = array_var_set_lookup_var; + vs->lookup_var_idx = array_var_set_lookup_var_idx; vs->destroy = array_var_set_destroy; vs->aux = avs = xmalloc (sizeof *avs); avs->var = var; avs->var_cnt = var_cnt; avs->name_tab = hsh_create (2 * var_cnt, - compare_variables, hash_variable, NULL, + compare_var_ptr_names, hash_var_ptr_name, NULL, NULL); for (i = 0; i < var_cnt; i++) - if (hsh_insert (avs->name_tab, var[i]) != NULL) + if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) { var_set_destroy (vs); return NULL;