checkin of 0.3.0
[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 /* AIX requires this to be the first thing in the file.  */
21 #include <config.h>
22 #if __GNUC__
23 #define alloca __builtin_alloca
24 #else
25 #if HAVE_ALLOCA_H
26 #include <alloca.h>
27 #else
28 #ifdef _AIX
29 #pragma alloca
30 #else
31 #ifndef alloca                  /* predefined by HP cc +Olibcalls */
32 char *alloca ();
33 #endif
34 #endif
35 #endif
36 #endif
37
38 #include <assert.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include "alloc.h"
42 #include "avl.h"
43 #include "bitvector.h"
44 #include "error.h"
45 #include "lexer.h"
46 #include "misc.h"
47 #include "str.h"
48 #include "var.h"
49
50 /* Allocates an array at *V to contain all the variables in
51    default_dict.  If FV_NO_SYSTEM is set in FLAGS then system
52    variables will not be included.  If FV_NO_SCRATCH is set in FLAGS
53    then scratch variables will not be included.  *C is set to the
54    number of variables in *V. */
55 void
56 fill_all_vars (struct variable ***varlist, int *c, int flags)
57 {
58   int i;
59
60   *varlist = xmalloc (default_dict.nvar * sizeof **varlist);
61   if (flags == FV_NONE)
62     {
63       *c = default_dict.nvar;
64       for (i = 0; i < default_dict.nvar; i++)
65         (*varlist)[i] = default_dict.var[i];
66     }
67   else
68     {
69       *c = 0;
70       
71       for (i = 0; i < default_dict.nvar; i++)
72         {
73           struct variable *v = default_dict.var[i];
74
75           if ((flags & FV_NO_SYSTEM) && v->name[0] == '$')
76             continue;
77           if ((flags & FV_NO_SCRATCH) && v->name[0] == '#')
78             continue;
79           
80           (*varlist)[*c] = v;
81           (*c)++;
82         }
83       
84       if (*c != default_dict.nvar)
85         *varlist = xrealloc (*varlist, *c * sizeof **varlist);
86     }
87 }
88
89 int
90 is_varname (const char *s)
91 {
92   return avl_find (default_dict.var_by_name, (struct variable *) s) != 0;
93 }
94
95 int
96 is_dict_varname (const struct dictionary *dict, const char *s)
97 {
98   return avl_find (dict->var_by_name, (struct variable *) s) != 0;
99 }
100
101 struct variable *
102 parse_variable (void)
103 {
104   struct variable *vp;
105
106   if (token != T_ID)
107     {
108       lex_error ("expecting variable name");
109       return NULL;
110     }
111   vp = find_variable (tokid);
112   if (!vp)
113     msg (SE, _("%s is not declared as a variable."), tokid);
114   lex_get ();
115   return vp;
116 }
117
118 struct variable *
119 parse_dict_variable (struct dictionary * dict)
120 {
121   struct variable *vp;
122
123   if (token != T_ID)
124     {
125       lex_error ("expecting variable name");
126       return NULL;
127     }
128
129   vp = avl_find (dict->var_by_name, (struct variable *) tokid);
130   if (!vp)
131     msg (SE, _("%s is not a variable name."), tokid);
132   lex_get ();
133
134   return vp;
135 }
136
137 /* Returns the dictionary class of an identifier based on its
138    first letter: `X' if is an ordinary identifier, `$' if it
139    designates a system variable, `#' if it designates a scratch
140    variable. */
141 #define id_dict(C)                                      \
142         ((C) == '$' ? '$' : ((C) == '#' ? '#' : 'X'))
143
144 /* FIXME: One interesting variation in the case of PV_APPEND would be
145    to keep the bitmap, reducing time required to an actual O(n log n)
146    instead of having to reproduce the bitmap *every* *single* *time*.
147    Later though.  (Another idea would be to keep a marker bit in each
148    variable.) */
149 /* Note that if parse_variables() returns 0, *v is free()'d.
150    Conversely, if parse_variables() returns non-zero, then *nv is
151    nonzero and *v is non-NULL. */
152 int
153 parse_variables (struct dictionary * dict, struct variable *** v, int *nv, int pv_opts)
154 {
155   int i;
156   int nbytes;
157   unsigned char *bits;
158
159   struct variable *v1, *v2;
160   int count, mv;
161   int scratch;                  /* Dictionary we're reading from. */
162   int delayed_fail = 0;
163
164   if (dict == NULL)
165     dict = &default_dict;
166
167   if (!(pv_opts & PV_APPEND))
168     {
169       *v = NULL;
170       *nv = 0;
171       mv = 0;
172     }
173   else
174     mv = *nv;
175
176 #if GLOBAL_DEBUGGING
177   {
178     int corrupt = 0;
179     int i;
180
181     for (i = 0; i < dict->nvar; i++)
182       if (dict->var[i]->index != i)
183         {
184           printf ("%s index corruption: variable %s\n",
185                   dict == &default_dict ? "default_dict" : "aux dict",
186                   dict->var[i]->name);
187           corrupt = 1;
188         }
189     
190     assert (!corrupt);
191   }
192 #endif
193
194   nbytes = DIV_RND_UP (dict->nvar, 8);
195   if (!(pv_opts & PV_DUPLICATE))
196     {
197       bits = local_alloc (nbytes);
198       memset (bits, 0, nbytes);
199       for (i = 0; i < *nv; i++)
200         SET_BIT (bits, (*v)[i]->index);
201     }
202
203   do
204     {
205       if (lex_match (T_ALL))
206         {
207           v1 = dict->var[0];
208           v2 = dict->var[dict->nvar - 1];
209           count = dict->nvar;
210           scratch = id_dict ('X');
211         }
212       else
213         {
214           v1 = parse_dict_variable (dict);
215           if (!v1)
216             goto fail;
217
218           if (lex_match (T_TO))
219             {
220               v2 = parse_dict_variable (dict);
221               if (!v2)
222                 {
223                   lex_error ("expecting variable name");
224                   goto fail;
225                 }
226
227               count = v2->index - v1->index + 1;
228               if (count < 1)
229                 {
230                   msg (SE, _("%s TO %s is not valid syntax since %s "
231                        "precedes %s in the dictionary."),
232                        v1->name, v2->name, v2->name, v1->name);
233                   goto fail;
234                 }
235
236               scratch = id_dict (v1->name[0]);
237               if (scratch != id_dict (v2->name[0]))
238                 {
239                   msg (SE, _("When using the TO keyword to specify several "
240                        "variables, both variables must be from "
241                        "the same variable dictionaries, of either "
242                        "ordinary, scratch, or system variables.  "
243                        "%s and %s are from different dictionaries."),
244                        v1->name, v2->name);
245                   goto fail;
246                 }
247             }
248           else
249             {
250               v2 = v1;
251               count = 1;
252               scratch = id_dict (v1->name[0]);
253             }
254           if (scratch == id_dict ('#') && (pv_opts & PV_NO_SCRATCH))
255             {
256               msg (SE, _("Scratch variables (such as %s) are not allowed "
257                          "here."), v1->name);
258               goto fail;
259             }
260         }
261
262       if (*nv + count > mv)
263         {
264           mv += ROUND_UP (count, 16);
265           *v = xrealloc (*v, mv * sizeof **v);
266         }
267
268       for (i = v1->index; i <= v2->index; i++)
269         {
270           struct variable *add = dict->var[i];
271
272           /* Skip over other dictionaries. */
273           if (scratch != id_dict (add->name[0]))
274             continue;
275
276           if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC)
277             {
278               delayed_fail = 1;
279               msg (SW, _("%s is not a numeric variable.  It will not be "
280                          "included in the variable list."), add->name);
281             }
282           else if ((pv_opts & PV_STRING) && add->type != ALPHA)
283             {
284               delayed_fail = 1;
285               msg (SE, _("%s is not a string variable.  It will not be "
286                          "included in the variable list."), add->name);
287             }
288           else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type)
289             {
290               delayed_fail = 1;
291               msg (SE, _("%s and %s are not the same type.  All variables in "
292                          "this variable list must be of the same type.  %s "
293                          "will be omitted from list."),
294                    (*v)[0]->name, add->name, add->name);
295             }
296           else if ((pv_opts & PV_NO_DUPLICATE) && TEST_BIT (bits, add->index))
297             {
298               delayed_fail = 1;
299               msg (SE, _("Variable %s appears twice in variable list."),
300                    add->name);
301             }
302           else if ((pv_opts & PV_DUPLICATE) || !TEST_BIT (bits, add->index))
303             {
304               (*v)[(*nv)++] = dict->var[i];
305               if (!(pv_opts & PV_DUPLICATE))
306                 SET_BIT (bits, add->index);
307             }
308         }
309
310       if (pv_opts & PV_SINGLE)
311         {
312           if (delayed_fail)
313             goto fail;
314           else
315             return 1;
316         }
317       lex_match (',');
318     }
319   while ((token == T_ID && is_dict_varname (dict, tokid)) || token == T_ALL);
320
321   if (!(pv_opts & PV_DUPLICATE))
322     local_free (bits);
323   if (!nv)
324     goto fail;
325   return 1;
326
327 fail:
328   free (*v);
329   *v = NULL;
330   *nv = 0;
331   if (!(pv_opts & PV_DUPLICATE))
332     local_free (bits);
333   return 0;
334 }
335
336 static int
337 extract_num (char *s, char *r, int *n, int *d)
338 {
339   char *cp;
340
341   /* Find first digit. */
342   cp = s + strlen (s) - 1;
343   while (isdigit ((unsigned char) *cp) && cp > s)
344     cp--;
345   cp++;
346
347   /* Extract root. */
348   strncpy (r, s, cp - s);
349   r[cp - s] = 0;
350
351   /* Count initial zeros. */
352   *n = *d = 0;
353   while (*cp == '0')
354     {
355       (*d)++;
356       cp++;
357     }
358
359   /* Extract value. */
360   while (isdigit ((unsigned char) *cp))
361     {
362       (*d)++;
363       *n = (*n * 10) + (*cp - '0');
364       cp++;
365     }
366
367   /* Sanity check. */
368   if (*n == 0 && *d == 0)
369     {
370       msg (SE, _("incorrect use of TO convention"));
371       return 0;
372     }
373   return 1;
374 }
375
376 /* Parses a list of variable names according to the DATA LIST version
377    of the TO convention.  */
378 int
379 parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts)
380 {
381   int n1, n2;
382   int d1, d2;
383   int n;
384   int nvar, mvar;
385   char *name1, *name2;
386   char *root1, *root2;
387   int success = 0;
388
389   if (pv_opts & PV_APPEND)
390     nvar = mvar = *nnames;
391   else
392     {
393       nvar = mvar = 0;
394       *names = NULL;
395     }
396
397   name1 = xmalloc (36);
398   name2 = &name1[1 * 9];
399   root1 = &name1[2 * 9];
400   root2 = &name1[3 * 9];
401   do
402     {
403       if (token != T_ID)
404         {
405           lex_error ("expecting variable name");
406           goto fail;
407         }
408       if (tokid[0] == '#' && (pv_opts & PV_NO_SCRATCH))
409         {
410           msg (SE, _("Scratch variables not allowed here."));
411           goto fail;
412         }
413       strcpy (name1, tokid);
414       lex_get ();
415       if (token == T_TO)
416         {
417           lex_get ();
418           if (token != T_ID)
419             {
420               lex_error ("expecting variable name");
421               goto fail;
422             }
423           strcpy (name2, tokid);
424           lex_get ();
425
426           if (!extract_num (name1, root1, &n1, &d1)
427               || !extract_num (name2, root2, &n2, &d2))
428             goto fail;
429
430           if (strcmp (root1, root2))
431             {
432               msg (SE, _("Prefixes don't match in use of TO convention."));
433               goto fail;
434             }
435           if (n1 > n2)
436             {
437               msg (SE, _("Bad bounds in use of TO convention."));
438               goto fail;
439             }
440           if (d2 > d1)
441             d2 = d1;
442
443           if (mvar < nvar + (n2 - n1 + 1))
444             {
445               mvar += ROUND_UP (n2 - n1 + 1, 16);
446               *names = xrealloc (*names, mvar * sizeof **names);
447             }
448
449           for (n = n1; n <= n2; n++)
450             {
451               (*names)[nvar] = xmalloc (9);
452               sprintf ((*names)[nvar], "%s%0*d", root1, d1, n);
453               nvar++;
454             }
455         }
456       else
457         {
458           if (nvar >= mvar)
459             {
460               mvar += 16;
461               *names = xrealloc (*names, mvar * sizeof **names);
462             }
463           (*names)[nvar++] = xstrdup (name1);
464         }
465
466       lex_match (',');
467
468       if (pv_opts & PV_SINGLE)
469         break;
470     }
471   while (token == T_ID);
472   success = 1;
473
474 fail:
475   *nnames = nvar;
476   free (name1);
477   if (!success)
478     {
479       int i;
480       for (i = 0; i < nvar; i++)
481         free ((*names)[i]);
482       free (*names);
483       *names = NULL;
484       *nnames = 0;
485     }
486   return success;
487 }
488
489 /* Parses a list of variables where some of the variables may be
490    existing and the rest are to be created.  Same args as
491    parse_variables(). */
492 int
493 parse_mixed_vars (char ***names, int *nnames, int pv_opts)
494 {
495   int i;
496
497   if (!(pv_opts & PV_APPEND))
498     {
499       *names = NULL;
500       *nnames = 0;
501     }
502   while (token == T_ID || token == T_ALL)
503     {
504       if (token == T_ALL || is_varname (tokid))
505         {
506           struct variable **v;
507           int nv;
508
509           if (!parse_variables (NULL, &v, &nv, PV_NONE))
510             goto fail;
511           *names = xrealloc (*names, (*nnames + nv) * sizeof **names);
512           for (i = 0; i < nv; i++)
513             (*names)[*nnames + i] = xstrdup (v[i]->name);
514           free (v);
515           *nnames += nv;
516         }
517       else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
518         goto fail;
519     }
520   return 1;
521
522 fail:
523   for (i = 0; i < *nnames; i++)
524     free ((*names)[*nnames]);
525   free (names);
526   *names = NULL;
527   *nnames = 0;
528   return 0;
529 }