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