9a559d2e0ca016f3bd894a9e4014c808dc986b9e
[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., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, 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));
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, *name2;
395   char *root1, *root2;
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   name1 = xmalloc (36);
413   name2 = &name1[1 * 9];
414   root1 = &name1[2 * 9];
415   root2 = &name1[3 * 9];
416   do
417     {
418       if (token != T_ID)
419         {
420           lex_error ("expecting variable name");
421           goto fail;
422         }
423       if (dict_class_from_id (tokid) == DC_SCRATCH
424           && (pv_opts & PV_NO_SCRATCH))
425         {
426           msg (SE, _("Scratch variables not allowed here."));
427           goto fail;
428         }
429       strcpy (name1, tokid);
430       lex_get ();
431       if (token == T_TO)
432         {
433           lex_get ();
434           if (token != T_ID)
435             {
436               lex_error ("expecting variable name");
437               goto fail;
438             }
439           strcpy (name2, tokid);
440           lex_get ();
441
442           if (!extract_num (name1, root1, &n1, &d1)
443               || !extract_num (name2, root2, &n2, &d2))
444             goto fail;
445
446           if (strcmp (root1, root2))
447             {
448               msg (SE, _("Prefixes don't match in use of TO convention."));
449               goto fail;
450             }
451           if (n1 > n2)
452             {
453               msg (SE, _("Bad bounds in use of TO convention."));
454               goto fail;
455             }
456           if (d2 > d1)
457             d2 = d1;
458
459           if (mvar < nvar + (n2 - n1 + 1))
460             {
461               mvar += ROUND_UP (n2 - n1 + 1, 16);
462               *names = xrealloc (*names, mvar * sizeof **names);
463             }
464
465           for (n = n1; n <= n2; n++)
466             {
467               (*names)[nvar] = xmalloc (9);
468               sprintf ((*names)[nvar], "%s%0*d", root1, d1, n);
469               nvar++;
470             }
471         }
472       else
473         {
474           if (nvar >= mvar)
475             {
476               mvar += 16;
477               *names = xrealloc (*names, mvar * sizeof **names);
478             }
479           (*names)[nvar++] = xstrdup (name1);
480         }
481
482       lex_match (',');
483
484       if (pv_opts & PV_SINGLE)
485         break;
486     }
487   while (token == T_ID);
488   success = 1;
489
490 fail:
491   *nnames = nvar;
492   free (name1);
493   if (!success)
494     {
495       int i;
496       for (i = 0; i < nvar; i++)
497         free ((*names)[i]);
498       free (*names);
499       *names = NULL;
500       *nnames = 0;
501     }
502   return success;
503 }
504
505 /* Parses a list of variables where some of the variables may be
506    existing and the rest are to be created.  Same args as
507    parse_DATA_LIST_vars(). */
508 int
509 parse_mixed_vars (char ***names, int *nnames, int pv_opts)
510 {
511   int i;
512
513   assert (names != NULL);
514   assert (nnames != NULL);
515   assert ((pv_opts & ~PV_APPEND) == 0);
516
517   if (!(pv_opts & PV_APPEND))
518     {
519       *names = NULL;
520       *nnames = 0;
521     }
522   while (token == T_ID || token == T_ALL)
523     {
524       if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
525         {
526           struct variable **v;
527           int nv;
528
529           if (!parse_variables (default_dict, &v, &nv, PV_NONE))
530             goto fail;
531           *names = xrealloc (*names, (*nnames + nv) * sizeof **names);
532           for (i = 0; i < nv; i++)
533             (*names)[*nnames + i] = xstrdup (v[i]->name);
534           free (v);
535           *nnames += nv;
536         }
537       else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
538         goto fail;
539     }
540   return 1;
541
542 fail:
543   for (i = 0; i < *nnames; i++)
544     free ((*names)[*nnames]);
545   free (names);
546   *names = NULL;
547   *nnames = 0;
548   return 0;
549 }
550 \f
551 /* A set of variables. */
552 struct var_set 
553   {
554     size_t (*get_cnt) (const struct var_set *);
555     struct variable *(*get_var) (const struct var_set *, size_t idx);
556     int (*lookup_var_idx) (const struct var_set *, const char *);
557     void (*destroy) (struct var_set *);
558     void *aux;
559   };
560
561 /* Returns the number of variables in VS. */
562 size_t
563 var_set_get_cnt (const struct var_set *vs) 
564 {
565   assert (vs != NULL);
566
567   return vs->get_cnt (vs);
568 }
569
570 /* Return variable with index IDX in VS.
571    IDX must be less than the number of variables in VS. */
572 struct variable *
573 var_set_get_var (const struct var_set *vs, size_t idx) 
574 {
575   assert (vs != NULL);
576   assert (idx < var_set_get_cnt (vs));
577
578   return vs->get_var (vs, idx);
579 }
580
581 /* Returns the variable in VS named NAME, or a null pointer if VS
582    contains no variable with that name. */
583 struct variable *
584 var_set_lookup_var (const struct var_set *vs, const char *name) 
585 {
586   int idx = var_set_lookup_var_idx (vs, name);
587   return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
588 }
589
590 /* Returns the index in VS of the variable named NAME, or -1 if
591    VS contains no variable with that name. */
592 int
593 var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
594 {
595   assert (vs != NULL);
596   assert (name != NULL);
597   assert (strlen (name) < 9);
598
599   return vs->lookup_var_idx (vs, name);
600 }
601
602 /* Destroys VS. */
603 void
604 var_set_destroy (struct var_set *vs) 
605 {
606   if (vs != NULL)
607     vs->destroy (vs);
608 }
609 \f
610 /* Returns the number of variables in VS. */
611 static size_t
612 dict_var_set_get_cnt (const struct var_set *vs) 
613 {
614   struct dictionary *d = vs->aux;
615
616   return dict_get_var_cnt (d);
617 }
618
619 /* Return variable with index IDX in VS.
620    IDX must be less than the number of variables in VS. */
621 static struct variable *
622 dict_var_set_get_var (const struct var_set *vs, size_t idx) 
623 {
624   struct dictionary *d = vs->aux;
625
626   return dict_get_var (d, idx);
627 }
628
629 /* Returns the index of the variable in VS named NAME, or -1 if
630    VS contains no variable with that name. */
631 static int
632 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
633 {
634   struct dictionary *d = vs->aux;
635   struct variable *v = dict_lookup_var (d, name);
636   return v != NULL ? v->index : -1;
637 }
638
639 /* Destroys VS. */
640 static void
641 dict_var_set_destroy (struct var_set *vs) 
642 {
643   free (vs);
644 }
645
646 /* Returns a variable set based on D. */
647 struct var_set *
648 var_set_create_from_dict (const struct dictionary *d) 
649 {
650   struct var_set *vs = xmalloc (sizeof *vs);
651   vs->get_cnt = dict_var_set_get_cnt;
652   vs->get_var = dict_var_set_get_var;
653   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
654   vs->destroy = dict_var_set_destroy;
655   vs->aux = (void *) d;
656   return vs;
657 }
658 \f
659 /* A variable set based on an array. */
660 struct array_var_set 
661   {
662     struct variable *const *var;/* Array of variables. */
663     size_t var_cnt;             /* Number of elements in var. */
664     struct hsh_table *name_tab; /* Hash from variable names to variables. */
665   };
666
667 /* Returns the number of variables in VS. */
668 static size_t
669 array_var_set_get_cnt (const struct var_set *vs) 
670 {
671   struct array_var_set *avs = vs->aux;
672
673   return avs->var_cnt;
674 }
675
676 /* Return variable with index IDX in VS.
677    IDX must be less than the number of variables in VS. */
678 static struct variable *
679 array_var_set_get_var (const struct var_set *vs, size_t idx) 
680 {
681   struct array_var_set *avs = vs->aux;
682
683   return (struct variable *) avs->var[idx];
684 }
685
686 /* Returns the index of the variable in VS named NAME, or -1 if
687    VS contains no variable with that name. */
688 static int
689 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
690 {
691   struct array_var_set *avs = vs->aux;
692   struct variable v, *vp, *const *vpp;
693
694   strcpy (v.name, name);
695   vp = &v;
696   vpp = hsh_find (avs->name_tab, &vp);
697   return vpp != NULL ? vpp - avs->var : -1;
698 }
699
700 /* Destroys VS. */
701 static void
702 array_var_set_destroy (struct var_set *vs) 
703 {
704   struct array_var_set *avs = vs->aux;
705
706   hsh_destroy (avs->name_tab);
707   free (avs);
708   free (vs);
709 }
710
711 /* Returns a variable set based on the VAR_CNT variables in
712    VAR. */
713 struct var_set *
714 var_set_create_from_array (struct variable *const *var, size_t var_cnt) 
715 {
716   struct var_set *vs;
717   struct array_var_set *avs;
718   size_t i;
719
720   vs = xmalloc (sizeof *vs);
721   vs->get_cnt = array_var_set_get_cnt;
722   vs->get_var = array_var_set_get_var;
723   vs->lookup_var_idx = array_var_set_lookup_var_idx;
724   vs->destroy = array_var_set_destroy;
725   vs->aux = avs = xmalloc (sizeof *avs);
726   avs->var = var;
727   avs->var_cnt = var_cnt;
728   avs->name_tab = hsh_create (2 * var_cnt,
729                               compare_var_ptr_names, hash_var_ptr_name, NULL,
730                               NULL);
731   for (i = 0; i < var_cnt; i++)
732     if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
733       {
734         var_set_destroy (vs);
735         return NULL;
736       }
737   
738   return vs;
739 }