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