1773e4d8d5f74bec6688bbdf41c05662b291748f
[pspp-builds.git] / src / vars-prs.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "var.h"
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include "alloc.h"
25 #include "bitvector.h"
26 #include "dictionary.h"
27 #include "error.h"
28 #include "hash.h"
29 #include "lexer.h"
30 #include "misc.h"
31 #include "str.h"
32
33 /* Parses a name as a variable within VS and returns the
34    variable's index if successful.  On failure emits an error
35    message and returns a null pointer. */
36 static int
37 parse_vs_variable_idx (const struct var_set *vs)
38 {
39   int idx;
40
41   if (token != T_ID)
42     {
43       lex_error (_("expecting variable name"));
44       return -1;
45     }
46
47   idx = var_set_lookup_var_idx (vs, tokid);
48   if (idx < 0)
49     msg (SE, _("%s is not a variable name."), tokid);
50   lex_get ();
51
52   return idx;
53 }
54
55 /* Parses a name as a variable within VS and returns the variable
56    if successful.  On failure emits an error message and returns
57    a null pointer. */
58 static struct variable *
59 parse_vs_variable (const struct var_set *vs)
60 {
61   int idx = parse_vs_variable_idx (vs);
62   return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
63 }
64
65 /* Parses a variable name in dictionary D and returns the
66    variable if successful.  On failure emits an error message and
67    returns a null pointer. */
68 struct variable *
69 parse_dict_variable (const struct dictionary *d) 
70 {
71   struct var_set *vs = var_set_create_from_dict (d);
72   struct variable *var = parse_vs_variable (vs);
73   var_set_destroy (vs);
74   return var;
75 }
76
77 /* Parses a variable name in default_dict and returns the
78    variable if successful.  On failure emits an error message and
79    returns a null pointer. */
80 struct variable *
81 parse_variable (void)
82 {
83   return parse_dict_variable (default_dict);
84 }
85
86 /* Returns the dictionary class corresponding to a variable named
87    NAME. */
88 enum dict_class
89 dict_class_from_id (const char *name) 
90 {
91   assert (name != NULL);
92
93   switch (name[0]) 
94     {
95     default:
96       return DC_ORDINARY;
97     case '$':
98       return DC_SYSTEM;
99     case '#':
100       return DC_SCRATCH;
101     }
102 }
103
104 /* Returns the name of dictionary class DICT_CLASS. */
105 const char *
106 dict_class_to_name (enum dict_class dict_class) 
107 {
108   switch (dict_class) 
109     {
110     case DC_ORDINARY:
111       return _("ordinary");
112     case DC_SYSTEM:
113       return _("system");
114     case DC_SCRATCH:
115       return _("scratch");
116     default:
117       assert (0);
118       abort ();
119     }
120 }
121
122 /* Parses a set of variables from dictionary D given options
123    OPTS.  Resulting list of variables stored in *VAR and the
124    number of variables into *CNT.  Returns nonzero only if
125    successful. */
126 int
127 parse_variables (const struct dictionary *d, struct variable ***var,
128                  int *cnt, int opts) 
129 {
130   struct var_set *vs;
131   int success;
132
133   assert (d != NULL);
134   assert (var != NULL);
135   assert (cnt != NULL);
136
137   vs = var_set_create_from_dict (d);
138   success = parse_var_set_vars (vs, var, cnt, opts);
139   if ( success == 0 )
140      free ( *var ) ;
141   var_set_destroy (vs);
142   return success;
143 }
144
145 /* Parses a variable name from VS.  If successful, sets *IDX to
146    the variable's index in VS, *CLASS to the variable's
147    dictionary class, and returns nonzero.  Returns zero on
148    failure. */
149 static int
150 parse_var_idx_class (const struct var_set *vs, int *idx,
151                      enum dict_class *class)
152 {
153   *idx = parse_vs_variable_idx (vs);
154   if (*idx < 0)
155     return 0;
156
157   *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
158   return 1;
159 }
160
161 /* Add the variable from VS with index IDX to the list of
162    variables V that has *NV elements and room for *MV.
163    Uses and updates INCLUDED to avoid duplicates if indicated by
164    PV_OPTS, which also affects what variables are allowed in
165    appropriate ways. */
166 static void
167 add_variable (struct variable ***v, int *nv, int *mv,
168               char *included, int pv_opts,
169               const struct var_set *vs, int idx)
170 {
171   struct variable *add = var_set_get_var (vs, idx);
172
173   if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) 
174     msg (SW, _("%s is not a numeric variable.  It will not be "
175                "included in the variable list."), add->name);
176   else if ((pv_opts & PV_STRING) && add->type != ALPHA) 
177     msg (SE, _("%s is not a string variable.  It will not be "
178                "included in the variable list."), add->name);
179   else if ((pv_opts & PV_NO_SCRATCH)
180            && dict_class_from_id (add->name) == DC_SCRATCH)
181     msg (SE, _("Scratch variables (such as %s) are not allowed "
182                "here."), add->name);
183   else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) 
184     msg (SE, _("%s and %s are not the same type.  All variables in "
185                "this variable list must be of the same type.  %s "
186                "will be omitted from list."),
187          (*v)[0]->name, add->name, add->name);
188   else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) 
189     msg (SE, _("Variable %s appears twice in variable list."), add->name);
190   else 
191     {
192       if (*nv >= *mv)
193         {
194           *mv = 2 * (*nv + 1);
195           *v = xrealloc (*v, *mv * sizeof **v);
196         }
197
198       if ((pv_opts & PV_DUPLICATE) || !included[idx])
199         {
200           (*v)[(*nv)++] = add;
201           if (!(pv_opts & PV_DUPLICATE))
202             included[idx] = 1;
203         }
204     }
205 }
206
207 /* Adds the variables in VS with indexes FIRST_IDX through
208    LAST_IDX, inclusive, to the list of variables V that has *NV
209    elements and room for *MV.  Uses and updates INCLUDED to avoid
210    duplicates if indicated by PV_OPTS, which also affects what
211    variables are allowed in appropriate ways. */
212 static void
213 add_variables (struct variable ***v, int *nv, int *mv, char *included,
214                int pv_opts,
215                const struct var_set *vs, int first_idx, int last_idx,
216                enum dict_class class) 
217 {
218   int i;
219   
220   for (i = first_idx; i <= last_idx; i++)
221     if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
222       add_variable (v, nv, mv, included, pv_opts, vs, i);
223 }
224
225 /* Note that if parse_variables() returns 0, *v is free()'d.
226    Conversely, if parse_variables() returns non-zero, then *nv is
227    nonzero and *v is non-NULL. */
228 int
229 parse_var_set_vars (const struct var_set *vs, 
230                     struct variable ***v, int *nv,
231                     int pv_opts)
232 {
233   int mv;
234   char *included;
235
236   assert (vs != NULL);
237   assert (v != NULL);
238   assert (nv != NULL);
239
240   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
241      specified. */
242   assert ((((pv_opts & PV_NUMERIC) != 0)
243            + ((pv_opts & PV_STRING) != 0)
244            + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
245
246   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
247   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
248
249   if (!(pv_opts & PV_APPEND))
250     {
251       *v = NULL;
252       *nv = 0;
253       mv = 0;
254     }
255   else
256     mv = *nv;
257
258   if (!(pv_opts & PV_DUPLICATE))
259     {
260       int i;
261       
262       included = xcalloc (var_set_get_cnt (vs), sizeof *included);
263       for (i = 0; i < *nv; i++)
264         included[(*v)[i]->index] = 1;
265     }
266   else
267     included = NULL;
268
269   if (lex_match (T_ALL))
270     add_variables (v, nv, &mv, included, pv_opts,
271                    vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
272   else 
273     {
274       do
275         {
276           enum dict_class class;
277           int first_idx;
278           
279           if (!parse_var_idx_class (vs, &first_idx, &class))
280             goto fail;
281
282           if (!lex_match (T_TO))
283             add_variable (v, nv, &mv, included, pv_opts,
284                           vs, first_idx);
285           else 
286             {
287               int last_idx;
288               enum dict_class last_class;
289               struct variable *first_var, *last_var;
290
291               if (!parse_var_idx_class (vs, &last_idx, &last_class))
292                 goto fail;
293
294               first_var = var_set_get_var (vs, first_idx);
295               last_var = var_set_get_var (vs, last_idx);
296
297               if (last_idx < first_idx)
298                 {
299                   msg (SE, _("%s TO %s is not valid syntax since %s "
300                              "precedes %s in the dictionary."),
301                        first_var->name, last_var->name,
302                        first_var->name, last_var->name);
303                   goto fail;
304                 }
305
306               if (class != last_class)
307                 {
308                   msg (SE, _("When using the TO keyword to specify several "
309                              "variables, both variables must be from "
310                              "the same variable dictionaries, of either "
311                              "ordinary, scratch, or system variables.  "
312                              "%s is a %s variable, whereas %s is %s."),
313                        first_var->name, dict_class_to_name (class),
314                        last_var->name, dict_class_to_name (last_class));
315                   goto fail;
316                 }
317
318               add_variables (v, nv, &mv, included, pv_opts,
319                              vs, first_idx, last_idx, class);
320             }
321           if (pv_opts & PV_SINGLE)
322             break;
323           lex_match (',');
324         }
325       while (token == T_ID && var_set_lookup_var (vs, tokid) != NULL);
326     }
327   
328   if (*nv == 0)
329     goto fail;
330
331   free (included);
332   return 1;
333
334 fail:
335   free (included);
336   free (*v);
337   *v = NULL;
338   *nv = 0;
339   return 0;
340 }
341
342 /* Extracts a numeric suffix from variable name S, copying it
343    into string R.  Sets *D to the length of R and *N to its
344    value. */
345 static int
346 extract_num (char *s, char *r, int *n, int *d)
347 {
348   char *cp;
349
350   /* Find first digit. */
351   cp = s + strlen (s) - 1;
352   while (isdigit ((unsigned char) *cp) && cp > s)
353     cp--;
354   cp++;
355
356   /* Extract root. */
357   strncpy (r, s, cp - s);
358   r[cp - s] = 0;
359
360   /* Count initial zeros. */
361   *n = *d = 0;
362   while (*cp == '0')
363     {
364       (*d)++;
365       cp++;
366     }
367
368   /* Extract value. */
369   while (isdigit ((unsigned char) *cp))
370     {
371       (*d)++;
372       *n = (*n * 10) + (*cp - '0');
373       cp++;
374     }
375
376   /* Sanity check. */
377   if (*n == 0 && *d == 0)
378     {
379       msg (SE, _("incorrect use of TO convention"));
380       return 0;
381     }
382   return 1;
383 }
384
385 /* Parses a list of variable names according to the DATA LIST version
386    of the TO convention.  */
387 int
388 parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
389 {
390   int n1, n2;
391   int d1, d2;
392   int n;
393   int nvar, mvar;
394   char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
395   char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
396   int success = 0;
397
398   assert (names != NULL);
399   assert (nnames != NULL);
400   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
401                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
402   /* FIXME: PV_NO_DUPLICATE is not implemented. */
403
404   if (pv_opts & PV_APPEND)
405     nvar = mvar = *nnames;
406   else
407     {
408       nvar = mvar = 0;
409       *names = NULL;
410     }
411
412   do
413     {
414       if (token != T_ID)
415         {
416           lex_error ("expecting variable name");
417           goto fail;
418         }
419       if (dict_class_from_id (tokid) == DC_SCRATCH
420           && (pv_opts & PV_NO_SCRATCH))
421         {
422           msg (SE, _("Scratch variables not allowed here."));
423           goto fail;
424         }
425       strcpy (name1, tokid);
426       lex_get ();
427       if (token == T_TO)
428         {
429           lex_get ();
430           if (token != T_ID)
431             {
432               lex_error ("expecting variable name");
433               goto fail;
434             }
435           strcpy (name2, tokid);
436           lex_get ();
437
438           if (!extract_num (name1, root1, &n1, &d1)
439               || !extract_num (name2, root2, &n2, &d2))
440             goto fail;
441
442           if (strcasecmp (root1, root2))
443             {
444               msg (SE, _("Prefixes don't match in use of TO convention."));
445               goto fail;
446             }
447           if (n1 > n2)
448             {
449               msg (SE, _("Bad bounds in use of TO convention."));
450               goto fail;
451             }
452           if (d2 > d1)
453             d2 = d1;
454
455           if (mvar < nvar + (n2 - n1 + 1))
456             {
457               mvar += ROUND_UP (n2 - n1 + 1, 16);
458               *names = xrealloc (*names, mvar * sizeof **names);
459             }
460
461           for (n = n1; n <= n2; n++)
462             {
463               char name[LONG_NAME_LEN + 1];
464               sprintf (name, "%s%0*d", root1, d1, n);
465               (*names)[nvar] = xstrdup (name);
466               nvar++;
467             }
468         }
469       else
470         {
471           if (nvar >= mvar)
472             {
473               mvar += 16;
474               *names = xrealloc (*names, mvar * sizeof **names);
475             }
476           (*names)[nvar++] = xstrdup (name1);
477         }
478
479       lex_match (',');
480
481       if (pv_opts & PV_SINGLE)
482         break;
483     }
484   while (token == T_ID);
485   success = 1;
486
487 fail:
488   *nnames = nvar;
489   if (!success)
490     {
491       int i;
492       for (i = 0; i < nvar; i++)
493         free ((*names)[i]);
494       free (*names);
495       *names = NULL;
496       *nnames = 0;
497     }
498   return success;
499 }
500
501 /* Parses a list of variables where some of the variables may be
502    existing and the rest are to be created.  Same args as
503    parse_DATA_LIST_vars(). */
504 int
505 parse_mixed_vars (char ***names, int *nnames, int pv_opts)
506 {
507   int i;
508
509   assert (names != NULL);
510   assert (nnames != NULL);
511   assert ((pv_opts & ~PV_APPEND) == 0);
512
513   if (!(pv_opts & PV_APPEND))
514     {
515       *names = NULL;
516       *nnames = 0;
517     }
518   while (token == T_ID || token == T_ALL)
519     {
520       if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
521         {
522           struct variable **v;
523           int nv;
524
525           if (!parse_variables (default_dict, &v, &nv, PV_NONE))
526             goto fail;
527           *names = xrealloc (*names, (*nnames + nv) * sizeof **names);
528           for (i = 0; i < nv; i++)
529             (*names)[*nnames + i] = xstrdup (v[i]->name);
530           free (v);
531           *nnames += nv;
532         }
533       else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
534         goto fail;
535     }
536   return 1;
537
538 fail:
539   for (i = 0; i < *nnames; i++)
540     free ((*names)[*nnames]);
541   free (names);
542   *names = NULL;
543   *nnames = 0;
544   return 0;
545 }
546 \f
547 /* A set of variables. */
548 struct var_set 
549   {
550     size_t (*get_cnt) (const struct var_set *);
551     struct variable *(*get_var) (const struct var_set *, size_t idx);
552     int (*lookup_var_idx) (const struct var_set *, const char *);
553     void (*destroy) (struct var_set *);
554     void *aux;
555   };
556
557 /* Returns the number of variables in VS. */
558 size_t
559 var_set_get_cnt (const struct var_set *vs) 
560 {
561   assert (vs != NULL);
562
563   return vs->get_cnt (vs);
564 }
565
566 /* Return variable with index IDX in VS.
567    IDX must be less than the number of variables in VS. */
568 struct variable *
569 var_set_get_var (const struct var_set *vs, size_t idx) 
570 {
571   assert (vs != NULL);
572   assert (idx < var_set_get_cnt (vs));
573
574   return vs->get_var (vs, idx);
575 }
576
577 /* Returns the variable in VS named NAME, or a null pointer if VS
578    contains no variable with that name. */
579 struct variable *
580 var_set_lookup_var (const struct var_set *vs, const char *name) 
581 {
582   int idx = var_set_lookup_var_idx (vs, name);
583   return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
584 }
585
586 /* Returns the index in VS of the variable named NAME, or -1 if
587    VS contains no variable with that name. */
588 int
589 var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
590 {
591   assert (vs != NULL);
592   assert (name != NULL);
593   assert (strlen (name) <= LONG_NAME_LEN );
594
595   return vs->lookup_var_idx (vs, name);
596 }
597
598 /* Destroys VS. */
599 void
600 var_set_destroy (struct var_set *vs) 
601 {
602   if (vs != NULL)
603     vs->destroy (vs);
604 }
605 \f
606 /* Returns the number of variables in VS. */
607 static size_t
608 dict_var_set_get_cnt (const struct var_set *vs) 
609 {
610   struct dictionary *d = vs->aux;
611
612   return dict_get_var_cnt (d);
613 }
614
615 /* Return variable with index IDX in VS.
616    IDX must be less than the number of variables in VS. */
617 static struct variable *
618 dict_var_set_get_var (const struct var_set *vs, size_t idx) 
619 {
620   struct dictionary *d = vs->aux;
621
622   return dict_get_var (d, idx);
623 }
624
625 /* Returns the index of the variable in VS named NAME, or -1 if
626    VS contains no variable with that name. */
627 static int
628 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
629 {
630   struct dictionary *d = vs->aux;
631   struct variable *v = dict_lookup_var (d, name);
632   return v != NULL ? v->index : -1;
633 }
634
635 /* Destroys VS. */
636 static void
637 dict_var_set_destroy (struct var_set *vs) 
638 {
639   free (vs);
640 }
641
642 /* Returns a variable set based on D. */
643 struct var_set *
644 var_set_create_from_dict (const struct dictionary *d) 
645 {
646   struct var_set *vs = xmalloc (sizeof *vs);
647   vs->get_cnt = dict_var_set_get_cnt;
648   vs->get_var = dict_var_set_get_var;
649   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
650   vs->destroy = dict_var_set_destroy;
651   vs->aux = (void *) d;
652   return vs;
653 }
654 \f
655 /* A variable set based on an array. */
656 struct array_var_set 
657   {
658     struct variable *const *var;/* Array of variables. */
659     size_t var_cnt;             /* Number of elements in var. */
660     struct hsh_table *name_tab; /* Hash from variable names to variables. */
661   };
662
663 /* Returns the number of variables in VS. */
664 static size_t
665 array_var_set_get_cnt (const struct var_set *vs) 
666 {
667   struct array_var_set *avs = vs->aux;
668
669   return avs->var_cnt;
670 }
671
672 /* Return variable with index IDX in VS.
673    IDX must be less than the number of variables in VS. */
674 static struct variable *
675 array_var_set_get_var (const struct var_set *vs, size_t idx) 
676 {
677   struct array_var_set *avs = vs->aux;
678
679   return (struct variable *) avs->var[idx];
680 }
681
682 /* Returns the index of the variable in VS named NAME, or -1 if
683    VS contains no variable with that name. */
684 static int
685 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
686 {
687   struct array_var_set *avs = vs->aux;
688   struct variable v, *vp, *const *vpp;
689
690   strcpy (v.name, name);
691   vp = &v;
692   vpp = hsh_find (avs->name_tab, &vp);
693   return vpp != NULL ? vpp - avs->var : -1;
694 }
695
696 /* Destroys VS. */
697 static void
698 array_var_set_destroy (struct var_set *vs) 
699 {
700   struct array_var_set *avs = vs->aux;
701
702   hsh_destroy (avs->name_tab);
703   free (avs);
704   free (vs);
705 }
706
707 /* Returns a variable set based on the VAR_CNT variables in
708    VAR. */
709 struct var_set *
710 var_set_create_from_array (struct variable *const *var, size_t var_cnt) 
711 {
712   struct var_set *vs;
713   struct array_var_set *avs;
714   size_t i;
715
716   vs = xmalloc (sizeof *vs);
717   vs->get_cnt = array_var_set_get_cnt;
718   vs->get_var = array_var_set_get_var;
719   vs->lookup_var_idx = array_var_set_lookup_var_idx;
720   vs->destroy = array_var_set_destroy;
721   vs->aux = avs = xmalloc (sizeof *avs);
722   avs->var = var;
723   avs->var_cnt = var_cnt;
724   avs->name_tab = hsh_create (2 * var_cnt,
725                               compare_var_ptr_names, hash_var_ptr_name, NULL,
726                               NULL);
727   for (i = 0; i < var_cnt; i++)
728     if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
729       {
730         var_set_destroy (vs);
731         return NULL;
732       }
733   
734   return vs;
735 }