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