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