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