1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
43 #include "bitvector.h"
50 static struct variable *
51 parse_vs_variable (struct var_set *vs)
57 lex_error ("expecting variable name");
61 vp = var_set_lookup_var (vs, tokid);
63 msg (SE, _("%s is not a variable name."), tokid);
70 parse_dict_variable (struct dictionary *d)
72 struct var_set *vs = var_set_create_from_dict (d);
73 struct variable *var = parse_vs_variable (vs);
81 return parse_dict_variable (default_dict);
86 dict_class_from_id (const char *name)
88 assert (name != NULL);
102 dict_class_to_name (enum dict_class dict_class)
118 parse_variables (struct dictionary *d, struct variable ***var, int *cnt,
125 assert (var != NULL);
126 assert (cnt != NULL);
128 vs = var_set_create_from_dict (d);
129 success = parse_var_set_vars (vs, var, cnt, opts);
130 var_set_destroy (vs);
134 /* Note that if parse_variables() returns 0, *v is free()'d.
135 Conversely, if parse_variables() returns non-zero, then *nv is
136 nonzero and *v is non-NULL. */
138 parse_var_set_vars (struct var_set *vs,
139 struct variable ***v, int *nv,
146 struct variable *v1, *v2;
148 enum dict_class dict_class;
154 /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
156 assert ((((pv_opts & PV_NUMERIC) != 0)
157 + ((pv_opts & PV_STRING) != 0)
158 + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
160 /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
161 assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
163 vs_var_cnt = var_set_get_cnt (vs);
165 if (!(pv_opts & PV_APPEND))
174 if (!(pv_opts & PV_DUPLICATE))
176 included = xmalloc (vs_var_cnt);
177 memset (included, 0, vs_var_cnt);
178 for (i = 0; i < *nv; i++)
179 included[(*v)[i]->index] = 1;
184 if (lex_match (T_ALL))
186 v1 = var_set_get_var (vs, 0);
187 v2 = var_set_get_var (vs, vs_var_cnt - 1);
189 dict_class = DC_ORDINARY;
193 v1 = parse_vs_variable (vs);
197 if (lex_match (T_TO))
199 enum dict_class dict_class_2;
201 v2 = parse_vs_variable (vs);
204 lex_error ("expecting variable name");
208 count = v2->index - v1->index + 1;
211 msg (SE, _("%s TO %s is not valid syntax since %s "
212 "precedes %s in the dictionary."),
213 v1->name, v2->name, v2->name, v1->name);
217 dict_class = dict_class_from_id (v1->name);
218 dict_class_2 = dict_class_from_id (v2->name);
219 if (dict_class != dict_class_2)
221 msg (SE, _("When using the TO keyword to specify several "
222 "variables, both variables must be from "
223 "the same variable dictionaries, of either "
224 "ordinary, scratch, or system variables. "
225 "%s is a %s variable, whereas %s is %s."),
226 v1->name, dict_class_to_name (dict_class),
227 v2->name, dict_class_to_name (dict_class_2));
235 dict_class = dict_class_from_id (v1->name);
237 if (dict_class == DC_SCRATCH && (pv_opts & PV_NO_SCRATCH))
239 msg (SE, _("Scratch variables (such as %s) are not allowed "
245 if (*nv + count > mv)
247 mv += ROUND_UP (count, 16);
248 *v = xrealloc (*v, mv * sizeof **v);
251 /* Add v1...v2 to the list. */
252 for (i = v1->index; i <= v2->index; i++)
254 struct variable *add = var_set_get_var (vs, i);
256 /* Skip over other dictionaries. */
257 if (dict_class != dict_class_from_id (add->name))
260 /* Different kinds of errors. */
261 if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC)
262 msg (SW, _("%s is not a numeric variable. It will not be "
263 "included in the variable list."), add->name);
264 else if ((pv_opts & PV_STRING) && add->type != ALPHA)
265 msg (SE, _("%s is not a string variable. It will not be "
266 "included in the variable list."), add->name);
267 else if ((pv_opts & PV_SAME_TYPE) && *nv
268 && add->type != (*v)[0]->type)
269 msg (SE, _("%s and %s are not the same type. All variables in "
270 "this variable list must be of the same type. %s "
271 "will be omitted from list."),
272 (*v)[0]->name, add->name, add->name);
273 else if ((pv_opts & PV_NO_DUPLICATE) && included[add->index])
274 msg (SE, _("Variable %s appears twice in variable list."),
277 /* Success--add the variable to the list. */
278 if ((pv_opts & PV_DUPLICATE) || !included[add->index])
280 (*v)[(*nv)++] = var_set_get_var (vs, i);
281 if (!(pv_opts & PV_DUPLICATE))
282 included[add->index] = 1;
289 /* Arrive here only on failure. */
290 if (pv_opts & PV_SINGLE)
294 /* We finished adding v1...v2 to the list. */
295 if (pv_opts & PV_SINGLE)
299 while ((token == T_ID && var_set_lookup_var (vs, tokid) != NULL)
302 if (!(pv_opts & PV_DUPLICATE))
312 if (!(pv_opts & PV_DUPLICATE))
318 extract_num (char *s, char *r, int *n, int *d)
322 /* Find first digit. */
323 cp = s + strlen (s) - 1;
324 while (isdigit ((unsigned char) *cp) && cp > s)
329 strncpy (r, s, cp - s);
332 /* Count initial zeros. */
341 while (isdigit ((unsigned char) *cp))
344 *n = (*n * 10) + (*cp - '0');
349 if (*n == 0 && *d == 0)
351 msg (SE, _("incorrect use of TO convention"));
357 /* Parses a list of variable names according to the DATA LIST version
358 of the TO convention. */
360 parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
370 assert (names != NULL);
371 assert (nnames != NULL);
372 assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
373 | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
374 /* FIXME: PV_NO_DUPLICATE is not implemented. */
376 if (pv_opts & PV_APPEND)
377 nvar = mvar = *nnames;
384 name1 = xmalloc (36);
385 name2 = &name1[1 * 9];
386 root1 = &name1[2 * 9];
387 root2 = &name1[3 * 9];
392 lex_error ("expecting variable name");
395 if (tokid[0] == '#' && (pv_opts & PV_NO_SCRATCH))
397 msg (SE, _("Scratch variables not allowed here."));
400 strcpy (name1, tokid);
407 lex_error ("expecting variable name");
410 strcpy (name2, tokid);
413 if (!extract_num (name1, root1, &n1, &d1)
414 || !extract_num (name2, root2, &n2, &d2))
417 if (strcmp (root1, root2))
419 msg (SE, _("Prefixes don't match in use of TO convention."));
424 msg (SE, _("Bad bounds in use of TO convention."));
430 if (mvar < nvar + (n2 - n1 + 1))
432 mvar += ROUND_UP (n2 - n1 + 1, 16);
433 *names = xrealloc (*names, mvar * sizeof **names);
436 for (n = n1; n <= n2; n++)
438 (*names)[nvar] = xmalloc (9);
439 sprintf ((*names)[nvar], "%s%0*d", root1, d1, n);
448 *names = xrealloc (*names, mvar * sizeof **names);
450 (*names)[nvar++] = xstrdup (name1);
455 if (pv_opts & PV_SINGLE)
458 while (token == T_ID);
467 for (i = 0; i < nvar; i++)
476 /* Parses a list of variables where some of the variables may be
477 existing and the rest are to be created. Same args as
478 parse_DATA_LIST_vars(). */
480 parse_mixed_vars (char ***names, int *nnames, int pv_opts)
484 assert (names != NULL);
485 assert (nnames != NULL);
486 assert ((pv_opts & ~PV_APPEND) == 0);
488 if (!(pv_opts & PV_APPEND))
493 while (token == T_ID || token == T_ALL)
495 if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
500 if (!parse_variables (default_dict, &v, &nv, PV_NONE))
502 *names = xrealloc (*names, (*nnames + nv) * sizeof **names);
503 for (i = 0; i < nv; i++)
504 (*names)[*nnames + i] = xstrdup (v[i]->name);
508 else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
514 for (i = 0; i < *nnames; i++)
515 free ((*names)[*nnames]);
524 size_t (*get_cnt) (struct var_set *);
525 struct variable *(*get_var) (struct var_set *, size_t idx);
526 struct variable *(*lookup_var) (struct var_set *, const char *);
527 void (*destroy) (struct var_set *);
532 var_set_get_cnt (struct var_set *vs)
536 return vs->get_cnt (vs);
540 var_set_get_var (struct var_set *vs, size_t idx)
543 assert (idx < var_set_get_cnt (vs));
545 return vs->get_var (vs, idx);
549 var_set_lookup_var (struct var_set *vs, const char *name)
552 assert (name != NULL);
553 assert (strlen (name) < 9);
555 return vs->lookup_var (vs, name);
559 var_set_destroy (struct var_set *vs)
566 dict_var_set_get_cnt (struct var_set *vs)
568 struct dictionary *d = vs->aux;
570 return dict_get_var_cnt (d);
573 static struct variable *
574 dict_var_set_get_var (struct var_set *vs, size_t idx)
576 struct dictionary *d = vs->aux;
578 return dict_get_var (d, idx);
581 static struct variable *
582 dict_var_set_lookup_var (struct var_set *vs, const char *name)
584 struct dictionary *d = vs->aux;
586 return dict_lookup_var (d, name);
590 dict_var_set_destroy (struct var_set *vs)
596 var_set_create_from_dict (struct dictionary *d)
598 struct var_set *vs = xmalloc (sizeof *vs);
599 vs->get_cnt = dict_var_set_get_cnt;
600 vs->get_var = dict_var_set_get_var;
601 vs->lookup_var = dict_var_set_lookup_var;
602 vs->destroy = dict_var_set_destroy;
609 struct variable **var;
611 struct hsh_table *name_tab;
615 array_var_set_get_cnt (struct var_set *vs)
617 struct array_var_set *avs = vs->aux;
622 static struct variable *
623 array_var_set_get_var (struct var_set *vs, size_t idx)
625 struct array_var_set *avs = vs->aux;
627 return avs->var[idx];
630 static struct variable *
631 array_var_set_lookup_var (struct var_set *vs, const char *name)
633 struct array_var_set *avs = vs->aux;
636 strcpy (v.name, name);
638 return hsh_find (avs->name_tab, &v);
642 array_var_set_destroy (struct var_set *vs)
644 struct array_var_set *avs = vs->aux;
646 hsh_destroy (avs->name_tab);
652 var_set_create_from_array (struct variable **var, size_t var_cnt)
655 struct array_var_set *avs;
658 vs = xmalloc (sizeof *vs);
659 vs->get_cnt = array_var_set_get_cnt;
660 vs->get_var = array_var_set_get_var;
661 vs->lookup_var = array_var_set_lookup_var;
662 vs->destroy = array_var_set_destroy;
663 vs->aux = avs = xmalloc (sizeof *avs);
665 avs->var_cnt = var_cnt;
666 avs->name_tab = hsh_create (2 * var_cnt,
667 compare_variables, hash_variable, NULL,
669 for (i = 0; i < var_cnt; i++)
670 if (hsh_insert (avs->name_tab, var[i]) != NULL)
672 var_set_destroy (vs);