You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
-/* AIX requires this to be the first thing in the file. */
#include <config.h>
-#if __GNUC__
-#define alloca __builtin_alloca
-#else
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else
-#ifdef _AIX
-#pragma alloca
-#else
-#ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#endif
-#endif
-#endif
-#endif
-
-#include <assert.h>
+#include "var.h"
#include <ctype.h>
#include <stdlib.h>
#include "alloc.h"
#include "bitvector.h"
+#include "dictionary.h"
#include "error.h"
#include "hash.h"
#include "lexer.h"
#include "misc.h"
#include "str.h"
-#include "var.h"
-/* Allocates an array at *V to contain all the variables in
- default_dict. If FV_NO_SYSTEM is set in FLAGS then system
- variables will not be included. If FV_NO_SCRATCH is set in FLAGS
- then scratch variables will not be included. *C is set to the
- number of variables in *V. */
-void
-fill_all_vars (struct variable ***varlist, int *c, int flags)
+/* Parses a name as a variable within VS and returns the
+ variable's index if successful. On failure emits an error
+ message and returns a null pointer. */
+static int
+parse_vs_variable_idx (const struct var_set *vs)
{
- int i;
+ int idx;
- *varlist = xmalloc (default_dict.nvar * sizeof **varlist);
- if (flags == FV_NONE)
+ if (token != T_ID)
{
- *c = default_dict.nvar;
- for (i = 0; i < default_dict.nvar; i++)
- (*varlist)[i] = default_dict.var[i];
- }
- else
- {
- *c = 0;
-
- for (i = 0; i < default_dict.nvar; i++)
- {
- struct variable *v = default_dict.var[i];
-
- if ((flags & FV_NO_SYSTEM) && v->name[0] == '$')
- continue;
- if ((flags & FV_NO_SCRATCH) && v->name[0] == '#')
- continue;
-
- (*varlist)[*c] = v;
- (*c)++;
- }
-
- if (*c != default_dict.nvar)
- *varlist = xrealloc (*varlist, *c * sizeof **varlist);
+ lex_error (_("expecting variable name"));
+ return -1;
}
+
+ idx = var_set_lookup_var_idx (vs, tokid);
+ if (idx < 0)
+ msg (SE, _("%s is not a variable name."), tokid);
+ lex_get ();
+
+ return idx;
}
-int
-is_varname (const char *s)
+/* Parses a name as a variable within VS and returns the variable
+ if successful. On failure emits an error message and returns
+ a null pointer. */
+static struct variable *
+parse_vs_variable (const struct var_set *vs)
{
- return hsh_find (default_dict.name_tab, s) != NULL;
+ int idx = parse_vs_variable_idx (vs);
+ return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
}
-int
-is_dict_varname (const struct dictionary *dict, const char *s)
+/* Parses a variable name in dictionary D and returns the
+ variable if successful. On failure emits an error message and
+ returns a null pointer. */
+struct variable *
+parse_dict_variable (const struct dictionary *d)
{
- return hsh_find (dict->name_tab, s) != NULL;
+ struct var_set *vs = var_set_create_from_dict (d);
+ struct variable *var = parse_vs_variable (vs);
+ var_set_destroy (vs);
+ return var;
}
+/* Parses a variable name in default_dict and returns the
+ variable if successful. On failure emits an error message and
+ returns a null pointer. */
struct variable *
parse_variable (void)
{
- struct variable *vp;
+ return parse_dict_variable (default_dict);
+}
- if (token != T_ID)
+/* Returns the dictionary class corresponding to a variable named
+ NAME. */
+enum dict_class
+dict_class_from_id (const char *name)
+{
+ assert (name != NULL);
+
+ switch (name[0])
{
- lex_error ("expecting variable name");
- return NULL;
+ default:
+ return DC_ORDINARY;
+ case '$':
+ return DC_SYSTEM;
+ case '#':
+ return DC_SCRATCH;
}
- vp = find_variable (tokid);
- if (!vp)
- msg (SE, _("%s is not declared as a variable."), tokid);
- lex_get ();
- return vp;
}
-struct variable *
-parse_dict_variable (struct dictionary * dict)
+/* Returns the name of dictionary class DICT_CLASS. */
+const char *
+dict_class_to_name (enum dict_class dict_class)
{
- struct variable *vp;
-
- if (token != T_ID)
+ switch (dict_class)
{
- lex_error ("expecting variable name");
- return NULL;
+ case DC_ORDINARY:
+ return _("ordinary");
+ case DC_SYSTEM:
+ return _("system");
+ case DC_SCRATCH:
+ return _("scratch");
+ default:
+ assert (0);
+ abort ();
}
+}
- vp = hsh_find (dict->name_tab, tokid);
- if (!vp)
- msg (SE, _("%s is not a variable name."), tokid);
- lex_get ();
+/* Parses a set of variables from dictionary D given options
+ OPTS. Resulting list of variables stored in *VAR and the
+ number of variables into *CNT. Returns nonzero only if
+ successful. */
+int
+parse_variables (const struct dictionary *d, struct variable ***var,
+ int *cnt, int opts)
+{
+ struct var_set *vs;
+ int success;
+
+ assert (d != NULL);
+ assert (var != NULL);
+ assert (cnt != NULL);
+
+ vs = var_set_create_from_dict (d);
+ success = parse_var_set_vars (vs, var, cnt, opts);
+ if ( success == 0 )
+ free ( *var ) ;
+ var_set_destroy (vs);
+ return success;
+}
+
+/* Parses a variable name from VS. If successful, sets *IDX to
+ the variable's index in VS, *CLASS to the variable's
+ dictionary class, and returns nonzero. Returns zero on
+ failure. */
+static int
+parse_var_idx_class (const struct var_set *vs, int *idx,
+ enum dict_class *class)
+{
+ *idx = parse_vs_variable_idx (vs);
+ if (*idx < 0)
+ return 0;
- return vp;
+ *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
+ return 1;
+}
+
+/* Add the variable from VS with index IDX to the list of
+ variables V that has *NV elements and room for *MV.
+ Uses and updates INCLUDED to avoid duplicates if indicated by
+ PV_OPTS, which also affects what variables are allowed in
+ appropriate ways. */
+static void
+add_variable (struct variable ***v, int *nv, int *mv,
+ char *included, int pv_opts,
+ const struct var_set *vs, int idx)
+{
+ struct variable *add = var_set_get_var (vs, idx);
+
+ if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC)
+ msg (SW, _("%s is not a numeric variable. It will not be "
+ "included in the variable list."), add->name);
+ else if ((pv_opts & PV_STRING) && add->type != ALPHA)
+ msg (SE, _("%s is not a string variable. It will not be "
+ "included in the variable list."), add->name);
+ else if ((pv_opts & PV_NO_SCRATCH)
+ && dict_class_from_id (add->name) == DC_SCRATCH)
+ msg (SE, _("Scratch variables (such as %s) are not allowed "
+ "here."), add->name);
+ else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type)
+ msg (SE, _("%s and %s are not the same type. All variables in "
+ "this variable list must be of the same type. %s "
+ "will be omitted from list."),
+ (*v)[0]->name, add->name, add->name);
+ else if ((pv_opts & PV_NO_DUPLICATE) && included[idx])
+ msg (SE, _("Variable %s appears twice in variable list."), add->name);
+ else
+ {
+ if (*nv >= *mv)
+ {
+ *mv = 2 * (*nv + 1);
+ *v = xrealloc (*v, *mv * sizeof **v);
+ }
+
+ if ((pv_opts & PV_DUPLICATE) || !included[idx])
+ {
+ (*v)[(*nv)++] = add;
+ if (!(pv_opts & PV_DUPLICATE))
+ included[idx] = 1;
+ }
+ }
+}
+
+/* Adds the variables in VS with indexes FIRST_IDX through
+ LAST_IDX, inclusive, to the list of variables V that has *NV
+ elements and room for *MV. Uses and updates INCLUDED to avoid
+ duplicates if indicated by PV_OPTS, which also affects what
+ variables are allowed in appropriate ways. */
+static void
+add_variables (struct variable ***v, int *nv, int *mv, char *included,
+ int pv_opts,
+ const struct var_set *vs, int first_idx, int last_idx,
+ enum dict_class class)
+{
+ int i;
+
+ for (i = first_idx; i <= last_idx; i++)
+ if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
+ add_variable (v, nv, mv, included, pv_opts, vs, i);
}
-/* Returns the dictionary class of an identifier based on its
- first letter: `X' if is an ordinary identifier, `$' if it
- designates a system variable, `#' if it designates a scratch
- variable. */
-#define id_dict(C) \
- ((C) == '$' ? '$' : ((C) == '#' ? '#' : 'X'))
-
-/* FIXME: One interesting variation in the case of PV_APPEND would be
- to keep the bitmap, reducing time required to an actual O(n log n)
- instead of having to reproduce the bitmap *every* *single* *time*.
- Later though. (Another idea would be to keep a marker bit in each
- variable.) */
/* Note that if parse_variables() returns 0, *v is free()'d.
Conversely, if parse_variables() returns non-zero, then *nv is
nonzero and *v is non-NULL. */
int
-parse_variables (struct dictionary * dict, struct variable *** v, int *nv, int pv_opts)
+parse_var_set_vars (const struct var_set *vs,
+ struct variable ***v, int *nv,
+ int pv_opts)
{
- int i;
- int nbytes;
- unsigned char *bits;
+ int mv;
+ char *included;
- struct variable *v1, *v2;
- int count, mv;
- int scratch; /* Dictionary we're reading from. */
- int delayed_fail = 0;
+ assert (vs != NULL);
+ assert (v != NULL);
+ assert (nv != NULL);
- if (dict == NULL)
- dict = &default_dict;
+ /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
+ specified. */
+ assert ((((pv_opts & PV_NUMERIC) != 0)
+ + ((pv_opts & PV_STRING) != 0)
+ + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
+
+ /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
+ assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
if (!(pv_opts & PV_APPEND))
{
else
mv = *nv;
-#if GLOBAL_DEBUGGING
- {
- int corrupt = 0;
- int i;
-
- for (i = 0; i < dict->nvar; i++)
- if (dict->var[i]->index != i)
- {
- printf ("%s index corruption: variable %s\n",
- dict == &default_dict ? "default_dict" : "aux dict",
- dict->var[i]->name);
- corrupt = 1;
- }
-
- assert (!corrupt);
- }
-#endif
-
- nbytes = DIV_RND_UP (dict->nvar, 8);
if (!(pv_opts & PV_DUPLICATE))
{
- bits = local_alloc (nbytes);
- memset (bits, 0, nbytes);
+ int i;
+
+ included = xcalloc (var_set_get_cnt (vs));
for (i = 0; i < *nv; i++)
- SET_BIT (bits, (*v)[i]->index);
+ included[(*v)[i]->index] = 1;
}
+ else
+ included = NULL;
- do
+ if (lex_match (T_ALL))
+ add_variables (v, nv, &mv, included, pv_opts,
+ vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
+ else
{
- if (lex_match (T_ALL))
- {
- v1 = dict->var[0];
- v2 = dict->var[dict->nvar - 1];
- count = dict->nvar;
- scratch = id_dict ('X');
- }
- else
- {
- v1 = parse_dict_variable (dict);
- if (!v1)
- goto fail;
-
- if (lex_match (T_TO))
- {
- v2 = parse_dict_variable (dict);
- if (!v2)
- {
- lex_error ("expecting variable name");
- goto fail;
- }
-
- count = v2->index - v1->index + 1;
- if (count < 1)
- {
- msg (SE, _("%s TO %s is not valid syntax since %s "
- "precedes %s in the dictionary."),
- v1->name, v2->name, v2->name, v1->name);
- goto fail;
- }
-
- scratch = id_dict (v1->name[0]);
- if (scratch != id_dict (v2->name[0]))
- {
- msg (SE, _("When using the TO keyword to specify several "
- "variables, both variables must be from "
- "the same variable dictionaries, of either "
- "ordinary, scratch, or system variables. "
- "%s and %s are from different dictionaries."),
- v1->name, v2->name);
- goto fail;
- }
- }
- else
- {
- v2 = v1;
- count = 1;
- scratch = id_dict (v1->name[0]);
- }
- if (scratch == id_dict ('#') && (pv_opts & PV_NO_SCRATCH))
- {
- msg (SE, _("Scratch variables (such as %s) are not allowed "
- "here."), v1->name);
- goto fail;
- }
- }
-
- if (*nv + count > mv)
- {
- mv += ROUND_UP (count, 16);
- *v = xrealloc (*v, mv * sizeof **v);
- }
-
- for (i = v1->index; i <= v2->index; i++)
- {
- struct variable *add = dict->var[i];
-
- /* Skip over other dictionaries. */
- if (scratch != id_dict (add->name[0]))
- continue;
-
- if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC)
- {
- delayed_fail = 1;
- msg (SW, _("%s is not a numeric variable. It will not be "
- "included in the variable list."), add->name);
- }
- else if ((pv_opts & PV_STRING) && add->type != ALPHA)
- {
- delayed_fail = 1;
- msg (SE, _("%s is not a string variable. It will not be "
- "included in the variable list."), add->name);
- }
- else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type)
- {
- delayed_fail = 1;
- msg (SE, _("%s and %s are not the same type. All variables in "
- "this variable list must be of the same type. %s "
- "will be omitted from list."),
- (*v)[0]->name, add->name, add->name);
- }
- else if ((pv_opts & PV_NO_DUPLICATE) && TEST_BIT (bits, add->index))
- {
- delayed_fail = 1;
- msg (SE, _("Variable %s appears twice in variable list."),
- add->name);
- }
- else if ((pv_opts & PV_DUPLICATE) || !TEST_BIT (bits, add->index))
- {
- (*v)[(*nv)++] = dict->var[i];
- if (!(pv_opts & PV_DUPLICATE))
- SET_BIT (bits, add->index);
- }
- }
-
- if (pv_opts & PV_SINGLE)
- {
- if (delayed_fail)
- goto fail;
- else
- return 1;
- }
- lex_match (',');
+ do
+ {
+ enum dict_class class;
+ int first_idx;
+
+ if (!parse_var_idx_class (vs, &first_idx, &class))
+ goto fail;
+
+ if (!lex_match (T_TO))
+ add_variable (v, nv, &mv, included, pv_opts,
+ vs, first_idx);
+ else
+ {
+ int last_idx;
+ enum dict_class last_class;
+ struct variable *first_var, *last_var;
+
+ if (!parse_var_idx_class (vs, &last_idx, &last_class))
+ goto fail;
+
+ first_var = var_set_get_var (vs, first_idx);
+ last_var = var_set_get_var (vs, last_idx);
+
+ if (last_idx < first_idx)
+ {
+ msg (SE, _("%s TO %s is not valid syntax since %s "
+ "precedes %s in the dictionary."),
+ first_var->name, last_var->name,
+ first_var->name, last_var->name);
+ goto fail;
+ }
+
+ if (class != last_class)
+ {
+ msg (SE, _("When using the TO keyword to specify several "
+ "variables, both variables must be from "
+ "the same variable dictionaries, of either "
+ "ordinary, scratch, or system variables. "
+ "%s is a %s variable, whereas %s is %s."),
+ first_var->name, dict_class_to_name (class),
+ last_var->name, dict_class_to_name (last_class));
+ goto fail;
+ }
+
+ add_variables (v, nv, &mv, included, pv_opts,
+ vs, first_idx, last_idx, class);
+ }
+ if (pv_opts & PV_SINGLE)
+ break;
+ lex_match (',');
+ }
+ while (token == T_ID && var_set_lookup_var (vs, tokid) != NULL);
}
- while ((token == T_ID && is_dict_varname (dict, tokid)) || token == T_ALL);
-
- if (!(pv_opts & PV_DUPLICATE))
- local_free (bits);
- if (!nv)
+
+ if (*nv == 0)
goto fail;
+
+ free (included);
return 1;
fail:
+ free (included);
free (*v);
*v = NULL;
*nv = 0;
- if (!(pv_opts & PV_DUPLICATE))
- local_free (bits);
return 0;
}
+/* Extracts a numeric suffix from variable name S, copying it
+ into string R. Sets *D to the length of R and *N to its
+ value. */
static int
extract_num (char *s, char *r, int *n, int *d)
{
int d1, d2;
int n;
int nvar, mvar;
- char *name1, *name2;
- char *root1, *root2;
+ char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
+ char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
int success = 0;
+ assert (names != NULL);
+ assert (nnames != NULL);
+ assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
+ | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
+ /* FIXME: PV_NO_DUPLICATE is not implemented. */
+
if (pv_opts & PV_APPEND)
nvar = mvar = *nnames;
else
*names = NULL;
}
- name1 = xmalloc (36);
- name2 = &name1[1 * 9];
- root1 = &name1[2 * 9];
- root2 = &name1[3 * 9];
do
{
if (token != T_ID)
lex_error ("expecting variable name");
goto fail;
}
- if (tokid[0] == '#' && (pv_opts & PV_NO_SCRATCH))
+ if (dict_class_from_id (tokid) == DC_SCRATCH
+ && (pv_opts & PV_NO_SCRATCH))
{
msg (SE, _("Scratch variables not allowed here."));
goto fail;
|| !extract_num (name2, root2, &n2, &d2))
goto fail;
- if (strcmp (root1, root2))
+ if (strcasecmp (root1, root2))
{
msg (SE, _("Prefixes don't match in use of TO convention."));
goto fail;
for (n = n1; n <= n2; n++)
{
- (*names)[nvar] = xmalloc (9);
- sprintf ((*names)[nvar], "%s%0*d", root1, d1, n);
+ char name[LONG_NAME_LEN + 1];
+ sprintf (name, "%s%0*d", root1, d1, n);
+ (*names)[nvar] = xstrdup (name);
nvar++;
}
}
fail:
*nnames = nvar;
- free (name1);
if (!success)
{
int i;
/* Parses a list of variables where some of the variables may be
existing and the rest are to be created. Same args as
- parse_variables(). */
+ parse_DATA_LIST_vars(). */
int
parse_mixed_vars (char ***names, int *nnames, int pv_opts)
{
int i;
+ assert (names != NULL);
+ assert (nnames != NULL);
+ assert ((pv_opts & ~PV_APPEND) == 0);
+
if (!(pv_opts & PV_APPEND))
{
*names = NULL;
}
while (token == T_ID || token == T_ALL)
{
- if (token == T_ALL || is_varname (tokid))
+ if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
{
struct variable **v;
int nv;
- if (!parse_variables (NULL, &v, &nv, PV_NONE))
+ if (!parse_variables (default_dict, &v, &nv, PV_NONE))
goto fail;
*names = xrealloc (*names, (*nnames + nv) * sizeof **names);
for (i = 0; i < nv; i++)
*nnames = 0;
return 0;
}
+\f
+/* A set of variables. */
+struct var_set
+ {
+ size_t (*get_cnt) (const struct var_set *);
+ struct variable *(*get_var) (const struct var_set *, size_t idx);
+ int (*lookup_var_idx) (const struct var_set *, const char *);
+ void (*destroy) (struct var_set *);
+ void *aux;
+ };
+
+/* Returns the number of variables in VS. */
+size_t
+var_set_get_cnt (const struct var_set *vs)
+{
+ assert (vs != NULL);
+
+ return vs->get_cnt (vs);
+}
+
+/* Return variable with index IDX in VS.
+ IDX must be less than the number of variables in VS. */
+struct variable *
+var_set_get_var (const struct var_set *vs, size_t idx)
+{
+ assert (vs != NULL);
+ assert (idx < var_set_get_cnt (vs));
+
+ return vs->get_var (vs, idx);
+}
+
+/* Returns the variable in VS named NAME, or a null pointer if VS
+ contains no variable with that name. */
+struct variable *
+var_set_lookup_var (const struct var_set *vs, const char *name)
+{
+ int idx = var_set_lookup_var_idx (vs, name);
+ return idx >= 0 ? var_set_get_var (vs, idx) : NULL;
+}
+
+/* Returns the index in VS of the variable named NAME, or -1 if
+ VS contains no variable with that name. */
+int
+var_set_lookup_var_idx (const struct var_set *vs, const char *name)
+{
+ assert (vs != NULL);
+ assert (name != NULL);
+ assert (strlen (name) <= LONG_NAME_LEN );
+
+ return vs->lookup_var_idx (vs, name);
+}
+
+/* Destroys VS. */
+void
+var_set_destroy (struct var_set *vs)
+{
+ if (vs != NULL)
+ vs->destroy (vs);
+}
+\f
+/* Returns the number of variables in VS. */
+static size_t
+dict_var_set_get_cnt (const struct var_set *vs)
+{
+ struct dictionary *d = vs->aux;
+
+ return dict_get_var_cnt (d);
+}
+
+/* Return variable with index IDX in VS.
+ IDX must be less than the number of variables in VS. */
+static struct variable *
+dict_var_set_get_var (const struct var_set *vs, size_t idx)
+{
+ struct dictionary *d = vs->aux;
+
+ return dict_get_var (d, idx);
+}
+
+/* Returns the index of the variable in VS named NAME, or -1 if
+ VS contains no variable with that name. */
+static int
+dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name)
+{
+ struct dictionary *d = vs->aux;
+ struct variable *v = dict_lookup_var (d, name);
+ return v != NULL ? v->index : -1;
+}
+
+/* Destroys VS. */
+static void
+dict_var_set_destroy (struct var_set *vs)
+{
+ free (vs);
+}
+
+/* Returns a variable set based on D. */
+struct var_set *
+var_set_create_from_dict (const struct dictionary *d)
+{
+ struct var_set *vs = xmalloc (sizeof *vs);
+ vs->get_cnt = dict_var_set_get_cnt;
+ vs->get_var = dict_var_set_get_var;
+ vs->lookup_var_idx = dict_var_set_lookup_var_idx;
+ vs->destroy = dict_var_set_destroy;
+ vs->aux = (void *) d;
+ return vs;
+}
+\f
+/* A variable set based on an array. */
+struct array_var_set
+ {
+ struct variable *const *var;/* Array of variables. */
+ size_t var_cnt; /* Number of elements in var. */
+ struct hsh_table *name_tab; /* Hash from variable names to variables. */
+ };
+
+/* Returns the number of variables in VS. */
+static size_t
+array_var_set_get_cnt (const struct var_set *vs)
+{
+ struct array_var_set *avs = vs->aux;
+
+ return avs->var_cnt;
+}
+
+/* Return variable with index IDX in VS.
+ IDX must be less than the number of variables in VS. */
+static struct variable *
+array_var_set_get_var (const struct var_set *vs, size_t idx)
+{
+ struct array_var_set *avs = vs->aux;
+
+ return (struct variable *) avs->var[idx];
+}
+
+/* Returns the index of the variable in VS named NAME, or -1 if
+ VS contains no variable with that name. */
+static int
+array_var_set_lookup_var_idx (const struct var_set *vs, const char *name)
+{
+ struct array_var_set *avs = vs->aux;
+ struct variable v, *vp, *const *vpp;
+
+ strcpy (v.name, name);
+ vp = &v;
+ vpp = hsh_find (avs->name_tab, &vp);
+ return vpp != NULL ? vpp - avs->var : -1;
+}
+
+/* Destroys VS. */
+static void
+array_var_set_destroy (struct var_set *vs)
+{
+ struct array_var_set *avs = vs->aux;
+
+ hsh_destroy (avs->name_tab);
+ free (avs);
+ free (vs);
+}
+
+/* Returns a variable set based on the VAR_CNT variables in
+ VAR. */
+struct var_set *
+var_set_create_from_array (struct variable *const *var, size_t var_cnt)
+{
+ struct var_set *vs;
+ struct array_var_set *avs;
+ size_t i;
+
+ vs = xmalloc (sizeof *vs);
+ vs->get_cnt = array_var_set_get_cnt;
+ vs->get_var = array_var_set_get_var;
+ vs->lookup_var_idx = array_var_set_lookup_var_idx;
+ vs->destroy = array_var_set_destroy;
+ vs->aux = avs = xmalloc (sizeof *avs);
+ avs->var = var;
+ avs->var_cnt = var_cnt;
+ avs->name_tab = hsh_create (2 * var_cnt,
+ compare_var_ptr_names, hash_var_ptr_name, NULL,
+ NULL);
+ for (i = 0; i < var_cnt; i++)
+ if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL)
+ {
+ var_set_destroy (vs);
+ return NULL;
+ }
+
+ return vs;
+}