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