Implemented long variable names a la spss V12.
[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  
138   vs = var_set_create_from_dict (d);
139   success = parse_var_set_vars (vs, var, cnt, opts);
140   if ( success == 0 )
141      free ( *var ) ;
142   var_set_destroy (vs);
143   return success;
144 }
145
146 /* Parses a variable name from VS.  If successful, sets *IDX to
147    the variable's index in VS, *CLASS to the variable's
148    dictionary class, and returns nonzero.  Returns zero on
149    failure. */
150 static int
151 parse_var_idx_class (const struct var_set *vs, int *idx,
152                      enum dict_class *class)
153 {
154   *idx = parse_vs_variable_idx (vs);
155   if (*idx < 0)
156     return 0;
157
158   *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
159   return 1;
160 }
161
162 /* Add the variable from VS with index IDX to the list of
163    variables V that has *NV elements and room for *MV.
164    Uses and updates INCLUDED to avoid duplicates if indicated by
165    PV_OPTS, which also affects what variables are allowed in
166    appropriate ways. */
167 static void
168 add_variable (struct variable ***v, int *nv, int *mv,
169               char *included, int pv_opts,
170               const struct var_set *vs, int idx)
171 {
172   struct variable *add = var_set_get_var (vs, idx);
173
174   if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) 
175     msg (SW, _("%s is not a numeric variable.  It will not be "
176                "included in the variable list."), add->name);
177   else if ((pv_opts & PV_STRING) && add->type != ALPHA) 
178     msg (SE, _("%s is not a string variable.  It will not be "
179                "included in the variable list."), add->name);
180   else if ((pv_opts & PV_NO_SCRATCH)
181            && dict_class_from_id (add->name) == DC_SCRATCH)
182     msg (SE, _("Scratch variables (such as %s) are not allowed "
183                "here."), add->name);
184   else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) 
185     msg (SE, _("%s and %s are not the same type.  All variables in "
186                "this variable list must be of the same type.  %s "
187                "will be omitted from list."),
188          (*v)[0]->name, add->name, add->name);
189   else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) 
190     msg (SE, _("Variable %s appears twice in variable list."), add->name);
191   else 
192     {
193       if (*nv >= *mv)
194         {
195           *mv = 2 * (*nv + 1);
196           *v = xrealloc (*v, *mv * sizeof **v);
197         }
198
199       if ((pv_opts & PV_DUPLICATE) || !included[idx])
200         {
201           (*v)[(*nv)++] = add;
202           if (!(pv_opts & PV_DUPLICATE))
203             included[idx] = 1;
204         }
205     }
206 }
207
208 /* Adds the variables in VS with indexes FIRST_IDX through
209    LAST_IDX, inclusive, to the list of variables V that has *NV
210    elements and room for *MV.  Uses and updates INCLUDED to avoid
211    duplicates if indicated by PV_OPTS, which also affects what
212    variables are allowed in appropriate ways. */
213 static void
214 add_variables (struct variable ***v, int *nv, int *mv, char *included,
215                int pv_opts,
216                const struct var_set *vs, int first_idx, int last_idx,
217                enum dict_class class) 
218 {
219   int i;
220   
221   for (i = first_idx; i <= last_idx; i++)
222     if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
223       add_variable (v, nv, mv, included, pv_opts, vs, i);
224 }
225
226 /* Note that if parse_variables() returns 0, *v is free()'d.
227    Conversely, if parse_variables() returns non-zero, then *nv is
228    nonzero and *v is non-NULL. */
229 int
230 parse_var_set_vars (const struct var_set *vs, 
231                     struct variable ***v, int *nv,
232                     int pv_opts)
233 {
234   int mv;
235   char *included;
236
237   assert (vs != NULL);
238   assert (v != NULL);
239   assert (nv != NULL);
240
241   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
242      specified. */
243   assert ((((pv_opts & PV_NUMERIC) != 0)
244            + ((pv_opts & PV_STRING) != 0)
245            + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
246
247   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
248   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
249
250   if (!(pv_opts & PV_APPEND))
251     {
252       *v = NULL;
253       *nv = 0;
254       mv = 0;
255     }
256   else
257     mv = *nv;
258
259   if (!(pv_opts & PV_DUPLICATE))
260     {
261       int i;
262       
263       included = xcalloc (var_set_get_cnt (vs));
264       for (i = 0; i < *nv; i++)
265         included[(*v)[i]->index] = 1;
266     }
267   else
268     included = NULL;
269
270 if (lex_match (T_ALL))
271     add_variables (v, nv, &mv, included, pv_opts,
272                    vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
273   else 
274     {
275       do
276         {
277           enum dict_class class;
278           int first_idx;
279           
280           if (!parse_var_idx_class (vs, &first_idx, &class))
281             goto fail;
282
283           if (!lex_match (T_TO))
284             add_variable (v, nv, &mv, included, pv_opts,
285                           vs, first_idx);
286           else 
287             {
288               int last_idx;
289               enum dict_class last_class;
290               struct variable *first_var, *last_var;
291
292               if (!parse_var_idx_class (vs, &last_idx, &last_class))
293                 goto fail;
294
295               first_var = var_set_get_var (vs, first_idx);
296               last_var = var_set_get_var (vs, last_idx);
297
298               if (last_idx < first_idx)
299                 {
300                   msg (SE, _("%s TO %s is not valid syntax since %s "
301                              "precedes %s in the dictionary."),
302                        first_var->name, last_var->name,
303                        first_var->name, last_var->name);
304                   goto fail;
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 (4 * (SHORT_NAME_LEN + 1));
413   name2 = &name1[1 * SHORT_NAME_LEN + 1];
414   root1 = &name1[2 * SHORT_NAME_LEN + 1];
415   root2 = &name1[3 * SHORT_NAME_LEN + 1];
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 (SHORT_NAME_LEN + 1);
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) <= LONG_NAME_LEN );
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     struct hsh_table *longname_tab; /* Hash of short names indexed by long names */
666   };
667
668 /* Returns the number of variables in VS. */
669 static size_t
670 array_var_set_get_cnt (const struct var_set *vs) 
671 {
672   struct array_var_set *avs = vs->aux;
673
674   return avs->var_cnt;
675 }
676
677 /* Return variable with index IDX in VS.
678    IDX must be less than the number of variables in VS. */
679 static struct variable *
680 array_var_set_get_var (const struct var_set *vs, size_t idx) 
681 {
682   struct array_var_set *avs = vs->aux;
683
684   return (struct variable *) avs->var[idx];
685 }
686
687 /* Returns the index of the variable in VS named NAME, or -1 if
688    VS contains no variable with that name. */
689 static int
690 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name) 
691 {
692   char *short_name ;
693   struct array_var_set *avs = vs->aux;
694   struct variable v, *vp, *const *vpp;
695
696   struct name_table_entry key;
697   key.longname = name;
698
699   struct name_table_entry *nte;
700
701   assert (avs->longname_tab);
702
703
704   nte = hsh_find (avs->longname_tab, &key);
705
706   if (!nte)
707     return -1;
708
709   short_name = nte->name;
710
711   strcpy (v.name, short_name);
712   vp = &v;
713   vpp = hsh_find (avs->name_tab, &vp);
714   return vpp != NULL ? vpp - avs->var : -1;
715 }
716
717 /* Destroys VS. */
718 static void
719 array_var_set_destroy (struct var_set *vs) 
720 {
721   struct array_var_set *avs = vs->aux;
722
723   hsh_destroy (avs->name_tab);
724   hsh_destroy (avs->longname_tab);
725   free (avs);
726   free (vs);
727 }
728
729 /* Returns a variable set based on the VAR_CNT variables in
730    VAR. */
731 struct var_set *
732 var_set_create_from_array (struct variable *const *var, size_t var_cnt) 
733 {
734   struct var_set *vs;
735   struct array_var_set *avs;
736   size_t i;
737
738   vs = xmalloc (sizeof *vs);
739   vs->get_cnt = array_var_set_get_cnt;
740   vs->get_var = array_var_set_get_var;
741   vs->lookup_var_idx = array_var_set_lookup_var_idx;
742   vs->destroy = array_var_set_destroy;
743   vs->aux = avs = xmalloc (sizeof *avs);
744   avs->var = var;
745   avs->var_cnt = var_cnt;
746   avs->name_tab = hsh_create (2 * var_cnt,
747                               compare_var_ptr_names, hash_var_ptr_name, 
748                               NULL, NULL);
749
750   avs->longname_tab = hsh_create (2 * var_cnt, 
751                                    compare_long_names, hash_long_name, 
752                                    NULL, NULL);
753   
754   for (i = 0; i < var_cnt; i++)
755     {
756       struct name_table_entry *nte ;
757
758       if (hsh_insert (avs->name_tab, &var[i]) != NULL) 
759         {
760           var_set_destroy (vs);
761           return NULL;
762         }
763
764       nte = xmalloc (sizeof (*nte));
765       nte->name = strdup(var[i]->name);
766       nte->longname = strdup(var[i]->longname);
767
768       if (hsh_insert (avs->longname_tab, nte) != NULL) 
769         {
770           var_set_destroy (vs);
771           free (nte);
772           return NULL;
773         }
774
775     }
776
777   return vs;
778 }