? opaque-var-2.patch
? opaque-var.patch
Index: doc/variables.texi
===================================================================
RCS file: /cvsroot/pspp/pspp/doc/variables.texi,v
retrieving revision 1.5
diff -u -p -r1.5 variables.texi
--- doc/variables.texi	5 Nov 2006 05:20:53 -0000	1.5
+++ doc/variables.texi	10 Dec 2006 03:30:12 -0000
@@ -446,7 +446,8 @@ to be created as numeric variables with 
 Variable names including numeric suffixes may not exceed 64 characters
 in length, and none of the variables may exist prior to @cmd{VECTOR}.
 
-All the variables in a vector must be the same type.
+All the variables in a vector must be the same type.  String variables
+in a vector must all have the same width.
 
 Vectors created with @cmd{VECTOR} disappear after any procedure or
 procedure-like command is executed.  The variables contained in the
Index: src/data/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/ChangeLog,v
retrieving revision 1.82
diff -u -p -r1.82 ChangeLog
--- src/data/ChangeLog	10 Dec 2006 02:33:43 -0000	1.82
+++ src/data/ChangeLog	10 Dec 2006 03:30:13 -0000
@@ -1,3 +1,165 @@
+Sat Dec  9 18:05:59 2006  Ben Pfaff  <blp@gnu.org>
+
+	* data-out.c (output_scientific): Fix bad assumption that "buf" is
+	null-terminated.
+	
+Sat Dec  9 17:23:23 2006  Ben Pfaff  <blp@gnu.org>
+
+	Finish converting struct variable to an opaque type.  In this
+	phase, we add remaining setter and getter functions, convert the
+	remaining PSPP code to use them, and do a bunch of cleanup.  The
+	resulting changes are pervasive but mostly trivial, and only the
+	notable changes are logged.
+	
+	* automake.mk (src_data_libdata_a_SOURCES): Add the new source
+	files.
+	
+	* case.c (case_data): Renamed case_data_idx.
+	(case_num): Renamed case_num_idx.
+	(case_str): Renamed case_str_idx.
+	(case_data_rw): Renamed case_data_rw_idx.
+
+	* case.h (case_data): New function with old name and an interface
+	that takes a variable instead of an index, which is easier to
+	use.  Updated all callers to use the new interface, or to use the
+	new *_idx function (see above).
+	(case_num): Ditto.
+	(case_str): Ditto.
+	(case_data_rw): Ditto.
+	
+	* category.c (cat_stored_values_destroy): Changed interface to
+	take a struct cat_vals * instead of a struct variable *.
+
+	* dictionary.c (dict_clone): Use new vector_clone function.	
+	(dict_clear) Use new var_destroy function.
+	(add_var) New function.
+	(dict_create_var) Rewrite in terms of dict_create_var_assert.
+	(dict_create_var_assert) Rewrite in terms of add_var.
+	(dict_clone_var) Rewrite in terms of dict_clone_var_assert.
+	(dict_clone_var_assert) Rewrite in terms of var_clone, add_var.
+	(dict_lookup_var) Use new var_create, var_destroy functions.
+	(dict_contains_var) Rewrite in terms of new vardict functionality.
+	(set_var_dict_index) New function.
+	(set_var_case_index) New function.
+	(reindex_vars) New function.
+	(dict_delete_var) Rewrite in terms of new vardict functionality.
+	(dict_reorder_var) Ditto.
+	(dict_reorder_vars) Ditto.
+	(rename_var) New function.
+	(dict_rename_var) Use rename_var.
+	(dict_rename_vars) Use pool to simplify code.  Use rename_var.
+	(dict_get_compacted_idx_to_fv) Rename
+	dict_get_compacted_dict_index_to_case_index, update callers.
+	(dict_create_vector) Use new vector_create function.
+	(dict_clear_vectors) Use new vector_destroy function.
+	(set_var_short_name_suffix) Move here from variable.c, renamed
+	from var_set_short_name_suffix, make static, update caller.
+
+	* sys-file-private.c: New file.  
+	(sfm_width_to_bytes) Moved here from variable.c, renamed from
+	width_to_bytes, update callers.
+
+	* sys-file-private.h: New file.  Later it will supplant
+	sfm-private.h; for now it supplements it.
+	(macro MIN_VERY_LONG_STRING) New macro.
+	(macro EFFECTIVE_LONG_STRING_LENGTH) New macro, from value.h.
+
+	* sys-file-reader.c: Use MIN_VERY_LONG_STRING - 1 where
+	MAX_LONG_STRING was used before.
+
+	* sys-file-writer.c: Ditto.
+
+	* value-labels.c: Change the paradigm here to be that a null
+	pointer is OK for a struct val_labs * in most cases; it just
+	represents an empty set of value labels.
+	(val_labs_copy) A copy of a null set is a null set.
+	(val_labs_count) A null set has 0 labels.
+	(val_labs_replace) Change return type to void.  Rewrite for
+	simplicity.
+	(val_labs_find) A null set does not contain the value.
+	(value_to_string) Moved to variable.c, renamed var_get_value_name,
+	transposed argument order, updated all callers.
+
+	* value.c: New file.
+	(value_dup) Moved here from variable.c.
+	(compare_values) Ditto.
+	(hash_value) Ditto.
+
+	* value.h: (macro MAX_SHORT_STRING) Rewrote for simplicity.
+	(macro MAX_LONG_STRING) Removed, because it was only interesting
+	for system files, not for general code.
+	(macro MAX_VERY_LONG_STRING) Ditto.
+	(macro EFFECTIVE_LONG_STRING_LENGTH) Moved to sys-file-private.h.
+	(macro MAX_ELEMS_PER_VALUE) Removed, as it was unused.
+
+	* vardict.h: New file, for an interface between variables and
+	their dictionaries.
+
+	* variable.c: A lot of functions were moved around, for better
+	organization.
+	(struct variable) Move definition here, from variable.h.
+	(var_type_adj) Removed--makes i18n hard.
+	(var_type_noun) Ditto.
+	(var_create) New function.
+	(var_clone) New function.
+	(var_destroy) New function.
+	(var_set_name) Assert that variable is not in a dictionary.
+	(compare_var_names) Rename compare_vars_by_name and fix a couple
+	of callers who thought the args were strings.
+	(hash_var_name) Rename hash_var_by_name.
+	(compare_var_ptr_names) Rename compare_var_ptrs_by_name.
+	(hash_var_ptr_name) Rename hash_var_ptr_by_name.
+	(var_is_very_long_string) Removed, because it was only interesting
+	to system file code.
+	(var_set_missing_values) Allow the argument to be the wrong width,
+	as long as we can resize it.  Simplify callers who were doing the
+	resizing themselves.
+	(var_get_value_labels) New function.
+	(var_has_value_labels) New function.
+	(var_set_value_labels) New function.
+	(alloc_value_labels) New function.
+	(var_add_value_label) New function.
+	(var_replace_value_label) New function.
+	(var_clear_value_labels) New function.
+	(var_lookup_value_label) New function.
+	(var_get_value_name) Moved here from variable.c, renamed from
+	var_get_value_name, transposed argument order, updated all
+	callers.
+	(var_to_string) Moved here, from variable-label.c.
+	(var_set_leave) New function.
+	(var_get_leave) New function.
+	(var_must_leave) New function.
+	(var_set_short_name_suffix) Moved to dictionary.c, renamed
+	set_var_short_name_suffix.
+	(var_get_dict_index) New function.
+	(var_get_case_index) New function.
+	(var_get_obs_vals) New function.
+	(var_set_obs_vals) New function.
+	(var_has_obs_vals) New function.
+	(var_get_vardict) New function.
+	(var_set_vardict) New function.
+	(var_has_vardict) New function.
+	(var_clear_vardict) New function.
+	(value_dup) Moved to value.c.
+	(compare_values) Ditto.
+	(hash_value) Ditto.
+
+	* variable.h: (enum NUMERIC) Rename VAR_NUMERIC, update all users.
+	(enum ALPHA) Rename VAR_STRING, update all users.
+
+	* vector.c: New file.
+	(struct vector) Moved here, from variable.h.
+	(check_widths) New function.
+	(vector_create) New function.
+	(vector_clone) New function.
+	(vector_destroy) New function.
+	(vector_get_name) New function.
+	(vector_get_var) New function.
+	(vector_get_var_cnt) New function.
+	(compare_vector_ptrs_by_name) New function.
+
+	* vector.h: New file.
+
 Sun Dec 10 11:32:56 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
 	* casefilter.c (casefilter_variable_missing): Avoided comparision of
@@ -23,10 +185,11 @@ Thu Dec  7 15:22:38 WST 2006 John Darrin
 
 Mon Dec  4 22:20:17 2006  Ben Pfaff  <blp@gnu.org>
 
-	Start converting struct variable to an opaque.  In this phase, we
-	add a bunch of setter and getter functions and convert most of the
-	PSPP code to use them.  The resulting changes are pervasive but
-	mostly trivial, and only the notable changes are logged.
+	Start converting struct variable to an opaque type.  In this
+	phase, we add a bunch of setter and getter functions and convert
+	most of the PSPP code to use them.  The resulting changes are
+	pervasive but mostly trivial, and only the notable changes are
+	logged.
 	
 	* format.c (fmt_equal): New function.
 	
Index: src/data/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/automake.mk,v
retrieving revision 1.9
diff -u -p -r1.9 automake.mk
--- src/data/automake.mk	29 Nov 2006 02:15:01 -0000	1.9
+++ src/data/automake.mk	10 Dec 2006 03:30:13 -0000
@@ -60,14 +60,19 @@ src_data_libdata_a_SOURCES = \
 	src/data/sfm-private.h \
 	src/data/storage-stream.c \
 	src/data/storage-stream.h \
+	src/data/sys-file-private.c \
+	src/data/sys-file-private.h \
 	src/data/sys-file-reader.c \
 	src/data/sys-file-reader.h \
 	src/data/sys-file-writer.c \
 	src/data/sys-file-writer.h \
 	src/data/transformations.c \
 	src/data/transformations.h \
+	src/data/value.c \
 	src/data/value.h \
 	src/data/value-labels.c \
 	src/data/value-labels.h \
 	src/data/variable.h \
-	src/data/variable.c 
+	src/data/variable.c \
+	src/data/vector.c \
+	src/data/vector.h
Index: src/data/case.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/case.c,v
retrieving revision 1.7
diff -u -p -r1.7 case.c
--- src/data/case.c	5 Dec 2006 15:10:21 -0000	1.7
+++ src/data/case.c	10 Dec 2006 03:30:13 -0000
@@ -255,7 +255,7 @@ case_from_values (struct ccase *c, const
    element of C numbered IDX.
    The caller must not modify the returned data. */
 const union value *
-case_data (const struct ccase *c, size_t idx) 
+case_data_idx (const struct ccase *c, size_t idx) 
 {
   assert (c != NULL);
   assert (c->case_data != NULL);
@@ -270,7 +270,7 @@ case_data (const struct ccase *c, size_t
 /* Returns the numeric value of the `union value' in C numbered
    IDX. */
 double
-case_num (const struct ccase *c, size_t idx) 
+case_num_idx (const struct ccase *c, size_t idx) 
 {
   assert (c != NULL);
   assert (c->case_data != NULL);
@@ -287,7 +287,7 @@ case_num (const struct ccase *c, size_t 
    (Note that the value is not null-terminated.)
    The caller must not modify the return value. */
 const char *
-case_str (const struct ccase *c, size_t idx) 
+case_str_idx (const struct ccase *c, size_t idx) 
 {
   assert (c != NULL);
   assert (c->case_data != NULL);
@@ -303,7 +303,7 @@ case_str (const struct ccase *c, size_t 
    element of C numbered IDX.
    The caller is allowed to modify the returned data. */
 union value *
-case_data_rw (struct ccase *c, size_t idx) 
+case_data_rw_idx (struct ccase *c, size_t idx) 
 {
   assert (c != NULL);
   assert (c->case_data != NULL);
@@ -342,16 +342,16 @@ case_compare_2dict (const struct ccase *
       
       if (var_get_width (va) == 0) 
         {
-          double af = case_num (ca, va->fv);
-          double bf = case_num (cb, vb->fv);
+          double af = case_num (ca, va);
+          double bf = case_num (cb, vb);
 
           if (af != bf) 
             return af > bf ? 1 : -1;
         }
       else 
         {
-          const char *as = case_str (ca, va->fv);
-          const char *bs = case_str (cb, vb->fv);
+          const char *as = case_str (ca, va);
+          const char *bs = case_str (cb, vb);
           int cmp = memcmp (as, bs, var_get_width (va));
 
           if (cmp != 0)
Index: src/data/case.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/case.h,v
retrieving revision 1.6
diff -u -p -r1.6 case.h
--- src/data/case.h	14 Oct 2006 00:25:20 -0000	1.6
+++ src/data/case.h	10 Dec 2006 03:30:13 -0000
@@ -23,6 +23,7 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include "value.h"
+#include "variable.h"
 
 /* Opaque structure that represents a case.  Use accessor
    functions instead of accessing any members directly.  Use
@@ -68,11 +69,19 @@ CASE_INLINE void case_to_values (const s
 CASE_INLINE void case_from_values (struct ccase *,
                                    const union value *, size_t);
 
-CASE_INLINE const union value *case_data (const struct ccase *, size_t idx);
-CASE_INLINE double case_num (const struct ccase *, size_t idx);
-CASE_INLINE const char *case_str (const struct ccase *, size_t idx);
-
-CASE_INLINE union value *case_data_rw (struct ccase *, size_t idx);
+static inline const union value *case_data (const struct ccase *,
+                                            const struct variable *);
+static inline double case_num (const struct ccase *, const struct variable *);
+static inline const char *case_str (const struct ccase *,
+                                    const struct variable *);
+static inline union value *case_data_rw (struct ccase *,
+                                         const struct variable *);
+
+CASE_INLINE const union value *case_data_idx (const struct ccase *,
+                                              size_t idx);
+CASE_INLINE double case_num_idx (const struct ccase *, size_t idx);
+CASE_INLINE const char *case_str_idx (const struct ccase *, size_t idx);
+CASE_INLINE union value *case_data_rw_idx (struct ccase *, size_t idx);
 
 struct variable;
 int case_compare (const struct ccase *, const struct ccase *,
@@ -161,25 +170,25 @@ case_from_values (struct ccase *c, const
 }
 
 static inline const union value *
-case_data (const struct ccase *c, size_t idx) 
+case_data_idx (const struct ccase *c, size_t idx) 
 {
   return &c->case_data->values[idx];
 }
 
 static inline double
-case_num (const struct ccase *c, size_t idx) 
+case_num_idx (const struct ccase *c, size_t idx) 
 {
   return c->case_data->values[idx].f;
 }
 
 static inline const char *
-case_str (const struct ccase *c, size_t idx)
+case_str_idx (const struct ccase *c, size_t idx)
 {
   return c->case_data->values[idx].s;
 }
 
 static inline union value *
-case_data_rw (struct ccase *c, size_t idx)
+case_data_rw_idx (struct ccase *c, size_t idx)
 {
   if (c->case_data->ref_cnt > 1)
     case_unshare (c);
@@ -187,4 +196,44 @@ case_data_rw (struct ccase *c, size_t id
 }
 #endif /* !DEBUGGING */
 
+/* Returns a pointer to the `union value' used for the
+   element of C for variable V.
+   Case C must be drawn from V's dictionary.
+   The caller must not modify the returned data. */
+static inline const union value *
+case_data (const struct ccase *c, const struct variable *v)
+{
+  return case_data_idx (c, var_get_case_index (v));
+}
+
+/* Returns the numeric value of the `union value' in C for
+   variable V.
+   Case C must be drawn from V's dictionary. */
+static inline double
+case_num (const struct ccase *c, const struct variable *v) 
+{
+  return case_num_idx (c, var_get_case_index (v));
+}
+
+/* Returns the string value of the `union value' in C for
+   variable V.
+   Case C must be drawn from V's dictionary.
+   (Note that the value is not null-terminated.)
+   The caller must not modify the return value. */
+static inline const char *
+case_str (const struct ccase *c, const struct variable *v) 
+{
+  return case_str_idx (c, var_get_case_index (v));
+}
+
+/* Returns a pointer to the `union value' used for the
+   element of C for variable V.
+   Case C must be drawn from V's dictionary.   
+   The caller is allowed to modify the returned data. */
+static inline union value *
+case_data_rw (struct ccase *c, const struct variable *v) 
+{
+  return case_data_rw_idx (c, var_get_case_index (v));
+}
+
 #endif /* case.h */
Index: src/data/casefilter.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/casefilter.c,v
retrieving revision 1.3
diff -u -p -r1.3 casefilter.c
--- src/data/casefilter.c	10 Dec 2006 02:33:43 -0000	1.3
+++ src/data/casefilter.c	10 Dec 2006 03:30:13 -0000
@@ -58,9 +58,9 @@ casefilter_variable_missing (const struc
 			     const struct ccase *c,
 			     const struct variable *var)
 {
-  const union value *val = case_data (c, var->fv) ;
+  const union value *val = case_data (c, var) ;
 
-  if ( var_get_type (var) != ALPHA && val->f == SYSMIS )
+  if ( var_is_numeric (var) && val->f == SYSMIS )
     return true;
 
   if ( filter->exclude_user_missing &&
Index: src/data/cat-routines.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/cat-routines.h,v
retrieving revision 1.1
diff -u -p -r1.1 cat-routines.h
--- src/data/cat-routines.h	4 Mar 2006 01:11:57 -0000	1.1
+++ src/data/cat-routines.h	10 Dec 2006 03:30:13 -0000
@@ -49,5 +49,5 @@ void cat_value_update (struct variable *
 
 void cat_create_value_matrix (struct variable *);
 
-void cat_stored_values_destroy (struct variable *);
+void cat_stored_values_destroy (struct cat_vals *);
 #endif
Index: src/data/category.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/category.c,v
retrieving revision 1.5
diff -u -p -r1.5 category.c
--- src/data/category.c	5 Dec 2006 15:10:21 -0000	1.5
+++ src/data/category.c	10 Dec 2006 03:30:13 -0000
@@ -42,6 +42,7 @@
 #include <libpspp/alloc.h>
 #include <libpspp/message.h>
 #include "cat-routines.h"
+#include "value.h"
 #include "variable.h"
 
 #define N_INITIAL_CATEGORIES 1
@@ -49,30 +50,24 @@
 void
 cat_stored_values_create (struct variable *v)
 {
-  if (v->obs_vals == NULL)
+  if (!var_has_obs_vals (v))
     {
-      v->obs_vals = xmalloc (sizeof (*v->obs_vals));
-      v->obs_vals->n_categories = 0;
-      v->obs_vals->n_allocated_categories = N_INITIAL_CATEGORIES;
-      v->obs_vals->vals =
-	xnmalloc (N_INITIAL_CATEGORIES, sizeof *v->obs_vals->vals);
+      struct cat_vals *obs_vals = xmalloc (sizeof *obs_vals);
+      obs_vals->n_categories = 0;
+      obs_vals->n_allocated_categories = N_INITIAL_CATEGORIES;
+      obs_vals->vals = xnmalloc (N_INITIAL_CATEGORIES, sizeof *obs_vals->vals);
+      var_set_obs_vals (v, obs_vals);
     }
 }
 
 void
-cat_stored_values_destroy (struct variable *v)
+cat_stored_values_destroy (struct cat_vals *obs_vals)
 {
-  assert (v != NULL);
-
-  if (v->obs_vals != NULL)
+  if (obs_vals != NULL) 
     {
-      if (v->obs_vals->n_allocated_categories > 0)
-	{
-	  free (v->obs_vals->vals);
-	  v->obs_vals->vals = NULL;
-	}
-      free (v->obs_vals);
-      v->obs_vals = NULL;
+      if (obs_vals->n_allocated_categories > 0)
+        free (obs_vals->vals);
+      free (obs_vals);
     }
 }
 
@@ -82,15 +77,13 @@ cat_stored_values_destroy (struct variab
 size_t
 cat_value_find (const struct variable *v, const union value *val)
 {
+  struct cat_vals *obs_vals = var_get_obs_vals (v);
   size_t i;
   const union value *candidate;
 
-  assert (val != NULL);
-  assert (v != NULL);
-  assert (v->obs_vals != NULL);
-  for (i = 0; i < v->obs_vals->n_categories; i++)
+  for (i = 0; i < obs_vals->n_categories; i++)
     {
-      candidate = v->obs_vals->vals + i;
+      candidate = obs_vals->vals + i;
       assert (candidate != NULL);
       if (!compare_values (candidate, val, var_get_width (v)))
 	{
@@ -106,13 +99,9 @@ cat_value_find (const struct variable *v
 void
 cat_value_update (struct variable *v, const union value *val)
 {
-  struct cat_vals *cv;
-
   if (var_is_alpha (v))
     {
-      assert (val != NULL);
-      assert (v != NULL);
-      cv = v->obs_vals;
+      struct cat_vals *cv = var_get_obs_vals (v);
       if (cat_value_find (v, val) == CAT_VALUE_NOT_FOUND)
 	{
 	  if (cv->n_categories >= cv->n_allocated_categories)
@@ -131,15 +120,8 @@ cat_value_update (struct variable *v, co
 union value *
 cat_subscript_to_value (const size_t s, struct variable *v)
 {
-  assert (v->obs_vals != NULL);
-  if (s < v->obs_vals->n_categories)
-    {
-      return (v->obs_vals->vals + s);
-    }
-  else
-    {
-      return NULL;
-    }
+  struct cat_vals *obs_vals = var_get_obs_vals (v);
+  return s < obs_vals->n_categories ? obs_vals->vals + s : NULL;
 }
 
 /*
@@ -148,6 +130,6 @@ cat_subscript_to_value (const size_t s, 
 size_t 
 cat_get_n_categories (const struct variable *v)
 {
-  return v->obs_vals->n_categories;
+  return var_get_obs_vals (v)->n_categories;
 }
 
Index: src/data/data-in.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/data-in.c,v
retrieving revision 1.17
diff -u -p -r1.17 data-in.c
--- src/data/data-in.c	22 Nov 2006 04:24:02 -0000	1.17
+++ src/data/data-in.c	10 Dec 2006 03:30:14 -0000
@@ -34,7 +34,7 @@
 #include "calendar.h"
 #include "identifier.h"
 #include "settings.h"
-#include "variable.h"
+#include "value.h"
 
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
Index: src/data/data-out.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/data-out.c,v
retrieving revision 1.13
diff -u -p -r1.13 data-out.c
--- src/data/data-out.c	8 Dec 2006 01:41:21 -0000	1.13
+++ src/data/data-out.c	10 Dec 2006 03:30:15 -0000
@@ -32,7 +32,7 @@
 #include "calendar.h"
 #include "format.h"
 #include "settings.h"
-#include "variable.h"
+#include "value.h"
 
 #include <libpspp/assertion.h>
 #include <libpspp/float-format.h>
@@ -709,8 +709,8 @@ output_scientific (double number, const 
     p = mempset (p, ' ', ss_length (style->neg_suffix));
 
   assert (p == buf + format->w);
+  memcpy (output, buf, format->w);
 
-  buf_copy_str_lpad (output, format->w, buf);
   return true;
 }
 
Index: src/data/dictionary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/dictionary.c,v
retrieving revision 1.20
diff -u -p -r1.20 dictionary.c
--- src/data/dictionary.c	5 Dec 2006 15:10:21 -0000	1.20
+++ src/data/dictionary.c	10 Dec 2006 03:30:16 -0000
@@ -29,13 +29,16 @@
 #include "category.h"
 #include "settings.h"
 #include "value-labels.h"
+#include "vardict.h"
 #include "variable.h"
+#include "vector.h"
 #include <libpspp/alloc.h>
 #include <libpspp/array.h>
 #include <libpspp/compiler.h>
 #include <libpspp/hash.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
+#include <libpspp/pool.h>
 #include <libpspp/str.h>
 
 #include "minmax.h"
@@ -69,7 +72,8 @@ dict_create (void) 
   
   d->var = NULL;
   d->var_cnt = d->var_cap = 0;
-  d->name_tab = hsh_create (8, compare_var_names, hash_var_name, NULL, NULL);
+  d->name_tab = hsh_create (8, compare_vars_by_name, hash_var_by_name,
+                            NULL, NULL);
   d->next_value_idx = 0;
   d->split = NULL;
   d->split_cnt = 0;
@@ -125,19 +129,8 @@ dict_clone (const struct dictionary *s) 
 
   d->vector_cnt = s->vector_cnt;
   d->vector = xnmalloc (d->vector_cnt, sizeof *d->vector);
-  for (i = 0; i < s->vector_cnt; i++) 
-    {
-      struct vector *sv = s->vector[i];
-      struct vector *dv = d->vector[i] = xmalloc (sizeof *dv);
-      int j;
-      
-      dv->idx = i;
-      strcpy (dv->name, sv->name);
-      dv->cnt = sv->cnt;
-      dv->var = xnmalloc (dv->cnt, sizeof *dv->var);
-      for (j = 0; j < dv->cnt; j++)
-        dv->var[j] = d->var[sv->var[j]->index];
-    }
+  for (i = 0; i < s->vector_cnt; i++)
+    d->vector[i] = vector_clone (s->vector[i], s, d);
 
   return d;
 }
@@ -153,14 +146,10 @@ dict_clear (struct dictionary *d) 
 
   assert (d != NULL);
 
-  for (i = 0; i < d->var_cnt; i++) 
+  for (i = 0; i < d->var_cnt; i++)
     {
-      struct variable *v = d->var[i];
-      var_clear_aux (v);
-      val_labs_destroy (v->val_labs);
-      var_clear_label (v);
-      free (v->label);
-      free (v); 
+      var_clear_vardict (d->var[i]);
+      var_destroy (d->var[i]); 
     }
   free (d->var);
   d->var = NULL;
@@ -214,9 +203,9 @@ dict_get_var_cnt (const struct dictionar
   return d->var_cnt;
 }
 
-/* Returns the variable in D with index IDX, which must be
-   between 0 and the count returned by dict_get_var_cnt(),
-   exclusive. */
+/* Returns the variable in D with dictionary index IDX, which
+   must be between 0 and the count returned by
+   dict_get_var_cnt(), exclusive. */
 struct variable *
 dict_get_var (const struct dictionary *d, size_t idx) 
 {
@@ -264,55 +253,14 @@ dict_get_vars (const struct dictionary *
   assert (*cnt == count);
 }
 
-
-/* Creates and returns a new variable in D with the given NAME
-   and WIDTH.  Returns a null pointer if the given NAME would
-   duplicate that of an existing variable in the dictionary. */
-struct variable *
-dict_create_var (struct dictionary *d, const char *name, int width)
+static struct variable *
+add_var (struct dictionary *d, struct variable *v) 
 {
-  struct variable *v;
-
-  assert (d != NULL);
-  assert (name != NULL);
-
-  assert (width >= 0 && width <= MAX_STRING);
-
-  assert (var_is_plausible_name(name,0));
-    
-  /* Make sure there's not already a variable by that name. */
-  if (dict_lookup_var (d, name) != NULL)
-    return NULL;
-
-  /* Allocate and initialize variable. */
-  v = xmalloc (sizeof *v);
-  var_set_name (v, name);
-  v->width = width;
-  v->fv = d->next_value_idx;
-  v->leave = dict_class_from_id (var_get_name (v)) == DC_SCRATCH;
-  v->index = d->var_cnt;
-  mv_init (&v->miss, width);
-  if (var_is_numeric (v))
-    {
-      v->print = fmt_for_output (FMT_F, 8, 2);
-      v->alignment = ALIGN_RIGHT;
-      v->display_width = 8;
-      v->measure = MEASURE_SCALE;
-    }
-  else
-    {
-      v->print = fmt_for_output (FMT_A, var_get_width (v), 0);
-      v->alignment = ALIGN_LEFT;
-      v->display_width = 8;
-      v->measure = MEASURE_NOMINAL;
-    }
-  v->write = v->print;
-  v->val_labs = val_labs_create (var_get_width (v));
-  v->label = NULL;
-  var_clear_short_name (v);
-  v->aux = NULL;
-  v->aux_dtor = NULL;
-  v->obs_vals = NULL;
+  /* Add dictionary info to variable. */
+  struct vardict_info vdi;
+  vdi.case_index = d->next_value_idx;
+  vdi.dict_index = d->var_cnt;
+  var_set_vardict (v, &vdi);
 
   /* Update dictionary. */
   if (d->var_cnt >= d->var_cap) 
@@ -320,8 +268,7 @@ dict_create_var (struct dictionary *d, c
       d->var_cap = 8 + 2 * d->var_cap; 
       d->var = xnrealloc (d->var, d->var_cap, sizeof *d->var);
     }
-  d->var[v->index] = v;
-  d->var_cnt++;
+  d->var[d->var_cnt++] = v;
   hsh_force_insert (d->name_tab, v);
 
   d->next_value_idx += var_get_value_cnt (v);
@@ -330,66 +277,52 @@ dict_create_var (struct dictionary *d, c
 }
 
 /* Creates and returns a new variable in D with the given NAME
+   and WIDTH.  Returns a null pointer if the given NAME would
+   duplicate that of an existing variable in the dictionary. */
+struct variable *
+dict_create_var (struct dictionary *d, const char *name, int width)
+{
+  return (dict_lookup_var (d, name) == NULL
+          ? dict_create_var_assert (d, name, width)
+          : NULL);
+}
+
+/* Creates and returns a new variable in D with the given NAME
    and WIDTH.  Assert-fails if the given NAME would duplicate
    that of an existing variable in the dictionary. */
 struct variable *
 dict_create_var_assert (struct dictionary *d, const char *name, int width)
 {
-  struct variable *v = dict_create_var (d, name, width);
-  assert (v != NULL);
-  return v;
+  assert (dict_lookup_var (d, name) == NULL);
+  return add_var (d, var_create (name, width));
 }
 
 /* Creates and returns a new variable in D with name NAME, as a
-   copy of existing variable OV, which need not be in D or in any
-   dictionary.  Returns a null pointer if the given NAME would
-   duplicate that of an existing variable in the dictionary. */
+   copy of existing variable OLD_VAR, which need not be in D or
+   in any dictionary.  Returns a null pointer if the given NAME
+   would duplicate that of an existing variable in the
+   dictionary. */
 struct variable *
-dict_clone_var (struct dictionary *d, const struct variable *ov,
+dict_clone_var (struct dictionary *d, const struct variable *old_var,
                 const char *name)
 {
-  struct variable *nv;
-
-  assert (d != NULL);
-  assert (ov != NULL);
-  assert (name != NULL);
-
-  assert (strlen (name) >= 1);
-  assert (strlen (name) <= LONG_NAME_LEN);
-
-  nv = dict_create_var (d, name, var_get_width (ov));
-  if (nv == NULL)
-    return NULL;
-
-  /* Copy most members not copied via dict_create_var().
-     short_name[] is intentionally not copied, because there is
-     no reason to give a new variable with potentially a new name
-     the same short name. */
-  nv->leave = var_get_leave (ov);
-  var_set_missing_values (nv, var_get_missing_values (ov));
-  var_set_print_format (nv, var_get_print_format (ov));
-  var_set_write_format (nv, var_get_write_format (ov));
-  val_labs_destroy (nv->val_labs);
-  nv->val_labs = val_labs_copy (ov->val_labs);
-  var_set_label (nv, var_get_label (ov));
-  var_set_measure (nv, var_get_measure (ov));
-  var_set_display_width (nv, var_get_display_width (ov));
-  var_set_alignment (nv, var_get_alignment (ov));
-
-  return nv;
+  return (dict_lookup_var (d, name) == NULL
+          ? dict_clone_var_assert (d, old_var, name)
+          : NULL);
 }
 
 /* Creates and returns a new variable in D with name NAME, as a
-   copy of existing variable OV, which need not be in D or in any
-   dictionary.  Assert-fails if the given NAME would duplicate
-   that of an existing variable in the dictionary. */
+   copy of existing variable OLD_VAR, which need not be in D or
+   in any dictionary.  Assert-fails if the given NAME would
+   duplicate that of an existing variable in the dictionary. */
 struct variable *
-dict_clone_var_assert (struct dictionary *d, const struct variable *ov,
+dict_clone_var_assert (struct dictionary *d, const struct variable *old_var,
                        const char *name)
 {
-  struct variable *v = dict_clone_var (d, ov, name);
-  assert (v != NULL);
-  return v;
+  struct variable *new_var = var_clone (old_var);
+  assert (dict_lookup_var (d, name) == NULL);
+  var_set_name (new_var, name);
+  return add_var (d, new_var);
 }
 
 /* Returns the variable named NAME in D, or a null pointer if no
@@ -397,13 +330,10 @@ dict_clone_var_assert (struct dictionary
 struct variable *
 dict_lookup_var (const struct dictionary *d, const char *name)
 {
-  struct variable v;
-  
-  assert (d != NULL);
-  assert (name != NULL);
-
-  str_copy_trunc (v.name, sizeof v.name, name);
-  return hsh_find (d->name_tab, &v);
+  struct variable *target = var_create (name, 0);
+  struct variable *result = hsh_find (d->name_tab, target);
+  var_destroy (target);
+  return result;
 }
 
 /* Returns the variable named NAME in D.  Assert-fails if no
@@ -421,10 +351,15 @@ dict_lookup_var_assert (const struct dic
 bool
 dict_contains_var (const struct dictionary *d, const struct variable *v)
 {
-  assert (d != NULL);
-  assert (v != NULL);
-
-  return v->index >= 0 && v->index < d->var_cnt && d->var[v->index] == v;
+  if (var_has_vardict (v)) 
+    {
+      const struct vardict_info *vdi = var_get_vardict (v);
+      return (vdi->dict_index >= 0
+              && vdi->dict_index < d->var_cnt
+              && d->var[vdi->dict_index] == v); 
+    }
+  else
+    return false;
 }
 
 /* Compares two double pointers to variables, which should point
@@ -438,6 +373,35 @@ compare_var_ptrs (const void *a_, const 
   return *a < *b ? -1 : *a > *b;
 }
 
+/* Sets the dict_index in V's vardict to DICT_INDEX. */
+static void
+set_var_dict_index (struct variable *v, int dict_index)
+{
+  struct vardict_info vdi = *var_get_vardict (v);
+  vdi.dict_index = dict_index;
+  var_set_vardict (v, &vdi); 
+}
+
+/* Sets the case_index in V's vardict to DICT_INDEX. */
+static void
+set_var_case_index (struct variable *v, int case_index)
+{
+  struct vardict_info vdi = *var_get_vardict (v);
+  vdi.case_index = case_index;
+  var_set_vardict (v, &vdi); 
+}
+
+/* Re-sets the dict_index in the dictionary variables with
+   indexes from FROM to TO (exclusive). */
+static void
+reindex_vars (struct dictionary *d, size_t from, size_t to) 
+{
+  size_t i;
+  
+  for (i = from; i < to; i++)
+    set_var_dict_index (d->var[i], i);
+}
+
 /* Deletes variable V from dictionary D and frees V.
 
    This is a very bad idea if there might be any pointers to V
@@ -453,10 +417,8 @@ compare_var_ptrs (const void *a_, const 
 void
 dict_delete_var (struct dictionary *d, struct variable *v) 
 {
-  size_t i;
+  int dict_index = var_get_dict_index (v);
 
-  assert (d != NULL);
-  assert (v != NULL);
   assert (dict_contains_var (d, v));
 
   /* Delete aux data. */
@@ -472,21 +434,18 @@ dict_delete_var (struct dictionary *d, s
   dict_clear_vectors (d);
 
   /* Remove V from var array. */
-  remove_element (d->var, d->var_cnt, sizeof *d->var, v->index);
+  remove_element (d->var, d->var_cnt, sizeof *d->var, dict_index);
   d->var_cnt--;
 
-  /* Update index. */
-  for (i = v->index; i < d->var_cnt; i++)
-    d->var[i]->index = i;
+  /* Update dict_index for each affected variable. */
+  reindex_vars (d, dict_index, d->var_cnt);
 
   /* Update name hash. */
   hsh_force_delete (d->name_tab, v);
 
   /* Free memory. */
-  val_labs_destroy (v->val_labs);
-  cat_stored_values_destroy (v);
-  free (v->label);
-  free (v);
+  var_clear_vardict (v);
+  var_destroy (v);
 }
 
 /* Deletes the COUNT variables listed in VARS from D.  This is
@@ -525,23 +484,13 @@ dict_delete_scratch_vars (struct diction
    if any, retain their relative positions.  Runs in time linear
    in the distance moved. */
 void
-dict_reorder_var (struct dictionary *d, struct variable *v,
-                  size_t new_index) 
+dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index) 
 {
-  size_t min_idx, max_idx;
-  size_t i;
-  
-  assert (d != NULL);
-  assert (v != NULL);
-  assert (dict_contains_var (d, v));
-  assert (new_index < d->var_cnt);
-
-  move_element (d->var, d->var_cnt, sizeof *d->var, v->index, new_index);
+  size_t old_index = var_get_dict_index (v);
 
-  min_idx = MIN (v->index, new_index);
-  max_idx = MAX (v->index, new_index);
-  for (i = min_idx; i <= max_idx; i++)
-    d->var[i]->index = i;
+  assert (new_index < d->var_cnt);
+  move_element (d->var, d->var_cnt, sizeof *d->var, old_index, new_index);
+  reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
 }
 
 /* Reorders the variables in D, placing the COUNT variables
@@ -563,22 +512,37 @@ dict_reorder_vars (struct dictionary *d,
   memcpy (new_var, order, count * sizeof *new_var);
   for (i = 0; i < count; i++) 
     {
-      assert (d->var[order[i]->index] != NULL);
-      d->var[order[i]->index] = NULL;
-      order[i]->index = i;
+      size_t index = var_get_dict_index (order[i]);
+      assert (d->var[index] == order[i]);
+      d->var[index] = NULL;
+      set_var_dict_index (order[i], i);
     }
   for (i = 0; i < d->var_cnt; i++)
     if (d->var[i] != NULL)
       {
         assert (count < d->var_cnt);
         new_var[count] = d->var[i];
-        new_var[count]->index = count;
+        set_var_dict_index (new_var[count], count);
         count++;
       }
   free (d->var);
   d->var = new_var;
 }
 
+/* Changes the name of variable V in dictionary D to NEW_NAME. */
+static void
+rename_var (struct dictionary *d, struct variable *v, const char *new_name) 
+{
+  struct vardict_info vdi;
+
+  assert (dict_contains_var (d, v));
+
+  vdi = *var_get_vardict (v);
+  var_clear_vardict (v);
+  var_set_name (v, new_name);
+  var_set_vardict (v, &vdi);
+}
+
 /* Changes the name of V in D to name NEW_NAME.  Assert-fails if
    a variable named NEW_NAME is already in D, except that
    NEW_NAME may be the same as V's existing name. */
@@ -586,16 +550,11 @@ void 
 dict_rename_var (struct dictionary *d, struct variable *v,
                  const char *new_name) 
 {
-  assert (d != NULL);
-  assert (v != NULL);
-  assert (new_name != NULL);
-  assert (var_is_plausible_name (new_name, false));
-  assert (dict_contains_var (d, v));
-  assert (!compare_var_names (var_get_name (v), new_name, NULL)
+  assert (!strcasecmp (var_get_name (v), new_name)
           || dict_lookup_var (d, new_name) == NULL);
 
   hsh_force_delete (d->name_tab, v);
-  var_set_name (v, new_name);
+  rename_var (d, v, new_name);
   hsh_force_insert (d->name_tab, v);
 
   if (get_algorithm () == ENHANCED)
@@ -610,73 +569,62 @@ dict_rename_var (struct dictionary *d, s
    is returned. */
 bool
 dict_rename_vars (struct dictionary *d,
-                  struct variable **vars, char **new_names,
-                  size_t count, char **err_name) 
+                  struct variable **vars, char **new_names, size_t count,
+                  char **err_name) 
 {
+  struct pool *pool;
   char **old_names;
   size_t i;
-  bool success = true;
 
-  assert (d != NULL);
   assert (count == 0 || vars != NULL);
   assert (count == 0 || new_names != NULL);
 
+  /* Save the names of the variables to be renamed. */
+  pool = pool_create ();
+  old_names = pool_nalloc (pool, count, sizeof *old_names);
+  for (i = 0; i < count; i++) 
+    old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
+  
   /* Remove the variables to be renamed from the name hash,
-     save their names, and rename them. */
-  old_names = xnmalloc (count, sizeof *old_names);
+     and rename them. */
   for (i = 0; i < count; i++) 
     {
-      assert (d->var[vars[i]->index] == vars[i]);
-      assert (var_is_plausible_name (new_names[i], false));
       hsh_force_delete (d->name_tab, vars[i]);
-      old_names[i] = xstrdup (var_get_name (vars[i]));
-      var_set_name (vars[i], new_names[i]);
+      rename_var (d, vars[i], new_names[i]);
     }
 
   /* Add the renamed variables back into the name hash,
      checking for conflicts. */
   for (i = 0; i < count; i++)
-    {
-      assert (new_names[i] != NULL);
-      assert (*new_names[i] != '\0');
-      assert (strlen (new_names[i]) >= 1);
-      assert (strlen (new_names[i]) <= LONG_NAME_LEN);
-
-      if (hsh_insert (d->name_tab, vars[i]) != NULL)
-        {
-          /* There is a name conflict.
-             Back out all the name changes that have already
-             taken place, and indicate failure. */
-          size_t fail_idx = i;
-          if (err_name != NULL) 
-            *err_name = new_names[i];
+    if (hsh_insert (d->name_tab, vars[i]) != NULL)
+      {
+        /* There is a name conflict.
+           Back out all the name changes that have already
+           taken place, and indicate failure. */
+        size_t fail_idx = i;
+        if (err_name != NULL) 
+          *err_name = new_names[i];
 
-          for (i = 0; i < fail_idx; i++)
-            hsh_force_delete (d->name_tab, vars[i]);
+        for (i = 0; i < fail_idx; i++)
+          hsh_force_delete (d->name_tab, vars[i]);
           
-          for (i = 0; i < count; i++)
-            {
-              var_set_name (vars[i], old_names[i]);
-              hsh_force_insert (d->name_tab, vars[i]);
-            }
+        for (i = 0; i < count; i++)
+          {
+            rename_var (d, vars[i], old_names[i]);
+            hsh_force_insert (d->name_tab, vars[i]);
+          }
 
-          success = false;
-          goto done;
-        }
-    }
+        pool_destroy (pool);
+        return false;
+      }
 
   /* Clear short names. */
   if (get_algorithm () == ENHANCED)
     for (i = 0; i < count; i++)
       var_clear_short_name (vars[i]);
 
- done:
-  /* Free the old names we kept around. */
-  for (i = 0; i < count; i++)
-    free (old_names[i]);
-  free (old_names);
-
-  return success;
+  pool_destroy (pool);
+  return true;
 }
 
 /* Returns the weighting variable in dictionary D, or a null
@@ -706,7 +654,7 @@ dict_get_case_weight (const struct dicti
     return 1.0;
   else 
     {
-      double w = case_num (c, d->weight->fv);
+      double w = case_num (c, d->weight);
       if (w < 0.0 || var_is_num_missing (d->weight, w))
         w = 0.0;
       if ( w == 0.0 && *warn_on_invalid ) {
@@ -773,8 +721,8 @@ dict_set_case_limit (struct dictionary *
   d->case_limit = case_limit;
 }
 
-/* Returns the index of the next value to be added to D.  This
-   value is the number of `union value's that need to be
+/* Returns the case index of the next value to be added to D.
+   This value is the number of `union value's that need to be
    allocated to store a case for dictionary D. */
 int
 dict_get_next_value_idx (const struct dictionary *d) 
@@ -808,7 +756,7 @@ dict_compact_values (struct dictionary *
 
       if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH) 
         {
-          v->fv = d->next_value_idx;
+          set_var_case_index (v, d->next_value_idx);
           d->next_value_idx += var_get_value_cnt (v);
           i++;
         }
@@ -833,17 +781,18 @@ dict_get_compacted_value_cnt (const stru
 }
 
 /* Creates and returns an array mapping from a dictionary index
-   to the `fv' that the corresponding variable will have after
-   calling dict_compact_values().  Scratch variables receive -1
-   for `fv' because dict_compact_values() will delete them. */
+   to the case index that the corresponding variable will have
+   after calling dict_compact_values().  Scratch variables
+   receive -1 for case index because dict_compact_values() will
+   delete them. */
 int *
-dict_get_compacted_idx_to_fv (const struct dictionary *d) 
+dict_get_compacted_dict_index_to_case_index (const struct dictionary *d) 
 {
   size_t i;
   size_t next_value_idx;
-  int *idx_to_fv;
+  int *map;
   
-  idx_to_fv = xnmalloc (d->var_cnt, sizeof *idx_to_fv);
+  map = xnmalloc (d->var_cnt, sizeof *map);
   next_value_idx = 0;
   for (i = 0; i < d->var_cnt; i++)
     {
@@ -851,13 +800,13 @@ dict_get_compacted_idx_to_fv (const stru
 
       if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH) 
         {
-          idx_to_fv[i] = next_value_idx;
+          map[i] = next_value_idx;
           next_value_idx += var_get_value_cnt (v);
         }
       else 
-        idx_to_fv[i] = -1;
+        map[i] = -1;
     }
-  return idx_to_fv;
+  return map;
 }
 
 /* Returns true if a case for dictionary D would be smaller after
@@ -893,7 +842,7 @@ dict_compacting_would_change (const stru
   for (i = 0; i < dict_get_var_cnt (d); i++) 
     {
       struct variable *v = dict_get_var (d, i);
-      if (v->fv != case_idx)
+      if (var_get_case_index (v) != case_idx)
         return true;
       case_idx += var_get_value_cnt (v);
     }
@@ -943,7 +892,7 @@ dict_make_compactor (const struct dictio
 
       if (dict_class_from_id (var_get_name (v)) == DC_SCRATCH)
         continue;
-      if (map != NULL && map->src_idx + map->cnt == v->fv) 
+      if (map != NULL && map->src_idx + map->cnt == var_get_case_index (v)) 
         map->cnt += var_get_value_cnt (v);
       else 
         {
@@ -951,7 +900,7 @@ dict_make_compactor (const struct dictio
             compactor->maps = x2nrealloc (compactor->maps, &map_allocated,
                                           sizeof *compactor->maps);
           map = &compactor->maps[compactor->map_cnt++];
-          map->src_idx = v->fv;
+          map->src_idx = var_get_case_index (v);
           map->dst_idx = value_idx;
           map->cnt = var_get_value_cnt (v);
         }
@@ -1079,39 +1028,29 @@ dict_set_documents (struct dictionary *d
     d->documents = xstrdup (documents);
 }
 
-/* Creates in D a vector named NAME that contains CNT variables
-   VAR (see cmd_vector()).  Returns true if successful, or
-   false if a vector named NAME already exists in D. */
+/* Creates in D a vector named NAME that contains the CNT
+   variables in VAR.  Returns true if successful, or false if a
+   vector named NAME already exists in D. */
 bool
 dict_create_vector (struct dictionary *d,
                     const char *name,
                     struct variable **var, size_t cnt) 
 {
-  struct vector *vector;
   size_t i;
 
-  assert (d != NULL);
-  assert (name != NULL);
-  assert (var_is_plausible_name (name, false));
   assert (var != NULL);
   assert (cnt > 0);
-  
-  if (dict_lookup_vector (d, name) != NULL)
-    return false;
-
-  d->vector = xnrealloc (d->vector, d->vector_cnt + 1, sizeof *d->vector);
-  vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
-  vector->idx = d->vector_cnt++;
-  str_copy_trunc (vector->name, sizeof vector->name, name);
-  vector->var = xnmalloc (cnt, sizeof *var);
   for (i = 0; i < cnt; i++)
+    assert (dict_contains_var (d, var[i]));
+  
+  if (dict_lookup_vector (d, name) == NULL)
     {
-      assert (dict_contains_var (d, var[i]));
-      vector->var[i] = var[i];
+      d->vector = xnrealloc (d->vector, d->vector_cnt + 1, sizeof *d->vector);
+      d->vector[d->vector_cnt++] = vector_create (name, var, cnt);
+      return true; 
     }
-  vector->cnt = cnt;
-  
-  return true;
+  else
+    return false;
 }
 
 /* Returns the vector in D with index IDX, which must be less
@@ -1140,12 +1079,8 @@ const struct vector *
 dict_lookup_vector (const struct dictionary *d, const char *name) 
 {
   size_t i;
-
-  assert (d != NULL);
-  assert (name != NULL);
-
   for (i = 0; i < d->vector_cnt; i++)
-    if (!strcasecmp (d->vector[i]->name, name))
+    if (!strcasecmp (vector_get_name (d->vector[i]), name))
       return d->vector[i];
   return NULL;
 }
@@ -1156,14 +1091,10 @@ dict_clear_vectors (struct dictionary *d
 {
   size_t i;
   
-  assert (d != NULL);
-
-  for (i = 0; i < d->vector_cnt; i++) 
-    {
-      free (d->vector[i]->var);
-      free (d->vector[i]);
-    }
+  for (i = 0; i < d->vector_cnt; i++)
+    vector_destroy (d->vector[i]);
   free (d->vector);
+
   d->vector = NULL;
   d->vector_cnt = 0;
 }
@@ -1182,6 +1113,51 @@ hash_string (const void *s, const void *
   return hsh_hash_string (s);
 }
 
+
+/* Sets V's short name to BASE, followed by a suffix of the form
+   _A, _B, _C, ..., _AA, _AB, etc. according to the value of
+   SUFFIX_NUMBER.  Truncates BASE as necessary to fit. */
+static void
+set_var_short_name_suffix (struct variable *v, const char *base,
+                           int suffix_number)
+{
+  char suffix[SHORT_NAME_LEN + 1];
+  char short_name[SHORT_NAME_LEN + 1];
+  char *start, *end;
+  int len, ofs;
+
+  assert (v != NULL);
+  assert (suffix_number >= 0);
+
+  /* Set base name. */
+  var_set_short_name (v, base);
+
+  /* Compose suffix. */
+  start = end = suffix + sizeof suffix - 1;
+  *end = '\0';
+  do 
+    {
+      *--start = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[suffix_number % 26];
+      if (start <= suffix + 1)
+        msg (SE, _("Variable suffix too large."));
+      suffix_number /= 26;
+    }
+  while (suffix_number > 0);
+  *--start = '_';
+
+  /* Append suffix to V's short name. */
+  str_copy_trunc (short_name, sizeof short_name, base);
+  len = end - start;
+  if (len + strlen (short_name) > SHORT_NAME_LEN)
+    ofs = SHORT_NAME_LEN - len;
+  else
+    ofs = strlen (short_name);
+  strcpy (short_name + ofs, start);
+
+  /* Set name. */
+  var_set_short_name (v, short_name);
+}
+
 /* Assigns a valid, unique short_name[] to each variable in D.
    Each variable whose actual name is short has highest priority
    for that short name.  Otherwise, variables with an existing
@@ -1236,7 +1212,7 @@ dict_assign_short_names (struct dictiona
               if (trial == 0)
                 var_set_short_name (v, var_get_name (v));
               else
-                var_set_short_name_suffix (v, var_get_name (v), trial - 1);
+                set_var_short_name_suffix (v, var_get_name (v), trial - 1);
 
               trial++;
             }
Index: src/data/dictionary.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/dictionary.h,v
retrieving revision 1.4
diff -u -p -r1.4 dictionary.h
--- src/data/dictionary.h	23 Sep 2006 00:15:58 -0000	1.4
+++ src/data/dictionary.h	10 Dec 2006 03:30:16 -0000
@@ -82,7 +82,7 @@ size_t dict_get_case_size (const struct 
 
 void dict_compact_values (struct dictionary *);
 size_t dict_get_compacted_value_cnt (const struct dictionary *);
-int *dict_get_compacted_idx_to_fv (const struct dictionary *);
+int *dict_get_compacted_dict_index_to_case_index (const struct dictionary *);
 bool dict_compacting_would_shrink (const struct dictionary *);
 bool dict_compacting_would_change (const struct dictionary *);
 
Index: src/data/format.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/format.c,v
retrieving revision 1.15
diff -u -p -r1.15 format.c
--- src/data/format.c	5 Dec 2006 15:10:21 -0000	1.15
+++ src/data/format.c	10 Dec 2006 03:30:16 -0000
@@ -26,6 +26,7 @@
 
 #include <data/identifier.h>
 #include <data/settings.h>
+#include <data/value.h>
 #include <data/variable.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
@@ -300,15 +301,15 @@ fmt_check_output (const struct fmt_spec 
    TYPE and returns true if so.  Otherwise returns false and
    emits an error message. */
 bool
-fmt_check_type_compat (const struct fmt_spec *format, int var_type)
+fmt_check_type_compat (const struct fmt_spec *format, enum var_type var_type)
 {
-  assert (var_type == NUMERIC || var_type == ALPHA);
-  if ((var_type == ALPHA) != (fmt_is_string (format->type) != 0))
+  assert (var_type_is_valid (var_type));
+  if ((var_type == VAR_STRING) != (fmt_is_string (format->type) != 0))
     {
       char str[FMT_STRING_LEN_MAX + 1];
       msg (SE, _("%s variables are not compatible with %s format %s."),
-           var_type == ALPHA ? _("String") : _("Numeric"),
-           var_type == ALPHA ? _("numeric") : _("string"),
+           var_type == VAR_STRING ? _("String") : _("Numeric"),
+           var_type == VAR_STRING ? _("numeric") : _("string"),
            fmt_to_string (format, str));
       return false;
     }
@@ -321,7 +322,7 @@ fmt_check_type_compat (const struct fmt_
 bool
 fmt_check_width_compat (const struct fmt_spec *format, int width)
 {
-  if (!fmt_check_type_compat (format, width != 0 ? ALPHA : NUMERIC))
+  if (!fmt_check_type_compat (format, var_type_from_width (width)))
     return false;
   if (fmt_var_width (format) != width)
     {
Index: src/data/format.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/format.h,v
retrieving revision 1.10
diff -u -p -r1.10 format.h
--- src/data/format.h	5 Dec 2006 15:10:21 -0000	1.10
+++ src/data/format.h	10 Dec 2006 03:30:16 -0000
@@ -24,6 +24,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
+#include <data/variable.h>
 #include <libpspp/str.h>
 
 /* Format type categories. */
@@ -82,7 +83,7 @@ struct fmt_spec fmt_default_for_width (i
 bool fmt_check (const struct fmt_spec *, bool for_input);
 bool fmt_check_input (const struct fmt_spec *);
 bool fmt_check_output (const struct fmt_spec *);
-bool fmt_check_type_compat (const struct fmt_spec *, int var_type);
+bool fmt_check_type_compat (const struct fmt_spec *, enum var_type);
 bool fmt_check_width_compat (const struct fmt_spec *, int var_width);
 
 /* Working with formats. */
Index: src/data/missing-values.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/missing-values.c,v
retrieving revision 1.5
diff -u -p -r1.5 missing-values.c
--- src/data/missing-values.c	5 Dec 2006 15:10:21 -0000	1.5
+++ src/data/missing-values.c	10 Dec 2006 03:30:16 -0000
@@ -303,7 +303,7 @@ can_resize_string (const char *s, int ol
    contains only spaces in the characters that will be
    trimmed. */
 bool
-mv_is_resizable (struct missing_values *mv, int width) 
+mv_is_resizable (const struct missing_values *mv, int width) 
 {
   assert ((width == 0) == (mv->width == 0));
   if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
Index: src/data/missing-values.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/missing-values.h,v
retrieving revision 1.2
diff -u -p -r1.2 missing-values.h
--- src/data/missing-values.h	5 Dec 2006 15:10:21 -0000	1.2
+++ src/data/missing-values.h	10 Dec 2006 03:30:16 -0000
@@ -69,7 +69,7 @@ bool mv_has_range (const struct missing_
 void mv_pop_range (struct missing_values *, double *low, double *high);
 void mv_peek_range (const struct missing_values *, double *low, double *high);
 
-bool mv_is_resizable (struct missing_values *, int width);
+bool mv_is_resizable (const struct missing_values *, int width);
 void mv_resize (struct missing_values *, int width);
 
 typedef bool mv_is_missing_func (const struct missing_values *,
Index: src/data/por-file-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-reader.c,v
retrieving revision 1.13
diff -u -p -r1.13 por-file-reader.c
--- src/data/por-file-reader.c	5 Dec 2006 15:10:21 -0000	1.13
+++ src/data/por-file-reader.c	10 Dec 2006 03:30:19 -0000
@@ -36,6 +36,7 @@
 #include "dictionary.h"
 #include "file-handle-def.h"
 #include "format.h"
+#include "missing-values.h"
 #include <libpspp/hash.h>
 #include <libpspp/magic.h>
 #include <libpspp/misc.h>
@@ -663,7 +664,7 @@ read_value_label (struct pfm_reader *r, 
 	{
 	  struct variable *var = v[j];
 
-	  if (!val_labs_replace (var->val_labs, val, label))
+	  if (!var_add_value_label (var, &val, label))
 	    continue;
 
 	  if (var_is_numeric (var))
@@ -698,14 +699,14 @@ pfm_read_case (struct pfm_reader *r, str
       
       if (width == 0)
         {
-          case_data_rw (c, idx)->f = read_float (r);
+          case_data_rw_idx (c, idx)->f = read_float (r);
           idx++;
         }
       else
         {
           char string[256];
           read_string (r, string);
-          buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
+          buf_copy_str_rpad (case_data_rw_idx (c, idx)->s, width, string);
           idx += DIV_RND_UP (width, MAX_SHORT_STRING);
         }
     }
Index: src/data/por-file-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-writer.c,v
retrieving revision 1.6
diff -u -p -r1.6 por-file-writer.c
--- src/data/por-file-writer.c	5 Dec 2006 15:10:21 -0000	1.6
+++ src/data/por-file-writer.c	10 Dec 2006 03:30:19 -0000
@@ -19,7 +19,7 @@
 
 #include <config.h>
 #include "por-file-writer.h"
-#include <libpspp/message.h>
+
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -30,18 +30,22 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
-#include <libpspp/alloc.h>
+
 #include "case.h"
 #include "dictionary.h"
-#include <libpspp/message.h>
 #include "file-handle-def.h"
+#include "format.h"
+#include "missing-values.h"
+#include "stat-macros.h"
+#include "value-labels.h"
+#include "variable.h"
+
+#include <libpspp/alloc.h>
 #include <libpspp/hash.h>
 #include <libpspp/magic.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include "stat-macros.h"
 #include <libpspp/str.h>
-#include "value-labels.h"
-#include "variable.h"
 #include <libpspp/version.h>
 
 #include "gettext.h"
@@ -134,7 +138,7 @@ pfm_open_writer (struct file_handle *fh,
       const struct variable *dv = dict_get_var (dict, i);
       struct pfm_var *pv = &w->vars[i];
       pv->width = var_get_width (dv);
-      pv->fv = dv->fv;
+      pv->fv = var_get_case_index (dv);
     }
 
   w->digits = opts.digits;
@@ -372,18 +376,19 @@ write_value_labels (struct pfm_writer *w
     {
       struct val_labs_iterator *j;
       struct variable *v = dict_get_var (dict, i);
+      const struct val_labs *val_labs = var_get_value_labels (v);
       struct val_lab *vl;
 
-      if (!val_labs_count (v->val_labs))
+      if (val_labs == NULL)
 	continue;
 
       buf_write (w, "D", 1);
       write_int (w, 1);
       write_string (w, var_get_short_name (v));
-      write_int (w, val_labs_count (v->val_labs));
+      write_int (w, val_labs_count (val_labs));
 
-      for (vl = val_labs_first_sorted (v->val_labs, &j); vl != NULL;
-           vl = val_labs_next (v->val_labs, &j)) 
+      for (vl = val_labs_first_sorted (val_labs, &j); vl != NULL;
+           vl = val_labs_next (val_labs, &j)) 
         {
           write_value (w, &vl->value, v);
           write_string (w, vl->label);
@@ -405,11 +410,11 @@ pfm_write_case (struct pfm_writer *w, co
       struct pfm_var *v = &w->vars[i];
       
       if (v->width == 0)
-        write_float (w, case_num (c, v->fv));
+        write_float (w, case_num_idx (c, v->fv));
       else
 	{
 	  write_int (w, v->width);
-          buf_write (w, case_str (c, v->fv), v->width);
+          buf_write (w, case_str_idx (c, v->fv), v->width);
 	}
     }
 
Index: src/data/procedure.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/procedure.c,v
retrieving revision 1.16
diff -u -p -r1.16 procedure.c
--- src/data/procedure.c	5 Dec 2006 15:10:21 -0000	1.16
+++ src/data/procedure.c	10 Dec 2006 03:30:19 -0000
@@ -265,7 +265,7 @@ create_trns_case (struct ccase *trns_cas
   for (i = 0; i < var_cnt; i++) 
     {
       struct variable *v = dict_get_var (dict, i);
-      union value *value = case_data_rw (trns_case, v->fv);
+      union value *value = case_data_rw (trns_case, v);
 
       if (var_is_numeric (v))
         value->f = var_get_leave (v) ? 0.0 : SYSMIS;
@@ -398,9 +398,9 @@ clear_case (const struct dataset *ds, st
       if (!var_get_leave (v)) 
         {
           if (var_is_numeric (v))
-            case_data_rw (c, v->fv)->f = SYSMIS;
+            case_data_rw (c, v)->f = SYSMIS; 
           else
-            memset (case_data_rw (c, v->fv)->s, ' ', var_get_width (v));
+            memset (case_data_rw (c, v)->s, ' ', var_get_width (v));
         } 
     }
 }
@@ -937,7 +937,7 @@ filter_trns_proc (void *filter_var_,
   
 {
   struct variable *filter_var = filter_var_;
-  double f = case_num (c, filter_var->fv);
+  double f = case_num (c, filter_var);
   return (f != 0.0 && !var_is_num_missing (filter_var, f)
           ? TRNS_CONTINUE : TRNS_DROP_CASE);
 }
Index: src/data/sys-file-private.c
===================================================================
RCS file: src/data/sys-file-private.c
diff -N src/data/sys-file-private.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/sys-file-private.c	10 Dec 2006 03:30:19 -0000
@@ -0,0 +1,45 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+#include "sys-file-private.h"
+
+#include <data/value.h>
+#include <libpspp/assertion.h>
+
+/* Return the number of bytes used when writing case_data for a variable 
+   of WIDTH */
+int
+sfm_width_to_bytes (int width)
+{
+  assert (width >= 0);
+
+  if (width == 0) 
+    return MAX_SHORT_STRING;
+  else if (width < MIN_VERY_LONG_STRING) 
+    return ROUND_UP (width, MAX_SHORT_STRING);
+  else 
+    {
+      int chunks = width / EFFECTIVE_LONG_STRING_LENGTH ;
+      int remainder = width % EFFECTIVE_LONG_STRING_LENGTH ;
+      int bytes = remainder + (chunks * MIN_VERY_LONG_STRING);
+      return ROUND_UP (bytes, MAX_SHORT_STRING); 
+    }
+}
+
+
Index: src/data/sys-file-private.h
===================================================================
RCS file: src/data/sys-file-private.h
diff -N src/data/sys-file-private.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/sys-file-private.h	10 Dec 2006 03:30:19 -0000
@@ -0,0 +1,30 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#ifndef DATA_SYS_FILE_PRIVATE_H
+#define DATA_SYS_FILE_PRIVATE_H 1
+
+/* This nonsense is required for SPSS compatibility. */
+
+#define MIN_VERY_LONG_STRING 256
+#define EFFECTIVE_LONG_STRING_LENGTH (MIN_VERY_LONG_STRING - 4)
+
+int sfm_width_to_bytes (int width);
+
+#endif /* data/sys-file-private.h */
Index: src/data/sys-file-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-reader.c,v
retrieving revision 1.27
diff -u -p -r1.27 sys-file-reader.c
--- src/data/sys-file-reader.c	5 Dec 2006 15:10:21 -0000	1.27
+++ src/data/sys-file-reader.c	10 Dec 2006 03:30:19 -0000
@@ -19,6 +19,10 @@
 
 #include <config.h>
 
+#include "sys-file-reader.h"
+#include "sfm-private.h"
+#include "sys-file-private.h"
+
 #include <stdlib.h>
 #include <errno.h>
 #include <float.h>
@@ -35,16 +39,15 @@
 #include <libpspp/hash.h>
 #include <libpspp/array.h>
 
-#include "sys-file-reader.h"
-#include "sfm-private.h"
 #include "case.h"
 #include "dictionary.h"
 #include "file-handle-def.h"
 #include "file-name.h"
 #include "format.h"
+#include "missing-values.h"
 #include "value-labels.h"
-#include "variable.h"
 #include "value.h"
+#include "variable.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -528,7 +531,7 @@ sfm_open_reader (struct file_handle *fh,
                         }
 
                       /* Identify any duplicates. */
-		      if ( compare_var_names(short_name, long_name, 0) &&
+		      if ( strcasecmp (short_name, long_name) &&
 			   NULL != dict_lookup_var (*dict, long_name))
                         lose ((ME, _("%s: Duplicate long variable name `%s' "
                                      "within system file."),
@@ -635,7 +638,7 @@ sfm_open_reader (struct file_handle *fh,
 			      else
 				l -= var_get_width (v);
 
-			      idx = v->index;
+			      idx = var_get_dict_index (v);
 			      while ( l > 0 ) 
 				{
 				  struct variable *v_next;
@@ -649,7 +652,7 @@ sfm_open_reader (struct file_handle *fh,
 				  dict_delete_var(*dict, v_next);
 				}
 
-			      assert ( length > MAX_LONG_STRING );
+			      assert ( length >= MIN_VERY_LONG_STRING );
 
                               var_set_width (v, length);
 			    }
@@ -723,7 +726,7 @@ sfm_open_reader (struct file_handle *fh,
         struct variable *v = dict_get_var (*dict, i);
         struct sfm_var *sv = &r->vars[i];
         sv->width = var_get_width (v);
-        sv->fv = v->fv; 
+        sv->fv = var_get_case_index (v); 
       }
   }
 
@@ -1413,7 +1416,7 @@ read_value_labels (struct sfm_reader *r,
       for (j = 0; j < n_labels; j++)
 	{
           struct label *label = labels + j;
-	  if (!val_labs_replace (v->val_labs, label->value, label->label))
+	  if (var_add_value_label (v, &label->value, label->label))
 	    continue;
 
 	  if (var_is_numeric (var[0]))
@@ -1676,7 +1679,7 @@ sfm_read_case (struct sfm_reader *r, str
           
           for (i = 0; i < r->var_cnt; i++) 
             if (r->vars[i].width == 0)
-              bswap_flt64 (&case_data_rw (c, r->vars[i].fv)->f);
+              bswap_flt64 (&case_data_rw_idx (c, r->vars[i].fv)->f);
         }
 
       /* Fix up SYSMIS values if needed.
@@ -1687,8 +1690,8 @@ sfm_read_case (struct sfm_reader *r, str
           int i;
           
           for (i = 0; i < r->var_cnt; i++) 
-            if (r->vars[i].width == 0 && case_num (c, i) == r->sysmis)
-              case_data_rw (c, r->vars[i].fv)->f = SYSMIS;
+            if (r->vars[i].width == 0 && case_num_idx (c, i) == r->sysmis)
+              case_data_rw_idx (c, r->vars[i].fv)->f = SYSMIS;
         }
     }
   else 
@@ -1725,7 +1728,7 @@ sfm_read_case (struct sfm_reader *r, str
               flt64 f = *bounce_cur++;
               if (r->reverse_endian)
                 bswap_flt64 (&f);
-              case_data_rw (c, sv->fv)->f = f == r->sysmis ? SYSMIS : f;
+              case_data_rw_idx (c, sv->fv)->f = f == r->sysmis ? SYSMIS : f;
             }
           else
             {
@@ -1733,14 +1736,16 @@ sfm_read_case (struct sfm_reader *r, str
 	      int ofs = 0;
               while (ofs < sv->width )
                 {
-                  const int chunk = MIN (MAX_LONG_STRING, sv->width - ofs);
-                  memcpy (case_data_rw (c, sv->fv)->s + ofs, bounce_cur, chunk);
+                  const int chunk = MIN (MIN_VERY_LONG_STRING - 1,
+                                         sv->width - ofs);
+                  memcpy (case_data_rw_idx (c, sv->fv)->s + ofs,
+                          bounce_cur, chunk);
 
                   bounce_cur += DIV_RND_UP (chunk, sizeof (flt64));
 
                   ofs += chunk;
                 }
-	      bounce_cur = bc_start + width_to_bytes(sv->width) / sizeof(flt64);
+	      bounce_cur = bc_start + sfm_width_to_bytes (sv->width) / sizeof(flt64);
             }
         }
 
Index: src/data/sys-file-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-writer.c,v
retrieving revision 1.17
diff -u -p -r1.17 sys-file-writer.c
--- src/data/sys-file-writer.c	5 Dec 2006 15:10:21 -0000	1.17
+++ src/data/sys-file-writer.c	10 Dec 2006 03:30:20 -0000
@@ -21,6 +21,7 @@
 
 #include "sys-file-writer.h"
 #include "sfm-private.h"
+#include "sys-file-private.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -41,6 +42,8 @@
 #include "case.h"
 #include "dictionary.h"
 #include "file-handle-def.h"
+#include "format.h"
+#include "missing-values.h"
 #include "settings.h"
 #include "value-labels.h"
 #include "variable.h"
@@ -114,7 +117,7 @@ static inline int
 var_flt64_cnt (const struct variable *v) 
 {
   assert(sizeof(flt64) == MAX_SHORT_STRING);
-  return width_to_bytes(var_get_width (v)) / MAX_SHORT_STRING ;
+  return sfm_width_to_bytes(var_get_width (v)) / MAX_SHORT_STRING ;
 }
 
 static inline int
@@ -218,10 +221,10 @@ sfm_open_writer (struct file_handle *fh,
       struct sfm_var *sv = &w->vars[i];
       sv->width = var_get_width (dv);
       /* spss compatibility nonsense */
-      if ( var_is_very_long_string (dv) ) 
+      if ( var_get_width (dv) >= MIN_VERY_LONG_STRING ) 
 	  w->has_vls = true;
 
-      sv->fv = dv->fv;
+      sv->fv = var_get_case_index (dv);
       sv->flt64_cnt = var_flt64_cnt (dv);
     }
 
@@ -244,32 +247,34 @@ sfm_open_writer (struct file_handle *fh,
       int wcount = var_get_width (v);
 
       do {
-	struct variable var_cont = *v;
+	struct variable *var_cont = var_clone (v);
+        var_set_short_name (var_cont, var_get_short_name (v));
 	if ( var_is_alpha (v)) 
 	  {
 	    if ( 0 != count ) 
 	      {
-		var_clear_missing_values (&var_cont);
-                var_set_short_name (&var_cont,
+		var_clear_missing_values (var_cont);
+                var_set_short_name (var_cont,
                                     cont_var_name (var_get_short_name (v),
                                                    count));
-                var_clear_label (&var_cont);
+                var_clear_label (var_cont);
 		w->var_cnt_vls++;
 	      }
 	    count++;
-	    if ( wcount > MAX_LONG_STRING ) 
+	    if ( wcount >= MIN_VERY_LONG_STRING ) 
 	      {
-                var_set_width (&var_cont, MAX_LONG_STRING);
+                var_set_width (var_cont, MIN_VERY_LONG_STRING - 1);
 		wcount -= EFFECTIVE_LONG_STRING_LENGTH;
 	      }
 	    else
 	      {
-		var_set_width (&var_cont, wcount);
-		wcount -= var_get_width (&var_cont);
+		var_set_width (var_cont, wcount);
+		wcount -= var_get_width (var_cont);
 	      }
 	  }
 
-	write_variable (w, &var_cont);
+	write_variable (w, var_cont);
+        var_destroy (var_cont);
       } while(wcount > 0);
     }
 
@@ -458,7 +463,7 @@ write_variable (struct sfm_writer *w, co
   const char *label = var_get_label (v);
 
   sv.rec_type = 2;
-  sv.type = MIN(var_get_width (v), MAX_LONG_STRING);
+  sv.type = MIN (var_get_width (v), MIN_VERY_LONG_STRING - 1);
   sv.has_var_label = label != NULL;
 
   mv_copy (&mv, var_get_missing_values (v));
@@ -524,7 +529,7 @@ write_variable (struct sfm_writer *w, co
       memset (&sv.write, 0, sizeof sv.write);
       memset (&sv.name, 0, sizeof sv.name);
 
-      pad_count = DIV_RND_UP (MIN(var_get_width (v), MAX_LONG_STRING),
+      pad_count = DIV_RND_UP (MIN(var_get_width (v), MIN_VERY_LONG_STRING - 1),
 			      (int) sizeof (flt64)) - 1;
       for (i = 0; i < pad_count; i++)
 	buf_write (w, &sv, sizeof sv);
@@ -550,6 +555,7 @@ write_value_labels (struct sfm_writer *w
       int32_t vars[1] ;
     } ATTRIBUTE((packed));
 
+  const struct val_labs *val_labs;
   struct val_labs_iterator *i;
   struct value_label_rec *vlr;
   struct var_idx_rec vir;
@@ -557,23 +563,24 @@ write_value_labels (struct sfm_writer *w
   size_t vlr_size;
   flt64 *loc;
 
-  if (!val_labs_count (v->val_labs))
+  val_labs = var_get_value_labels (v);
+  if (val_labs == NULL)
     return;
 
   /* Pass 1: Count bytes. */
   vlr_size = (sizeof (struct value_label_rec)
-	      + sizeof (flt64) * (val_labs_count (v->val_labs) - 1));
-  for (vl = val_labs_first (v->val_labs, &i); vl != NULL;
-       vl = val_labs_next (v->val_labs, &i))
+	      + sizeof (flt64) * (val_labs_count (val_labs) - 1));
+  for (vl = val_labs_first (val_labs, &i); vl != NULL;
+       vl = val_labs_next (val_labs, &i))
     vlr_size += ROUND_UP (strlen (vl->label) + 1, sizeof (flt64));
 
   /* Pass 2: Copy bytes. */
   vlr = xmalloc (vlr_size);
   vlr->rec_type = 3;
-  vlr->n_labels = val_labs_count (v->val_labs);
+  vlr->n_labels = val_labs_count (val_labs);
   loc = vlr->labels;
-  for (vl = val_labs_first_sorted (v->val_labs, &i); vl != NULL;
-       vl = val_labs_next (v->val_labs, &i))
+  for (vl = val_labs_first_sorted (val_labs, &i); vl != NULL;
+       vl = val_labs_next (val_labs, &i))
     {
       size_t len = strlen (vl->label);
 
@@ -662,7 +669,7 @@ write_variable_display_parameters (struc
 
 	  while (wcount > 0) 
 	    {
-	      params.width = wcount > MAX_LONG_STRING ? 32 : wcount;
+	      params.width = wcount >= MIN_VERY_LONG_STRING ? 32 : wcount;
 	    
 	      buf_write (w, &params, sizeof(params));
 
@@ -699,7 +706,7 @@ write_vls_length_table (struct sfm_write
     {
       const struct variable *v = dict_get_var (dict, i);
       
-      if ( var_get_width (v) <=  MAX_LONG_STRING ) 
+      if ( var_get_width (v) < MIN_VERY_LONG_STRING ) 
 	continue;
 
       ds_put_format (&vls_length_map, "%s=%05d",
@@ -904,17 +911,17 @@ sfm_write_case (struct sfm_writer *w, co
 
           if (v->width == 0) 
 	    {
-	      *bounce_cur = case_num (c, v->fv);
+	      *bounce_cur = case_num_idx (c, v->fv);
 	      bounce_cur += v->flt64_cnt;
 	    }
           else 
 	    { int ofs = 0;
 	    while (ofs < v->width)
 	      {
-		int chunk = MIN (MAX_LONG_STRING, v->width - ofs);
+		int chunk = MIN (MIN_VERY_LONG_STRING - 1, v->width - ofs);
 		int nv = DIV_RND_UP (chunk, sizeof (flt64));
 		buf_copy_rpad ((char *) bounce_cur, nv * sizeof (flt64),
-			       case_data (c, v->fv)->s + ofs, chunk);
+			       case_data_idx (c, v->fv)->s + ofs, chunk);
 		bounce_cur += nv;
 		ofs += chunk;
 	      }
Index: src/data/value-labels.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/value-labels.c,v
retrieving revision 1.11
diff -u -p -r1.11 value-labels.c
--- src/data/value-labels.c	8 Dec 2006 22:24:08 -0000	1.11
+++ src/data/value-labels.c	10 Dec 2006 03:30:20 -0000
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 
 #include <data/data-out.h>
+#include <data/format.h>
+#include <data/value.h>
 #include <data/variable.h>
 #include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
@@ -72,7 +74,8 @@ val_labs_copy (const struct val_labs *vl
   struct val_labs_iterator *i;
   struct val_lab *vl;
 
-  assert (vls != NULL);
+  if (vls == NULL)
+    return NULL;
 
   copy = val_labs_create (vls->width);
   for (vl = val_labs_first (vls, &i); vl != NULL;
@@ -155,12 +158,7 @@ val_labs_clear (struct val_labs *vls) 
 size_t
 val_labs_count (const struct val_labs *vls) 
 {
-  assert (vls != NULL);
-
-  if (vls->labels == NULL)
-    return 0;
-  else
-    return hsh_count (vls->labels);
+  return vls == NULL || vls->labels == NULL ? 0 : hsh_count (vls->labels);
 }
 
 /* One value label in internal format. */
@@ -222,29 +220,19 @@ val_labs_add (struct val_labs *vls, unio
    if there wasn't already a value label for VALUE, or true if
    there was.  Behavior is undefined if VLS's width is greater
    than MAX_SHORT_STRING. */
-bool
+void
 val_labs_replace (struct val_labs *vls, union value value, const char *label) 
 {
-  struct int_val_lab *ivl;
-
-  assert (vls != NULL);
   assert (vls->width <= MAX_SHORT_STRING);
-  assert (label != NULL);
-
-  if (vls->labels == NULL)
+  if (vls->labels != NULL)
     {
-      val_labs_add (vls, value, label);
-      return false;
+      struct int_val_lab *new = create_int_val_lab (vls, value, label);
+      struct int_val_lab *old = hsh_replace (vls->labels, new);
+      if (old != NULL) 
+        free_int_val_lab (old, vls); 
     }
-
-  ivl = hsh_replace (vls->labels, create_int_val_lab (vls, value, label));
-  if (ivl == NULL) 
-    return false;
   else 
-    {
-      free_int_val_lab (ivl, vls);
-      return true;
-    }
+    val_labs_add (vls, value, label);  
 }
 
 /* Removes any value label for VALUE within VLS.  Returns true
@@ -274,12 +262,9 @@ val_labs_remove (struct val_labs *vls, u
 char *
 val_labs_find (const struct val_labs *vls, union value value) 
 {
-  assert (vls != NULL);
-
-  if (vls->width > MAX_SHORT_STRING)
-    return NULL;
-
-  if (vls->labels != NULL) 
+  if (vls != NULL
+      && vls->width <= MAX_SHORT_STRING
+      && vls->labels != NULL)
     {
       struct int_val_lab ivl, *vlp;
 
@@ -536,30 +521,3 @@ free_atom (void *atom_, const void *aux 
   free (atom->string);
   free (atom);
 }
-
-
-/* Get a string representing the value.
-   That is, if it has a label, then return that label,
-   otherwise, if the value is alpha, then return the string for it,
-   else format it and return the formatted string
-*/
-const char *
-value_to_string (const union value *val, const struct variable *var)
-{
-  char *s;
-  
-  assert (val != NULL);
-  assert (var != NULL);
-
-  s = val_labs_find (var->val_labs, *val);
-  if (s == NULL) 
-    {
-      static char buf[MAX_STRING + 1];
-      const struct fmt_spec *print = var_get_print_format (var);
-      data_out (val, print, buf);
-      buf[print->w] = '\0';
-      s = buf;
-    }
-  
-  return s;
-}
Index: src/data/value-labels.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/value-labels.h,v
retrieving revision 1.4
diff -u -p -r1.4 value-labels.h
--- src/data/value-labels.h	14 Oct 2006 00:25:20 -0000	1.4
+++ src/data/value-labels.h	10 Dec 2006 03:30:20 -0000
@@ -44,7 +44,7 @@ bool val_labs_can_set_width (const struc
 void val_labs_set_width (struct val_labs *, int new_width);
 
 bool val_labs_add (struct val_labs *, union value, const char *);
-bool val_labs_replace (struct val_labs *, union value, const char *);
+void val_labs_replace (struct val_labs *, union value, const char *);
 bool val_labs_remove (struct val_labs *, union value);
 char *val_labs_find (const struct val_labs *, union value);
 
@@ -58,10 +58,4 @@ struct val_lab *val_labs_next (const str
                                struct val_labs_iterator **);
 void val_labs_done (struct val_labs_iterator **);
 
-/* Return a string representing this value, in the form most 
-   appropriate from a human factors perspective.
-   (IE: the label if it has one, otherwise the alpha/numeric )
-*/
-const char *value_to_string(const union value *, const struct variable *);
-
 #endif /* value-labels.h */
Index: src/data/value.c
===================================================================
RCS file: src/data/value.c
diff -N src/data/value.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/value.c	10 Dec 2006 03:30:20 -0000
@@ -0,0 +1,56 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+#include "value.h"
+
+#include <libpspp/hash.h>
+#include <libpspp/str.h>
+
+#include "xalloc.h"
+
+/* Duplicate a value.
+   The caller is responsible for freeing the returned value. */
+union value *
+value_dup (const union value *val, int width)
+{
+  return xmemdup (val, MAX (width, sizeof *val));
+}
+
+/* Compares A and B, which both have the given WIDTH, and returns
+   a strcmp()-type result.
+   Only the short string portion of longer strings are
+   compared. */
+int
+compare_values (const union value *a, const union value *b, int width) 
+{
+  return (width == 0
+          ? (a->f < b->f ? -1 : a->f > b->f)
+          : memcmp (a->s, b->s, MIN (MAX_SHORT_STRING, width)));
+}
+
+/* Create a hash of V, which has the given WIDTH.
+   Only the short string portion of a longer string is hashed. */
+unsigned 
+hash_value (const union value *v, int width)
+{
+  return (width == 0
+          ? hsh_hash_double (v->f)
+          : hsh_hash_bytes (v->s, MIN (MAX_SHORT_STRING, width)));
+}
Index: src/data/value.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/value.h,v
retrieving revision 1.4
diff -u -p -r1.4 value.h
--- src/data/value.h	6 May 2006 23:04:05 -0000	1.4
+++ src/data/value.h	10 Dec 2006 03:30:20 -0000
@@ -21,26 +21,17 @@
 #define value_h 1
 
 #include <float.h>
-
-#include <config.h>
+#include <libpspp/misc.h>
+#include "minmax.h"
 
 /* Values. */
 
-/* Max length of a short string value, generally 8 chars. */
-#define MAX_SHORT_STRING ( (SIZEOF_DOUBLE)>=8 ? (SIZEOF_DOUBLE + 1)/2 * 2 : 8 )
-
+/* "Short" strings, which are generally those no more than 8
+   characters wide, can participate in more operations than
+   longer strings. */
+#define MAX_SHORT_STRING (MAX (ROUND_UP (SIZEOF_DOUBLE, 2), 8))
 #define MIN_LONG_STRING (MAX_SHORT_STRING + 1)
-
-/* Max string length. */
-#define MAX_LONG_STRING 255
-
-/* This nonsense is required for SPSS compatibility */
-#define EFFECTIVE_LONG_STRING_LENGTH (MAX_LONG_STRING - 3)
-
-#define MAX_VERY_LONG_STRING 32767
-
-#define MAX_STRING MAX_VERY_LONG_STRING
-
+#define MAX_STRING 32767
 
 /* Special values. */
 #define SYSMIS (-DBL_MAX)
@@ -55,14 +46,8 @@ union value
     char s[MAX_SHORT_STRING];
   };
 
-/* Maximum number of `union value's in a single number or string
-   value. */
-#define MAX_ELEMS_PER_VALUE (MAX_STRING / sizeof (union value) + 1)
-
-int compare_values (const union value *a, const union value *b, int width);
-
-unsigned  hash_value(const union value  *v, int width);
-
-
+union value *value_dup (const union value *, int width);
+int compare_values (const union value *, const union value *, int width);
+unsigned hash_value (const union value  *, int width);
 
 #endif /* !value.h */
Index: src/data/vardict.h
===================================================================
RCS file: src/data/vardict.h
diff -N src/data/vardict.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/vardict.h	10 Dec 2006 03:30:20 -0000
@@ -0,0 +1,39 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#ifndef DATA_VARDICT_H
+#define DATA_VARDICT_H 1
+
+/* Interface between dictionary and variable code.
+   This header file should only be included by variable.c and
+   dictionary.c. */
+
+/* Dictionary data stored in variable. */
+struct vardict_info 
+  {
+    int dict_index;     /* Dictionary index containing the variable. */
+    int case_index;     /* Index into case of variable data. */
+  };
+
+const struct vardict_info *var_get_vardict (const struct variable *);
+void var_set_vardict (struct variable *, const struct vardict_info *);
+bool var_has_vardict (const struct variable *);
+void var_clear_vardict (struct variable *);
+
+#endif /* data/vardict.h */
Index: src/data/variable.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/variable.c,v
retrieving revision 1.15
diff -u -p -r1.15 variable.c
--- src/data/variable.c	7 Dec 2006 06:31:04 -0000	1.15
+++ src/data/variable.c	10 Dec 2006 03:30:21 -0000
@@ -19,150 +19,178 @@
 
 #include <config.h>
 #include "variable.h"
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
+
 #include <stdlib.h>
+
+#include "cat-routines.h"
+#include "category.h"
+#include "data-out.h"
+#include "dictionary.h"
+#include "format.h"
+#include "identifier.h"
+#include "missing-values.h"
+#include "value.h"
+#include "value-labels.h"
+#include "vardict.h"
+
 #include <libpspp/alloc.h>
+#include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
-#include "dictionary.h"
 #include <libpspp/hash.h>
-#include "identifier.h"
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
-#include "value-labels.h"
 
 #include "minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+/* A variable. */
+struct variable
+  {
+    /* Dictionary information. */
+    char name[LONG_NAME_LEN + 1]; /* Variable name.  Mixed case. */
+    int width;			/* 0 for numeric, otherwise string width. */
+    struct missing_values miss; /* Missing values. */
+    struct fmt_spec print;	/* Default format for PRINT. */
+    struct fmt_spec write;	/* Default format for WRITE. */
+    struct val_labs *val_labs;  /* Value labels. */
+    char *label;		/* Variable label. */
+
+    /* GUI information. */
+    enum measure measure;       /* Nominal, ordinal, or continuous. */
+    int display_width;          /* Width of data editor column. */
+    enum alignment alignment;   /* Alignment of data in GUI. */
+
+    /* Case information. */
+    bool leave;                 /* Leave value from case to case? */
+
+    /* Data for use by containing dictionary. */
+    struct vardict_info vardict;    
+
+    /* Short name, used only for system and portable file input
+       and output.  Upper case only.  There is no index for short
+       names.  Short names are not necessarily unique.  Any
+       variable may have no short name, indicated by an empty
+       string. */
+    char short_name[SHORT_NAME_LEN + 1];
+
+    /* Each command may use these fields as needed. */
+    void *aux;
+    void (*aux_dtor) (struct variable *);
+
+    /* Values of a categorical variable.  Procedures need
+       vectors with binary entries, so any variable of type ALPHA will
+       have its values stored here. */
+    struct cat_vals *obs_vals;
+  };
+
 /* Returns true if VAR_TYPE is a valid variable type. */
 bool
 var_type_is_valid (enum var_type var_type) 
 {
-  return var_type == NUMERIC || var_type == ALPHA;
-}
-
-/* Returns an adjective describing the given variable TYPE,
-   suitable for use in phrases like "numeric variable". */
-const char *
-var_type_adj (enum var_type type) 
-{
-  return type == NUMERIC ? _("numeric") : _("string");
+  return var_type == VAR_NUMERIC || var_type == VAR_STRING;
 }
 
-/* Returns a noun describing a value of the given variable TYPE,
-   suitable for use in phrases like "a number". */
-const char *
-var_type_noun (enum var_type type) 
-{
-  return type == NUMERIC ? _("number") : _("string");
-}
-
-/* Returns true if M is a valid variable measurement level,
-   false otherwise. */
-bool
-measure_is_valid (enum measure m)
-{
-  return m == MEASURE_NOMINAL || m == MEASURE_ORDINAL || m == MEASURE_SCALE;
-}
-
-/* Returns true if A is a valid alignment,
-   false otherwise. */
-bool
-alignment_is_valid (enum alignment a)
+/* Returns the variable type for the given width. */
+enum var_type
+var_type_from_width (int width) 
 {
-  return a == ALIGN_LEFT || a == ALIGN_RIGHT || a == ALIGN_CENTRE;
+  return width != 0 ? VAR_STRING : VAR_NUMERIC;
 }
 
-/* Assign auxiliary data AUX to variable V, which must not
-   already have auxiliary data.  Before V's auxiliary data is
-   cleared, AUX_DTOR(V) will be called. */
-void *
-var_attach_aux (struct variable *v,
-                void *aux, void (*aux_dtor) (struct variable *)) 
+/* Creates and returns a new variable with the given NAME and
+   WIDTH and other fields initialized to default values.  The
+   variable is not added to a dictionary; for that, use
+   dict_create_var instead. */
+struct variable *
+var_create (const char *name, int width) 
 {
-  assert (v->aux == NULL);
-  assert (aux != NULL);
-  v->aux = aux;
-  v->aux_dtor = aux_dtor;
-  return aux;
-}
-
-/* Remove auxiliary data, if any, from V, and returns it, without
-   calling any associated destructor. */
-void *
-var_detach_aux (struct variable *v) 
-{
-  void *aux = v->aux;
-  assert (aux != NULL);
-  v->aux = NULL;
-  return aux;
-}
+  struct variable *v;
+  
+  assert (width >= 0 && width <= MAX_STRING);
 
-/* Clears auxiliary data, if any, from V, and calls any
-   associated destructor. */
-void
-var_clear_aux (struct variable *v) 
-{
-  assert (v != NULL);
-  if (v->aux != NULL) 
+  v = xmalloc (sizeof *v);
+  v->vardict.dict_index = v->vardict.case_index = -1;
+  var_set_name (v, name);
+  v->width = width;
+  mv_init (&v->miss, width);
+  v->leave = var_must_leave (v);
+  if (var_is_numeric (v))
+    {
+      v->print = fmt_for_output (FMT_F, 8, 2);
+      v->alignment = ALIGN_RIGHT;
+      v->display_width = 8;
+      v->measure = MEASURE_SCALE;
+    }
+  else
     {
-      if (v->aux_dtor != NULL)
-        v->aux_dtor (v);
-      v->aux = NULL;
+      v->print = fmt_for_output (FMT_A, var_get_width (v), 0);
+      v->alignment = ALIGN_LEFT;
+      v->display_width = 8;
+      v->measure = MEASURE_NOMINAL;
     }
-}
-
-/* This function is appropriate for use an auxiliary data
-   destructor (passed as AUX_DTOR to var_attach_aux()) for the
-   case where the auxiliary data should be passed to free(). */
-void
-var_dtor_free (struct variable *v) 
-{
-  free (v->aux);
-}
-
-/* Duplicate a value.
-   The caller is responsible for freeing the returned value
-*/
-union value *
-value_dup (const union value *val, int width)
-{
-  size_t bytes = MAX(width, sizeof *val);
+  v->write = v->print;
+  v->val_labs = NULL;
+  v->label = NULL;
+  var_clear_short_name (v);
+  v->aux = NULL;
+  v->aux_dtor = NULL;
+  v->obs_vals = NULL;
 
-  union value *v = xmalloc (bytes);
-  memcpy (v, val, bytes);
   return v;
 }
 
+/* Creates and returns a clone of OLD_VAR.  Most properties of
+   the new variable are copied from OLD_VAR, except:
 
-
-/* Compares A and B, which both have the given WIDTH, and returns
-   a strcmp()-type result. */
-int
-compare_values (const union value *a, const union value *b, int width) 
-{
-  if (width == 0) 
-    return a->f < b->f ? -1 : a->f > b->f;
-  else
-    return memcmp (a->s, b->s, MIN(MAX_SHORT_STRING, width));
-}
-
-/* Create a hash of v */
-unsigned 
-hash_value(const union value  *v, int width)
-{
-  unsigned id_hash;
-
-  if ( 0 == width ) 
-    id_hash = hsh_hash_double (v->f);
-  else
-    id_hash = hsh_hash_bytes (v->s, MIN(MAX_SHORT_STRING, width));
-
-  return id_hash;
+    - The variable's short name is not copied, because there is
+      no reason to give a new variable with potentially a new
+      name the same short name.
+
+    - The new variable is not added to OLD_VAR's dictionary by
+      default.  Use dict_clone_var, instead, to do that.
+
+    - Auxiliary data and obs_vals are not copied. */
+struct variable *
+var_clone (const struct variable *old_var)
+{
+  struct variable *new_var = var_create (var_get_name (old_var),
+                                         var_get_width (old_var));
+
+  var_set_missing_values (new_var, var_get_missing_values (old_var));
+  var_set_print_format (new_var, var_get_print_format (old_var));
+  var_set_write_format (new_var, var_get_write_format (old_var));
+  var_set_value_labels (new_var, var_get_value_labels (old_var));
+  var_set_label (new_var, var_get_label (old_var));
+  var_set_measure (new_var, var_get_measure (old_var));
+  var_set_display_width (new_var, var_get_display_width (old_var));
+  var_set_alignment (new_var, var_get_alignment (old_var));
+  var_set_leave (new_var, var_get_leave (old_var));
+
+  return new_var;
+}
+
+/* Destroys variable V.
+   V must not belong to a dictionary.  If it does, use
+   dict_delete_var instead. */
+void
+var_destroy (struct variable *v) 
+{
+  if (v != NULL) 
+    {
+      assert (!var_has_vardict (v));
+      cat_stored_values_destroy (v->obs_vals);
+      var_clear_aux (v);
+      val_labs_destroy (v->val_labs);
+      var_clear_label (v);
+      free (v); 
+    }
 }
 
+/* Variable names. */
+
 /* Return variable V's name. */
 const char *
 var_get_name (const struct variable *v) 
@@ -170,12 +198,14 @@ var_get_name (const struct variable *v) 
   return v->name;
 }
 
-/* Sets V's name to NAME. */
+/* Sets V's name to NAME.
+   Do not use this function for a variable in a dictionary.  Use
+   dict_rename_var instead. */
 void
 var_set_name (struct variable *v, const char *name) 
 {
-  assert (name[0] != '\0');
-  assert (lex_id_to_token (ss_cstr (name)) == T_ID);
+  assert (v->vardict.dict_index == -1);
+  assert (var_is_plausible_name (name, false));
 
   str_copy_trunc (v->name, sizeof v->name, name);
 }
@@ -226,8 +256,7 @@ var_is_valid_name (const char *name, boo
   return true;
 }
 
-/* 
-   Returns true if NAME is an plausible name for a variable,
+/* Returns true if NAME is an plausible name for a variable,
    false otherwise.  If ISSUE_ERROR is true, issues an
    explanatory error message on failure. 
    This function makes no use of LC_CTYPE.
@@ -270,27 +299,28 @@ var_is_plausible_name (const char *name,
 /* A hsh_compare_func that orders variables A and B by their
    names. */
 int
-compare_var_names (const void *a_, const void *b_, const void *aux UNUSED) 
+compare_vars_by_name (const void *a_, const void *b_, const void *aux UNUSED) 
 {
   const struct variable *a = a_;
   const struct variable *b = b_;
 
-  return strcasecmp (var_get_name (a), var_get_name (b));
+  return strcasecmp (a->name, b->name);
 }
 
 /* A hsh_hash_func that hashes variable V based on its name. */
 unsigned
-hash_var_name (const void *v_, const void *aux UNUSED) 
+hash_var_by_name (const void *v_, const void *aux UNUSED) 
 {
   const struct variable *v = v_;
 
-  return hsh_hash_case_string (var_get_name (v));
+  return hsh_hash_case_string (v->name);
 }
 
 /* A hsh_compare_func that orders pointers to variables A and B
    by their names. */
 int
-compare_var_ptr_names (const void *a_, const void *b_, const void *aux UNUSED) 
+compare_var_ptrs_by_name (const void *a_, const void *b_,
+                          const void *aux UNUSED) 
 {
   struct variable *const *a = a_;
   struct variable *const *b = b_;
@@ -301,25 +331,18 @@ compare_var_ptr_names (const void *a_, c
 /* A hsh_hash_func that hashes pointer to variable V based on its
    name. */
 unsigned
-hash_var_ptr_name (const void *v_, const void *aux UNUSED) 
+hash_var_ptr_by_name (const void *v_, const void *aux UNUSED) 
 {
   struct variable *const *v = v_;
 
   return hsh_hash_case_string (var_get_name (*v));
 }
 
-/* Returns the type of a variable with the given WIDTH. */
-static enum var_type
-width_to_type (int width) 
-{
-  return width == 0 ? NUMERIC : ALPHA;
-}
-
 /* Returns the type of variable V. */
 enum var_type
 var_get_type (const struct variable *v) 
 {
-  return width_to_type (v->width);
+  return var_type_from_width (v->width);
 }
 
 /* Returns the width of variable V. */
@@ -333,7 +356,7 @@ var_get_width (const struct variable *v)
 void
 var_set_width (struct variable *v, int new_width) 
 {
-  enum var_type new_type = width_to_type (new_width);
+  enum var_type new_type = var_type_from_width (new_width);
   
   if (mv_is_resizable (&v->miss, new_width))
     mv_resize (&v->miss, new_width);
@@ -353,12 +376,12 @@ var_set_width (struct variable *v, int n
   
   if (var_get_type (v) != new_type) 
     {
-      v->print = (new_type == NUMERIC
+      v->print = (new_type == VAR_NUMERIC
                   ? fmt_for_output (FMT_F, 8, 2)
                   : fmt_for_output (FMT_A, new_width, 0));
       v->write = v->print;
     }
-  else if (new_type == ALPHA) 
+  else if (new_type == VAR_STRING) 
     {
       v->print.w = v->print.type == FMT_AHEX ? new_width * 2 : new_width;
       v->write.w = v->write.type == FMT_AHEX ? new_width * 2 : new_width;
@@ -371,7 +394,7 @@ var_set_width (struct variable *v, int n
 bool
 var_is_numeric (const struct variable *v) 
 {
-  return var_get_type (v) == NUMERIC;
+  return var_get_type (v) == VAR_NUMERIC;
 }
 
 /* Returns true if variable V is a string variable, false
@@ -379,7 +402,7 @@ var_is_numeric (const struct variable *v
 bool
 var_is_alpha (const struct variable *v) 
 {
-  return var_get_type (v) == ALPHA;
+  return var_get_type (v) == VAR_STRING;
 }
 
 /* Returns true if variable V is a short string variable, false
@@ -398,14 +421,14 @@ var_is_long_string (const struct variabl
   return v->width > MAX_SHORT_STRING;
 }
 
-/* Returns true if variable V is a very long string variable,
-   false otherwise. */
-bool
-var_is_very_long_string (const struct variable *v) 
+/* Returns the number of "union value"s need to store a value of
+   variable V. */
+size_t
+var_get_value_cnt (const struct variable *v) 
 {
-  return v->width > MAX_LONG_STRING;
+  return v->width == 0 ? 1 : DIV_RND_UP (v->width, MAX_SHORT_STRING);
 }
-
+
 /* Returns variable V's missing values. */
 const struct missing_values *
 var_get_missing_values (const struct variable *v) 
@@ -413,15 +436,18 @@ var_get_missing_values (const struct var
   return &v->miss;
 }
 
-/* Sets variable V's missing values to MISS, which must be of the
-   correct width. */
+/* Sets variable V's missing values to MISS, which must be of V's
+   width or at least resizable to V's width.
+   If MISS is null, then V's missing values, if any, are
+   cleared. */
 void
 var_set_missing_values (struct variable *v, const struct missing_values *miss)
 {
   if (miss != NULL) 
     {
-      assert (v->width == mv_get_width (miss));
+      assert (mv_is_resizable (miss, v->width));
       mv_copy (&v->miss, miss);
+      mv_resize (&v->miss, v->width);
     }
   else
     mv_init (&v->miss, v->width);
@@ -502,6 +528,104 @@ var_is_value_system_missing (const struc
   return mv_is_value_system_missing (&v->miss, value);
 }
 
+/* Returns variable V's value labels,
+   possibly a null pointer if it has none. */
+const struct val_labs *
+var_get_value_labels (const struct variable *v) 
+{
+  return v->val_labs;
+}
+
+/* Returns true if variable V has at least one value label. */
+bool
+var_has_value_labels (const struct variable *v) 
+{
+  return val_labs_count (v->val_labs) > 0;
+}
+
+/* Sets variable V's value labels to a copy of VLS,
+   which must have a width equal to V's width or one that can be
+   changed to V's width.
+   If VLS is null, then V's value labels, if any, are removed. */
+void
+var_set_value_labels (struct variable *v, const struct val_labs *vls) 
+{
+  val_labs_destroy (v->val_labs);
+  v->val_labs = NULL;
+
+  if (vls != NULL)
+    {
+      assert (val_labs_can_set_width (vls, v->width));
+      v->val_labs = val_labs_copy (vls);
+      val_labs_set_width (v->val_labs, v->width);
+    }
+}
+
+/* Makes sure that V has a set of value labels,
+   by assigning one to it if necessary. */
+static void
+alloc_value_labels (struct variable *v) 
+{
+  assert (!var_is_long_string (v));
+  if (v->val_labs == NULL)
+    v->val_labs = val_labs_create (v->width);
+}
+
+/* Attempts to add a value label with the given VALUE and LABEL
+   to V.  Returns true if successful, false if VALUE has an
+   existing label.
+   V must not be a long string variable. */
+bool
+var_add_value_label (struct variable *v,
+                     const union value *value, const char *label) 
+{
+  alloc_value_labels (v);
+  return val_labs_add (v->val_labs, *value, label);
+}
+
+/* Adds or replaces a value label with the given VALUE and LABEL
+   to V.
+   V must not be a long string variable. */
+void
+var_replace_value_label (struct variable *v,
+                         const union value *value, const char *label)
+{
+  alloc_value_labels (v);
+  val_labs_replace (v->val_labs, *value, label);
+}
+
+/* Removes V's value labels, if any. */
+void
+var_clear_value_labels (struct variable *v) 
+{
+  var_set_value_labels (v, NULL);
+}
+
+/* Returns the label associated with VALUE for variable V,
+   or a null pointer if none. */
+const char *
+var_lookup_value_label (const struct variable *v, const union value *value) 
+{
+  return val_labs_find (v->val_labs, *value);
+}
+
+/* Get a string representing VALUE for variable V.
+   That is, if VALUE has a label, return that label,
+   otherwise format VALUE and return the formatted string. */
+const char *
+var_get_value_name (const struct variable *v, const union value *value)
+{
+  const char *name = var_lookup_value_label (v, value);
+  if (name == NULL) 
+    {
+      static char buf[MAX_STRING + 1];
+      data_out (value, &v->print, buf);
+      buf[v->print.w] = '\0';
+      name = buf;
+    }
+  return name;
+}
+
 /* Print and write formats. */
 
 /* Returns V's print format specification. */
@@ -548,6 +672,15 @@ var_set_both_formats (struct variable *v
   var_set_write_format (v, format);
 }
 
+/* Return a string representing this variable, in the form most
+   appropriate from a human factors perspective, that is, its
+   variable label if it has one, otherwise its name. */
+const char *
+var_to_string (const struct variable *v)
+{
+  return v->label != NULL ? v->label : v->name;
+}
+
 /* Returns V's variable label, or a null pointer if it has none. */
 const char *
 var_get_label (const struct variable *v) 
@@ -591,6 +724,14 @@ var_has_label (const struct variable *v)
   return v->label != NULL;
 }
 
+/* Returns true if M is a valid variable measurement level,
+   false otherwise. */
+bool
+measure_is_valid (enum measure m)
+{
+  return m == MEASURE_NOMINAL || m == MEASURE_ORDINAL || m == MEASURE_SCALE;
+}
+
 /* Returns V's measurement level. */
 enum measure
 var_get_measure (const struct variable *v) 
@@ -605,7 +746,7 @@ var_set_measure (struct variable *v, enu
   assert (measure_is_valid (measure));
   v->measure = measure;
 }
-
+
 /* Returns V's display width, which applies only to GUIs. */
 int
 var_get_display_width (const struct variable *v) 
@@ -619,6 +760,14 @@ var_set_display_width (struct variable *
 {
   v->display_width = display_width;
 }
+
+/* Returns true if A is a valid alignment,
+   false otherwise. */
+bool
+alignment_is_valid (enum alignment a)
+{
+  return a == ALIGN_LEFT || a == ALIGN_RIGHT || a == ALIGN_CENTRE;
+}
 
 /* Returns V's display alignment, which applies only to GUIs. */
 enum alignment
@@ -635,21 +784,32 @@ var_set_alignment (struct variable *v, e
   v->alignment = alignment;
 }
 
-/* Returns the number of "union value"s need to store a value of
-   variable V. */
-size_t
-var_get_value_cnt (const struct variable *v) 
-{
-  return v->width == 0 ? 1 : DIV_RND_UP (v->width, MAX_SHORT_STRING);
-}
+/* Whether variables' values should be preserved from case to
+   case. */
 
-/* Return whether variable V's values should be preserved from
-   case to case. */
+/* Returns true if variable V's value should be left from case to
+   case, instead of being reset to 0, system-missing, or blanks. */
 bool
 var_get_leave (const struct variable *v) 
 {
   return v->leave;
 }
+
+/* Sets V's leave setting to LEAVE. */
+void
+var_set_leave (struct variable *v, bool leave) 
+{
+  assert (leave || !var_must_leave (v));
+  v->leave = leave;
+}
+
+/* Returns true if V must be left from case to case,
+   false if it can be set either way. */
+bool
+var_must_leave (const struct variable *v) 
+{
+  return dict_class_from_id (v->name) == DC_SCRATCH;
+}
 
 /* Returns V's short name, if it has one, or a null pointer
    otherwise.
@@ -692,59 +852,119 @@ var_clear_short_name (struct variable *v
 
   v->short_name[0] = '\0';
 }
+
+/* Relationship with dictionary. */
 
-/* Sets V's short name to BASE, followed by a suffix of the form
-   _A, _B, _C, ..., _AA, _AB, etc. according to the value of
-   SUFFIX_NUMBER.  Truncates BASE as necessary to fit. */
-void
-var_set_short_name_suffix (struct variable *v, const char *base,
-                           int suffix_number)
-{
-  char suffix[SHORT_NAME_LEN + 1];
-  char short_name[SHORT_NAME_LEN + 1];
-  char *start, *end;
-  int len, ofs;
+/* Returns V's index within its dictionary, the value
+   for which "dict_get_var (dict, index)" will return V.
+   V must be in a dictionary. */
+size_t
+var_get_dict_index (const struct variable *v) 
+{
+  assert (v->vardict.dict_index != -1);
+  return v->vardict.dict_index;
+}
 
-  assert (v != NULL);
-  assert (suffix_number >= 0);
+/* Returns V's index within the case represented by its
+   dictionary, that is, the value for which "case_data_idx (case,
+   index)" will return the data for V in that case.
+   V must be in a dictionary. */
+size_t
+var_get_case_index (const struct variable *v) 
+{
+  assert (v->vardict.case_index != -1);
+  return v->vardict.case_index;
+}
+
+/* Returns V's auxiliary data, or a null pointer if none has been
+   attached. */
+void *
+var_get_aux (const struct variable *v) 
+{
+  return v->aux;
+}
 
-  /* Set base name. */
-  var_set_short_name (v, base);
+/* Assign auxiliary data AUX to variable V, which must not
+   already have auxiliary data.  Before V's auxiliary data is
+   cleared, AUX_DTOR(V) will be called.  (var_dtor_free, below,
+   may be appropriate for use as AUX_DTOR.) */
+void *
+var_attach_aux (struct variable *v,
+                void *aux, void (*aux_dtor) (struct variable *)) 
+{
+  assert (v->aux == NULL);
+  assert (aux != NULL);
+  v->aux = aux;
+  v->aux_dtor = aux_dtor;
+  return aux;
+}
 
-  /* Compose suffix. */
-  start = end = suffix + sizeof suffix - 1;
-  *end = '\0';
-  do 
-    {
-      *--start = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[suffix_number % 26];
-      if (start <= suffix + 1)
-        msg (SE, _("Variable suffix too large."));
-      suffix_number /= 26;
-    }
-  while (suffix_number > 0);
-  *--start = '_';
-
-  /* Append suffix to V's short name. */
-  str_copy_trunc (short_name, sizeof short_name, base);
-  len = end - start;
-  if (len + strlen (short_name) > SHORT_NAME_LEN)
-    ofs = SHORT_NAME_LEN - len;
-  else
-    ofs = strlen (short_name);
-  strcpy (short_name + ofs, start);
+/* Remove auxiliary data, if any, from V, and return it, without
+   calling any associated destructor. */
+void *
+var_detach_aux (struct variable *v) 
+{
+  void *aux = v->aux;
+  assert (aux != NULL);
+  v->aux = NULL;
+  return aux;
+}
+
+/* Clears auxiliary data, if any, from V, and calls any
+   associated destructor. */
+void
+var_clear_aux (struct variable *v) 
+{
+  assert (v != NULL);
+  if (v->aux != NULL) 
+    {
+      if (v->aux_dtor != NULL)
+        v->aux_dtor (v);
+      v->aux = NULL;
+    }
+}
+
+/* This function is appropriate for use an auxiliary data
+   destructor (passed as AUX_DTOR to var_attach_aux()) for the
+   case where the auxiliary data should be passed to free(). */
+void
+var_dtor_free (struct variable *v) 
+{
+  free (v->aux);
+}
+
+/* Observed categorical values. */
 
-  /* Set name. */
-  var_set_short_name (v, short_name);
+/* Returns V's observed categorical values,
+   which V must have. */
+struct cat_vals *
+var_get_obs_vals (const struct variable *v) 
+{
+  assert (v->obs_vals != NULL);
+  return v->obs_vals;
 }
 
+/* Sets V's observed categorical values to CAT_VALS. */
+void
+var_set_obs_vals (struct variable *v, struct cat_vals *cat_vals) 
+{
+  cat_stored_values_destroy (v->obs_vals);
+  v->obs_vals = cat_vals;
+}
 
+/* Returns true if V has observed categorical values,
+   false otherwise. */
+bool
+var_has_obs_vals (const struct variable *v) 
+{
+  return v->obs_vals != NULL;
+}
+
 /* 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]) 
     {
     default:
@@ -772,25 +992,34 @@ dict_class_to_name (enum dict_class dict
       NOT_REACHED ();
     }
 }
-
-/* Return the number of bytes used when writing case_data for a variable 
-   of WIDTH */
-int
-width_to_bytes(int width)
+
+/* Returns V's vardict structure. */
+const struct vardict_info *
+var_get_vardict (const struct variable *v) 
 {
-  assert (width >= 0);
+  assert (var_has_vardict (v));
+  return &v->vardict;
+}
 
-  if ( width == 0 ) 
-    return MAX_SHORT_STRING ;
-  else if (width <= MAX_LONG_STRING) 
-    return ROUND_UP (width, MAX_SHORT_STRING);
-  else 
-    {
-      int chunks = width / EFFECTIVE_LONG_STRING_LENGTH ;
-      int remainder = width % EFFECTIVE_LONG_STRING_LENGTH ;
-      int bytes = remainder + (chunks * (MAX_LONG_STRING + 1) );
-      return ROUND_UP (bytes, MAX_SHORT_STRING); 
-    }
+/* Sets V's vardict data to VARDICT. */
+void
+var_set_vardict (struct variable *v, const struct vardict_info *vardict) 
+{
+  assert (vardict->dict_index >= 0);
+  assert (vardict->case_index >= 0);
+  v->vardict = *vardict;
 }
 
+/* Returns true if V has vardict data. */
+bool
+var_has_vardict (const struct variable *v) 
+{
+  return v->vardict.dict_index != -1;
+}
 
+/* Clears V's vardict data. */
+void
+var_clear_vardict (struct variable *v) 
+{
+  v->vardict.dict_index = v->vardict.case_index = -1;
+}
Index: src/data/variable.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/variable.h,v
retrieving revision 1.15
diff -u -p -r1.15 variable.h
--- src/data/variable.h	7 Dec 2006 06:31:04 -0000	1.15
+++ src/data/variable.h	10 Dec 2006 03:30:21 -0000
@@ -20,101 +20,43 @@
 #if !variable_h
 #define variable_h 1
 
-
 #include <stddef.h>
 #include "config.h"
 #include <stdbool.h>
-#include "category.h"
-#include "format.h"
-#include "missing-values.h"
+
+union value;
 
 /* Variable type. */
 enum var_type
   {
-    NUMERIC,			/* A numeric variable. */
-    ALPHA			/* A string variable. */
+    VAR_NUMERIC,                /* A numeric variable. */
+    VAR_STRING			/* A string variable. */
   };
 
 bool var_type_is_valid (enum var_type);
-const char *var_type_adj (enum var_type);
-const char *var_type_noun (enum var_type);
-
-/* Alignment of data for display. */
-enum alignment 
-  {
-    ALIGN_LEFT = 0,
-    ALIGN_RIGHT = 1,
-    ALIGN_CENTRE = 2,
-    n_ALIGN
-  };
+enum var_type var_type_from_width (int width);
 
-bool alignment_is_valid (enum alignment);
+/* Variables. */
+struct variable *var_create (const char *name, int width);
+struct variable *var_clone (const struct variable *);
+void var_destroy (struct variable *);
+
+/* Variable names.
+   Long variable names can be used in most contexts, but a few
+   procedures and file formats are limited to short names. */
+#define SHORT_NAME_LEN 8
+#define LONG_NAME_LEN 64
 
-/* How data is measured. */
-enum measure
-  {
-    MEASURE_NOMINAL = 1,
-    MEASURE_ORDINAL = 2,
-    MEASURE_SCALE = 3,
-    n_MEASURES
-  };
-
-bool measure_is_valid (enum measure);
-
-/* Maximum lengths of short and long variable names.
-   Most operations support long variable names,
-   but some file formats are limited to short names. */
-#define SHORT_NAME_LEN 8        /* Short name length. */
-#define LONG_NAME_LEN 64        /* Long name length. */
-
-/* A variable's dictionary entry.  */
-struct variable
-  {
-    /* Dictionary information. */
-    char name[LONG_NAME_LEN + 1]; /* Variable name.  Mixed case. */
-    int width;			/* 0 for numeric, otherwise string width. */
-    struct missing_values miss; /* Missing values. */
-    struct fmt_spec print;	/* Default format for PRINT. */
-    struct fmt_spec write;	/* Default format for WRITE. */
-    struct val_labs *val_labs;  /* Value labels. */
-    char *label;		/* Variable label. */
-
-    /* GUI information. */
-    enum measure measure;       /* Nominal, ordinal, or continuous. */
-    int display_width;          /* Width of data editor column. */
-    enum alignment alignment;   /* Alignment of data in GUI. */
-
-    /* Case information. */
-    int fv;			/* Index into `value's. */
-    bool leave;                 /* Leave value from case to case? */
-
-    /* Data for use by containing dictionary. */
-    int index;			/* Dictionary index. */
-
-    /* Short name, used only for system and portable file input
-       and output.  Upper case only.  There is no index for short
-       names.  Short names are not necessarily unique.  Any
-       variable may have no short name, indicated by an empty
-       string. */
-    char short_name[SHORT_NAME_LEN + 1];
-
-    /* Each command may use these fields as needed. */
-    void *aux;
-    void (*aux_dtor) (struct variable *);
-
-    /* Values of a categorical variable.  Procedures need
-       vectors with binary entries, so any variable of type ALPHA will
-       have its values stored here. */
-    struct cat_vals *obs_vals;
-  };
-
-/* Variable names. */
 const char *var_get_name (const struct variable *);
 void var_set_name (struct variable *, const char *);
 bool var_is_valid_name (const char *, bool issue_error);
 bool var_is_plausible_name (const char *name, bool issue_error);
-int  compare_var_names (const void *, const void *, const void *);
-unsigned hash_var_name (const void *, const void *);
+
+int compare_vars_by_name (const void *, const void *, const void *);
+unsigned hash_var_by_name (const void *, const void *);
+
+int compare_var_ptrs_by_name (const void *, const void *, const void *);
+unsigned hash_var_ptr_by_name (const void *, const void *);
 
 /* Variable types and widths. */
 enum var_type var_get_type (const struct variable *);
@@ -124,7 +66,7 @@ bool var_is_numeric (const struct variab
 bool var_is_alpha (const struct variable *);
 bool var_is_short_string (const struct variable *);
 bool var_is_long_string (const struct variable *);
-bool var_is_very_long_string (const struct variable *);
+size_t var_get_value_cnt (const struct variable *);
 
 /* Variables' missing values. */
 const struct missing_values *var_get_missing_values (const struct variable *);
@@ -144,6 +86,19 @@ bool var_is_str_user_missing (const stru
 bool var_is_value_system_missing (const struct variable *,
                                   const union value *);
 
+/* Value labels. */
+const struct val_labs *var_get_value_labels (const struct variable *);
+bool var_has_value_labels (const struct variable *);
+void var_set_value_labels (struct variable *, const struct val_labs *);
+bool var_add_value_label (struct variable *,
+                          const union value *, const char *);
+void var_replace_value_label (struct variable *,
+                              const union value *, const char *);
+void var_clear_value_labels (struct variable *);
+const char *var_lookup_value_label (const struct variable *,
+                                    const union value *);
+const char *var_get_value_name (const struct variable *, const union value *);
+
 /* Print and write formats. */
 const struct fmt_spec *var_get_print_format (const struct variable *);
 void var_set_print_format (struct variable *, const struct fmt_spec *);
@@ -152,45 +107,70 @@ void var_set_write_format (struct variab
 void var_set_both_formats (struct variable *, const struct fmt_spec *);
 
 /* Variable labels. */
+const char *var_to_string (const struct variable *);
 const char *var_get_label (const struct variable *);
 void var_set_label (struct variable *, const char *);
 void var_clear_label (struct variable *);
 bool var_has_label (const struct variable *);
 
-/* GUI information. */
+/* How data is measured. */
+enum measure
+  {
+    MEASURE_NOMINAL = 1,
+    MEASURE_ORDINAL = 2,
+    MEASURE_SCALE = 3,
+    n_MEASURES
+  };
+
+bool measure_is_valid (enum measure);
 enum measure var_get_measure (const struct variable *);
 void var_set_measure (struct variable *, enum measure);
 
+/* GUI display width. */
 int var_get_display_width (const struct variable *);
 void var_set_display_width (struct variable *, int display_width);
 
+/* Alignment of data for display. */
+enum alignment 
+  {
+    ALIGN_LEFT = 0,
+    ALIGN_RIGHT = 1,
+    ALIGN_CENTRE = 2,
+    n_ALIGN
+  };
+
+bool alignment_is_valid (enum alignment);
 enum alignment var_get_alignment (const struct variable *);
 void var_set_alignment (struct variable *, enum alignment);
 
-/* Variable location in cases. */
-size_t var_get_value_cnt (const struct variable *);
-
 /* Whether variables' values should be preserved from case to
    case. */
 bool var_get_leave (const struct variable *);
+void var_set_leave (struct variable *, bool leave);
+bool var_must_leave (const struct variable *);
 
 /* Short names. */
 const char *var_get_short_name (const struct variable *);
 void var_set_short_name (struct variable *, const char *);
-void var_set_short_name_suffix (struct variable *, const char *, int suffix);
 void var_clear_short_name (struct variable *);
 
-/* Pointers to `struct variable', by name. */
-int compare_var_ptr_names (const void *, const void *, const void *);
-unsigned hash_var_ptr_name (const void *, const void *);
+/* Relationship with dictionary. */
+size_t var_get_dict_index (const struct variable *);
+size_t var_get_case_index (const struct variable *);
 
 /* Variable auxiliary data. */
+void *var_get_aux (const struct variable *);
 void *var_attach_aux (struct variable *,
                       void *aux, void (*aux_dtor) (struct variable *));
 void var_clear_aux (struct variable *);
 void *var_detach_aux (struct variable *);
 void var_dtor_free (struct variable *);
 
+/* Observed categorical values. */
+struct cat_vals *var_get_obs_vals (const struct variable *);
+void var_set_obs_vals (struct variable *, struct cat_vals *);
+bool var_has_obs_vals (const struct variable *);
+
 /* Classes of variables. */
 enum dict_class 
   {
@@ -201,27 +181,5 @@ enum dict_class 
 
 enum dict_class dict_class_from_id (const char *name);
 const char *dict_class_to_name (enum dict_class dict_class);
-
-/* Vector of variables. */
-struct vector
-  {
-    int idx;                    /* Index for dict_get_vector(). */
-    char name[LONG_NAME_LEN + 1]; /* Name. */
-    struct variable **var;	/* Vector of variables. */
-    int cnt;			/* Number of variables. */
-  };
-
-
-/* Return a string representing this variable, in the form most 
-   appropriate from a human factors perspective.
-   (IE: the label if it has one, otherwise the name )
-*/
-const char * var_to_string(const struct variable *var);
-
-
-int width_to_bytes(int width);
-
-union value * value_dup (const union value *val, int width);
-
 
 #endif /* !variable.h */
Index: src/data/vector.c
===================================================================
RCS file: src/data/vector.c
diff -N src/data/vector.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/vector.c	10 Dec 2006 03:30:21 -0000
@@ -0,0 +1,146 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+#include "vector.h"
+
+#include "dictionary.h"
+
+#include <libpspp/assertion.h>
+#include <libpspp/str.h>
+
+#include "xalloc.h"
+
+/* Vector of variables. */
+struct vector
+  {
+    char name[LONG_NAME_LEN + 1];       /* Name. */
+    struct variable **vars;             /* Set of variables. */
+    size_t var_cnt;                     /* Number of variables. */
+  };
+
+/* Checks that all the variables in VECTOR have consistent
+   width. */
+static void
+check_widths (const struct vector *vector) 
+{
+  int width = var_get_width (vector->vars[0]);
+  size_t i;
+  
+  for (i = 1; i < vector->var_cnt; i++)
+    assert (width == var_get_width (vector->vars[i]));
+}
+
+/* Creates and returns a new vector with the given NAME
+   that contains the VAR_CNT variables in VARS.
+   All variables in VARS must have the same type and width. */
+struct vector *
+vector_create (const char *name,
+               struct variable **vars, size_t var_cnt) 
+{
+  struct vector *vector = xmalloc (sizeof *vector);
+
+  assert (var_cnt > 0);
+  assert (var_is_plausible_name (name, false));
+  str_copy_trunc (vector->name, sizeof vector->name, name);
+
+  vector->vars = xmemdup (vars, var_cnt * sizeof *vector->vars);
+  vector->var_cnt = var_cnt;
+  check_widths (vector);
+
+  return vector;
+}
+
+/* Creates and returns a new vector as a clone of OLD, but that
+   contains variables from NEW_DICT that are in the same position
+   as those in OLD are in OLD_DICT. 
+   All variables in the new vector must have the same type and
+   width. */
+struct vector *
+vector_clone (const struct vector *old,
+              const struct dictionary *old_dict,
+              const struct dictionary *new_dict) 
+{
+  struct vector *new = xmalloc (sizeof *new);
+  size_t i;
+  
+  strcpy (new->name, old->name);
+
+  new->vars = xnmalloc (old->var_cnt, sizeof *new->vars);
+  new->var_cnt = old->var_cnt;
+  for (i = 0; i < new->var_cnt; i++) 
+    {
+      assert (dict_contains_var (old_dict, old->vars[i]));
+      new->vars[i] = dict_get_var (new_dict,
+                                   var_get_dict_index (old->vars[i]));
+    }
+  check_widths (new);
+  
+  return new;
+}
+
+/* Destroys VECTOR. */
+void
+vector_destroy (struct vector *vector) 
+{
+  free (vector->vars);
+  free (vector);
+}
+
+/* Returns VECTOR's name. */
+const char *
+vector_get_name (const struct vector *vector) 
+{
+  return vector->name;
+}
+
+/* Returns the type of the variables in VECTOR. */
+enum var_type vector_get_type (const struct vector *vector) 
+{
+  return var_get_type (vector->vars[0]);
+}
+
+/* Returns the variable in VECTOR with the given INDEX. */
+struct variable *
+vector_get_var (const struct vector *vector, size_t index) 
+{
+  assert (index < vector->var_cnt);
+  return vector->vars[index];
+}
+
+/* Returns the number of variables in VECTOR. */
+size_t
+vector_get_var_cnt (const struct vector *vector) 
+{
+  return vector->var_cnt;
+}
+
+/* Compares two pointers to vectors represented by A and B and
+   returns a strcmp()-type result. */
+int
+compare_vector_ptrs_by_name (const void *a_, const void *b_)
+{
+  struct vector *const *pa = a_;
+  struct vector *const *pb = b_;
+  struct vector *a = *pa;
+  struct vector *b = *pb;
+  
+  return strcasecmp (a->name, b->name);
+}
+
Index: src/data/vector.h
===================================================================
RCS file: src/data/vector.h
diff -N src/data/vector.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/data/vector.h	10 Dec 2006 03:30:21 -0000
@@ -0,0 +1,42 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#ifndef DATA_VECTOR_H 
+#define DATA_VECTOR_H 1
+
+#include <stddef.h>
+#include <data/variable.h>
+
+struct dictionary;
+
+struct vector *vector_create (const char *name,
+                              struct variable **var, size_t var_cnt);
+struct vector *vector_clone (const struct vector *old,
+                             const struct dictionary *old_dict,
+                             const struct dictionary *new_dict);
+void vector_destroy (struct vector *);
+
+const char *vector_get_name (const struct vector *);
+enum var_type vector_get_type (const struct vector *);
+struct variable *vector_get_var (const struct vector *, size_t idx);
+size_t vector_get_var_cnt (const struct vector *);
+
+int compare_vector_ptrs_by_name (const void *a_, const void *b_);
+
+#endif /* data/vector.h */
Index: src/language/control/do-if.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/control/do-if.c,v
retrieving revision 1.10
diff -u -p -r1.10 do-if.c
--- src/language/control/do-if.c	11 Nov 2006 23:10:00 -0000	1.10
+++ src/language/control/do-if.c	10 Dec 2006 03:30:21 -0000
@@ -24,7 +24,7 @@
 #include "control-stack.h"
 #include <data/procedure.h>
 #include <data/transformations.h>
-#include <data/variable.h>
+#include <data/value.h>
 #include <language/command.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
Index: src/language/control/loop.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/control/loop.c,v
retrieving revision 1.11
diff -u -p -r1.11 loop.c
--- src/language/control/loop.c	11 Nov 2006 23:10:00 -0000	1.11
+++ src/language/control/loop.c	10 Dec 2006 03:30:22 -0000
@@ -294,7 +294,7 @@ loop_trns_proc (void *loop_, struct ccas
 
       /* Even if the loop is never entered, set the index
          variable to the initial value. */
-      case_data_rw (c, loop->index_var->fv)->f = loop->cur;
+      case_data_rw (c, loop->index_var)->f = loop->cur;
 
       /* Throw out pathological cases. */
       if (!finite (loop->cur) || !finite (loop->by) || !finite (loop->last)
@@ -355,7 +355,7 @@ end_loop_trns_proc (void *loop_, struct 
       if ((loop->by > 0.0 && loop->cur > loop->last)
           || (loop->by < 0.0 && loop->cur < loop->last))
         goto break_out;
-      case_data_rw (c, loop->index_var->fv)->f = loop->cur;
+      case_data_rw (c, loop->index_var)->f = loop->cur;
     }
 
   if (loop->loop_condition != NULL
Index: src/language/data-io/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/ChangeLog,v
retrieving revision 1.34
diff -u -p -r1.34 ChangeLog
--- src/language/data-io/ChangeLog	1 Dec 2006 05:52:59 -0000	1.34
+++ src/language/data-io/ChangeLog	10 Dec 2006 03:30:22 -0000
@@ -1,3 +1,7 @@
+Sat Dec  9 18:43:34 2006  Ben Pfaff  <blp@gnu.org>
+
+	* list.q (cmd_list): Use new var_create, var_destroy functions.
+
 Thu Nov 30 21:51:58 2006  Ben Pfaff  <blp@gnu.org>
 
 	* inpt-pgm.c (cmd_reread): Always return error code upon detecting
Index: src/language/data-io/data-list.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/data-list.c,v
retrieving revision 1.27
diff -u -p -r1.27 data-list.c
--- src/language/data-io/data-list.c	5 Dec 2006 15:10:21 -0000	1.27
+++ src/language/data-io/data-list.c	10 Dec 2006 03:30:23 -0000
@@ -370,7 +370,7 @@ parse_fixed (struct lexer *lexer, struct
             /* Create specifier for parsing the variable. */
             spec = pool_alloc (dls->pool, sizeof *spec);
             spec->input = *f;
-            spec->fv = v->fv;
+            spec->fv = var_get_case_index (v);
             spec->record = record;
             spec->first_column = column;
             strcpy (spec->name, var_get_name (v));
@@ -498,7 +498,7 @@ parse_free (struct lexer *lexer, struct 
 
           spec = pool_alloc (dls->pool, sizeof *spec);
           spec->input = input;
-	  spec->fv = v->fv;
+	  spec->fv = var_get_case_index (v);
 	  strcpy (spec->name, var_get_name (v));
           ll_push_tail (&dls->specs, &spec->ll);
 	}
@@ -679,7 +679,7 @@ read_from_data_list_fixed (const struct 
       ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs) 
         data_in (ss_substr (line, spec->first_column - 1, spec->input.w),
                  spec->input.type, spec->input.d, spec->first_column,
-                 case_data_rw (c, spec->fv), fmt_var_width (&spec->input));
+                 case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
 
       dfm_forward_record (dls->reader);
     }
@@ -715,7 +715,7 @@ read_from_data_list_free (const struct d
       
       data_in (field, spec->input.type, 0,
                dfm_get_column (dls->reader, ss_data (field)),
-               case_data_rw (c, spec->fv), fmt_var_width (&spec->input));
+               case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
     }
   return true;
 }
@@ -746,16 +746,16 @@ read_from_data_list_list (const struct d
             {
               int width = fmt_var_width (&spec->input);
               if (width == 0)
-                case_data_rw (c, spec->fv)->f = SYSMIS;
+                case_data_rw_idx (c, spec->fv)->f = SYSMIS;
               else
-                memset (case_data_rw (c, spec->fv)->s, ' ', width); 
+                memset (case_data_rw_idx (c, spec->fv)->s, ' ', width); 
             }
 	  break;
 	}
       
       data_in (field, spec->input.type, 0,
                dfm_get_column (dls->reader, ss_data (field)),
-               case_data_rw (c, spec->fv), fmt_var_width (&spec->input));
+               case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
     }
 
   dfm_forward_record (dls->reader);
@@ -794,7 +794,7 @@ data_list_trns_proc (void *dls_, struct 
   /* If there was an END subcommand handle it. */
   if (dls->end != NULL) 
     {
-      double *end = &case_data_rw (c, dls->end->fv)->f;
+      double *end = &case_data_rw (c, dls->end)->f;
       if (retval == TRNS_DROP_CASE)
         {
           *end = 1.0;
Index: src/language/data-io/get.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/get.c,v
retrieving revision 1.24
diff -u -p -r1.24 get.c
--- src/language/data-io/get.c	7 Dec 2006 05:41:11 -0000	1.24
+++ src/language/data-io/get.c	10 Dec 2006 03:30:24 -0000
@@ -28,6 +28,7 @@
 #include <data/case.h>
 #include <data/casefile.h>
 #include <data/fastfile.h>
+#include <data/format.h>
 #include <data/dictionary.h>
 #include <data/por-file-writer.h>
 #include <data/procedure.h>
@@ -1272,14 +1273,14 @@ mtf_delete_file_in_place (struct mtf_pro
   *file = f->next;
 
   if (f->in_var != NULL)
-    case_data_rw (&mtf->mtf_case, f->in_var->fv)->f = 0.;
+    case_data_rw (&mtf->mtf_case, f->in_var)->f = 0.;
   for (i = 0; i < dict_get_var_cnt (f->dict); i++)
     {
       struct variable *v = dict_get_var (f->dict, i);
       struct variable *mv = get_master (v);
       if (mv != NULL) 
         {
-          union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
+          union value *out = case_data_rw (&mtf->mtf_case, mv);
 	  
           if (var_is_numeric (v))
             out->f = SYSMIS;
@@ -1427,23 +1428,23 @@ mtf_processing (const struct ccase *c, v
 	    {
 	      struct variable *v = dict_get_var (iter->dict, i);
               struct variable *mv = get_master (v);
+              size_t mv_index = mv ? var_get_dict_index (mv) : 0;
 	  
-	      if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
+	      if (mv != NULL && mtf->seq_nums[mv_index] != mtf->seq_num) 
                 {
                   const struct ccase *record
                     = case_is_null (&iter->input) ? c : &iter->input;
-                  union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
+                  union value *out = case_data_rw (&mtf->mtf_case, mv);
 
-                  mtf->seq_nums[mv->index] = mtf->seq_num;
+                  mtf->seq_nums[mv_index] = mtf->seq_num;
                   if (var_is_numeric (v))
-                    out->f = case_num (record, v->fv);
+                    out->f = case_num (record, v);
                   else
-                    memcpy (out->s, case_str (record, v->fv),
-                            var_get_width (v));
+                    memcpy (out->s, case_str (record, v), var_get_width (v));
                 } 
             }
           if (iter->in_var != NULL)
-            case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 1.;
+            case_data_rw (&mtf->mtf_case, iter->in_var)->f = 1.;
 
           if (iter->type == MTF_FILE && iter->handle == NULL)
             read_active_file = true;
@@ -1461,11 +1462,12 @@ mtf_processing (const struct ccase *c, v
 	    {
 	      struct variable *v = dict_get_var (iter->dict, i);
               struct variable *mv = get_master (v);
+              size_t mv_index = mv ? var_get_dict_index (mv) : 0;
 
-	      if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
+	      if (mv != NULL && mtf->seq_nums[mv_index] != mtf->seq_num) 
                 {
-                  union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
-                  mtf->seq_nums[mv->index] = mtf->seq_num;
+                  union value *out = case_data_rw (&mtf->mtf_case, mv);
+                  mtf->seq_nums[mv_index] = mtf->seq_num;
 
                   if (var_is_numeric (v))
                     out->f = SYSMIS;
@@ -1474,7 +1476,7 @@ mtf_processing (const struct ccase *c, v
                 }
             }
           if (iter->in_var != NULL)
-            case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 0.;
+            case_data_rw (&mtf->mtf_case, iter->in_var)->f = 0.;
 	}
 
       /* 5. Write the output record. */
@@ -1552,12 +1554,8 @@ mtf_merge_dictionary (struct dictionary 
         
           if (var_get_width (dv) == var_get_width (mv))
             {
-              if (val_labs_count (dv->val_labs)
-                  && !val_labs_count (mv->val_labs)) 
-                {
-                  val_labs_destroy (mv->val_labs);
-                  mv->val_labs = val_labs_copy (dv->val_labs); 
-                }
+              if (var_has_value_labels (dv) && !var_has_value_labels (mv))
+                var_set_value_labels (mv, var_get_value_labels (dv));
               if (var_has_missing_values (dv) && !var_has_missing_values (mv))
                 var_set_missing_values (mv, var_get_missing_values (dv));
             }
@@ -1584,7 +1582,7 @@ set_master (struct variable *v, struct v
 static struct variable *
 get_master (struct variable *v) 
 {
-  return v->aux;
+  return var_get_aux (v);
 }
 
 /* Case map.
@@ -1619,7 +1617,7 @@ start_case_map (struct dictionary *d) 
     {
       struct variable *v = dict_get_var (d, i);
       int *src_fv = xmalloc (sizeof *src_fv);
-      *src_fv = v->fv;
+      *src_fv = var_get_case_index (v);
       var_attach_aux (v, src_fv, var_dtor_free);
     }
 }
@@ -1654,13 +1652,13 @@ finish_case_map (struct dictionary *d) 
       int *src_fv = (int *) var_detach_aux (v);
       size_t idx;
 
-      if (v->fv != *src_fv)
+      if (var_get_case_index (v) != *src_fv)
         identity_map = 0;
       
       for (idx = 0; idx < value_cnt; idx++)
         {
           int src_idx = *src_fv + idx;
-          int dst_idx = v->fv + idx;
+          int dst_idx = var_get_case_index (v) + idx;
           
           assert (map->map[dst_idx] == -1);
           map->map[dst_idx] = src_idx;
@@ -1696,7 +1694,7 @@ map_case (const struct case_map *map,
     {
       int src_idx = map->map[dst_idx];
       if (src_idx != -1)
-        *case_data_rw (dst, dst_idx) = *case_data (src, src_idx);
+        *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx);
     }
 }
 
Index: src/language/data-io/inpt-pgm.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/inpt-pgm.c,v
retrieving revision 1.19
diff -u -p -r1.19 inpt-pgm.c
--- src/language/data-io/inpt-pgm.c	5 Dec 2006 15:10:21 -0000	1.19
+++ src/language/data-io/inpt-pgm.c	10 Dec 2006 03:30:24 -0000
@@ -169,7 +169,7 @@ cmd_input_program (struct lexer *lexer, 
       value_init |= var_get_leave (var) ? INP_INIT_ONCE : INP_REINIT;
 
       for (j = 0; j < value_cnt; j++)
-        inp->init[j + var->fv] = value_init;
+        inp->init[j + var_get_case_index (var)] = value_init;
     }
   for (i = 0; i < inp->init_cnt; i++)
     assert (inp->init[i] != -1);
@@ -198,14 +198,15 @@ init_case (const struct input_program_pg
     switch (inp->init[i]) 
       {
       case INP_NUMERIC | INP_INIT_ONCE:
-        case_data_rw (c, i)->f = 0.0;
+        case_data_rw_idx (c, i)->f = 0.0;
         break;
       case INP_NUMERIC | INP_REINIT:
-        case_data_rw (c, i)->f = SYSMIS;
+        case_data_rw_idx (c, i)->f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
       case INP_STRING | INP_REINIT:
-        memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
+        memset (case_data_rw_idx (c, i)->s, ' ',
+                sizeof case_data_rw_idx (c, i)->s);
         break;
       default:
         NOT_REACHED ();
@@ -224,12 +225,13 @@ clear_case (const struct input_program_p
       case INP_NUMERIC | INP_INIT_ONCE:
         break;
       case INP_NUMERIC | INP_REINIT:
-        case_data_rw (c, i)->f = SYSMIS;
+        case_data_rw_idx (c, i)->f = SYSMIS;
         break;
       case INP_STRING | INP_INIT_ONCE:
         break;
       case INP_STRING | INP_REINIT:
-        memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
+        memset (case_data_rw_idx (c, i)->s, ' ',
+                sizeof case_data_rw_idx (c, i)->s);
         break;
       default:
         NOT_REACHED ();
Index: src/language/data-io/list.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/list.q,v
retrieving revision 1.22
diff -u -p -r1.22 list.q
--- src/language/data-io/list.q	5 Dec 2006 15:10:21 -0000	1.22
+++ src/language/data-io/list.q	10 Dec 2006 03:30:24 -0000
@@ -134,7 +134,7 @@ write_line (struct outp_driver *d, const
 int
 cmd_list (struct lexer *lexer, struct dataset *ds)
 {
-  struct variable casenum_var;
+  struct variable *casenum_var = NULL;
   bool ok;
 
   if (!parse_list (lexer, ds, &cmd, NULL))
@@ -215,10 +215,8 @@ cmd_list (struct lexer *lexer, struct da
       /* Initialize the case-number variable. */
       int width = cmd.last == LONG_MAX ? 5 : intlog10 (cmd.last);
       struct fmt_spec format = fmt_for_output (FMT_F, width, 0);
-      var_set_name (&casenum_var, "Case#");
-      casenum_var.width = 0;
-      casenum_var.fv = -1;
-      var_set_both_formats (&casenum_var, &format);
+      casenum_var = var_create ("Case#", 0);
+      var_set_both_formats (casenum_var, &format);
 
       /* Add the weight variable at the beginning of the variable list. */
       cmd.n_variables++;
@@ -226,7 +224,7 @@ cmd_list (struct lexer *lexer, struct da
                                    cmd.n_variables, sizeof *cmd.v_variables);
       memmove (&cmd.v_variables[1], &cmd.v_variables[0],
 	       (cmd.n_variables - 1) * sizeof *cmd.v_variables);
-      cmd.v_variables[0] = &casenum_var;
+      cmd.v_variables[0] = casenum_var;
     }
 
   determine_layout ();
@@ -237,6 +235,8 @@ cmd_list (struct lexer *lexer, struct da
 
   clean_up ();
 
+  var_destroy (casenum_var);    
+
   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
@@ -625,7 +625,7 @@ determine_layout (void)
 
 /* Writes case C to output. */
 static bool
-list_cases (const struct ccase *c, void *aux UNUSED, const struct dataset *ds UNUSED)
+list_cases (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
 {
   struct outp_driver *d;
   
@@ -681,9 +681,10 @@ list_cases (const struct ccase *c, void 
 	    if (width > print->w)
               ds_put_char_multiple(&line_buffer, ' ', width - print->w);
 
-            if (fmt_is_string (print->type) || v->fv != -1)
+            if (fmt_is_string (print->type)
+                || dict_contains_var (dataset_dict (ds), v))
 	      {
-                data_out (case_data (c, v->fv), print,
+                data_out (case_data (c, v), print,
                           ds_put_uninit (&line_buffer, print->w));
 	      }
             else 
@@ -719,8 +720,9 @@ list_cases (const struct ccase *c, void 
             const struct fmt_spec *print = var_get_print_format (v);
 	    char buf[256];
 	    
-            if (fmt_is_string (print->type) || v->fv != -1)
-	      data_out (case_data (c, v->fv), print, buf);
+            if (fmt_is_string (print->type)
+                || dict_contains_var (dataset_dict (ds), v))
+	      data_out (case_data (c, v), print, buf);
             else 
               {
                 union value case_idx_value;
Index: src/language/data-io/matrix-data.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/matrix-data.c,v
retrieving revision 1.20
diff -u -p -r1.20 matrix-data.c
--- src/language/data-io/matrix-data.c	5 Dec 2006 15:10:21 -0000	1.20
+++ src/language/data-io/matrix-data.c	10 Dec 2006 03:30:25 -0000
@@ -351,8 +351,7 @@ cmd_matrix_data (struct lexer *lexer, st
 
             for (i = 0; i < split_cnt; i++)
               {
-                struct mxd_var *mv = split[i]->aux;
-                assert (mv != NULL);
+                struct mxd_var *mv = var_get_aux (split[i]);
 		if (mv->var_type != MXD_CONTINUOUS)
 		  {
 		    msg (SE, _("Split variable %s is already another type."),
@@ -385,8 +384,7 @@ cmd_matrix_data (struct lexer *lexer, st
 	    for (i = 0; i < mx->n_factors; i++)
 	      {
                 struct variable *v = mx->factors[i];
-                struct mxd_var *mv = v->aux;
-                assert (mv != NULL);
+                struct mxd_var *mv = var_get_aux (v);
 		if (mv->var_type != MXD_CONTINUOUS)
 		  {
 		    msg (SE, _("Factor variable %s is already another type."),
@@ -606,7 +604,7 @@ cmd_matrix_data (struct lexer *lexer, st
     for (i = 0; i < dict_get_var_cnt (dataset_dict (ds)); i++)
       {
 	struct variable *v = dict_get_var (dataset_dict (ds), i);
-        struct mxd_var *mv = v->aux;
+        struct mxd_var *mv = var_get_aux (v);
 	int type = mv->var_type;
 	
 	assert (type >= 0 && type < MXD_COUNT);
@@ -699,8 +697,8 @@ compare_variables_by_mxd_var_type (const
 {
   struct variable *const *pa = a_;
   struct variable *const *pb = b_;
-  const struct mxd_var *a = (*pa)->aux;
-  const struct mxd_var *b = (*pb)->aux;
+  const struct mxd_var *a = var_get_aux (*pa);
+  const struct mxd_var *b = var_get_aux (*pb);
   
   if (a->var_type != b->var_type)
     return a->var_type > b->var_type ? 1 : -1;
@@ -715,7 +713,7 @@ attach_mxd_aux (struct variable *v, int 
 {
   struct mxd_var *mv;
   
-  assert (v->aux == NULL);
+  assert (var_get_aux (v) == NULL);
   mv = xmalloc (sizeof *mv);
   mv->var_type = var_type;
   mv->sub_type = sub_type;
@@ -1232,7 +1230,7 @@ nr_read_splits (struct nr_aux_data *nr, 
     {
       if (!compare) 
         {
-          struct mxd_var *mv = dict_get_split_vars (nr->dict)[0]->aux;
+          struct mxd_var *mv = var_get_aux (dict_get_split_vars (nr->dict)[0]);
           nr->split_values[0] = ++mv->sub_type; 
         }
       return true;
@@ -1331,11 +1329,11 @@ dump_cell_content (const struct dictiona
   int type = content_type[content];
 
   {
-    buf_copy_str_rpad (case_data_rw (c, mx->rowtype_->fv)->s, 8,
+    buf_copy_str_rpad (case_data_rw (c, mx->rowtype_)->s, 8,
                        content_names[content]);
     
     if (type != 1)
-      memset (case_data_rw (c, mx->varname_->fv)->s, ' ', 8);
+      memset (case_data_rw (c, mx->varname_)->s, ' ', 8);
   }
 
   {
@@ -1348,12 +1346,12 @@ dump_cell_content (const struct dictiona
 
 	for (j = 0; j < mx->n_continuous; j++)
 	  {
-            int fv = dict_get_var (dict, mx->first_continuous + j)->fv;
-            case_data_rw (c, fv)->f = *cp;
+            struct variable *v = dict_get_var (dict, mx->first_continuous + j);
+            case_data_rw (c, v)->f = *cp;
 	    cp++;
 	  }
 	if (type == 1)
-	  buf_copy_str_rpad (case_data_rw (c, mx->varname_->fv)->s, 8,
+	  buf_copy_str_rpad (case_data_rw (c, mx->varname_)->s, 8,
                              var_get_name (
                                dict_get_var (dict, mx->first_continuous + i)));
 	if (!write_case (wc_data))
@@ -1378,7 +1376,7 @@ nr_output_data (struct nr_aux_data *nr, 
     split_cnt = dict_get_split_cnt (nr->dict);
     split = dict_get_split_vars (nr->dict);
     for (i = 0; i < split_cnt; i++)
-      case_data_rw (c, split[i]->fv)->f = nr->split_values[i];
+      case_data_rw (c, split[i])->f = nr->split_values[i];
   }
 
   if (mx->n_factors)
@@ -1391,7 +1389,7 @@ nr_output_data (struct nr_aux_data *nr, 
 	    size_t factor;
 
 	    for (factor = 0; factor < mx->n_factors; factor++)
-              case_data_rw (c, mx->factors[factor]->fv)->f
+              case_data_rw (c, mx->factors[factor])->f
                 = nr->factor_values[factor + cell * mx->n_factors];
 	  }
 	  
@@ -1420,7 +1418,7 @@ nr_output_data (struct nr_aux_data *nr, 
       size_t factor;
 
       for (factor = 0; factor < mx->n_factors; factor++)
-	case_data_rw (c, mx->factors[factor]->fv)->f = SYSMIS;
+	case_data_rw (c, mx->factors[factor])->f = SYSMIS;
     }
     
     for (content = 0; content <= PROX; content++)
@@ -1631,7 +1629,7 @@ wr_output_data (struct wr_aux_data *wr,
     split_cnt = dict_get_split_cnt (wr->dict);
     split = dict_get_split_vars (wr->dict);
     for (i = 0; i < split_cnt; i++)
-      case_data_rw (c, split[i]->fv)->f = wr->split_values[i];
+      case_data_rw (c, split[i])->f = wr->split_values[i];
   }
 
   /* Sort the wr->data list. */
@@ -1665,8 +1663,7 @@ wr_output_data (struct wr_aux_data *wr,
 	  size_t factor;
 
 	  for (factor = 0; factor < mx->n_factors; factor++)
-            case_data_rw (c, mx->factors[factor]->fv)->f
-              = iter->factors[factor];
+            case_data_rw (c, mx->factors[factor])->f = iter->factors[factor];
 	}
 	
 	{
Index: src/language/data-io/print-space.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/print-space.c,v
retrieving revision 1.7
diff -u -p -r1.7 print-space.c
--- src/language/data-io/print-space.c	11 Nov 2006 23:10:00 -0000	1.7
+++ src/language/data-io/print-space.c	10 Dec 2006 03:30:28 -0000
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 
 #include <data/procedure.h>
+#include <data/value.h>
 #include <language/command.h>
 #include <language/data-io/data-writer.h>
 #include <language/data-io/file-handle.h>
Index: src/language/data-io/print.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/print.c,v
retrieving revision 1.21
diff -u -p -r1.21 print.c
--- src/language/data-io/print.c	5 Dec 2006 15:10:21 -0000	1.21
+++ src/language/data-io/print.c	10 Dec 2006 03:30:28 -0000
@@ -460,7 +460,7 @@ print_trns_proc (void *trns_, struct cca
       ds_set_length (&trns->line, spec->first_column, ' ');
       if (spec->type == PRT_VAR)
         {
-          const union value *input = case_data (c, spec->var->fv);
+          const union value *input = case_data (c, spec->var);
           char *output = ds_put_uninit (&trns->line, spec->format.w);
           if (!spec->sysmis_as_spaces || input->f != SYSMIS)
             data_out (input, &spec->format, output);
Index: src/language/dictionary/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/ChangeLog,v
retrieving revision 1.6
diff -u -p -r1.6 ChangeLog
--- src/language/dictionary/ChangeLog	1 Dec 2006 06:06:52 -0000	1.6
+++ src/language/dictionary/ChangeLog	10 Dec 2006 03:30:28 -0000
@@ -1,3 +1,11 @@
+Sat Dec  9 18:44:26 2006  Ben Pfaff  <blp@gnu.org>
+
+	* variable-label.c: Move to src/data/variable.c.
+	
+	* vector.c (cmd_vector): Use PV_SAME_WIDTH in parse_variables
+	call, because string variables in a vector must have the same
+	width.
+
 Thu Nov 30 22:06:21 2006  Ben Pfaff  <blp@gnu.org>
 
 	* value-labels.c (get_label): Allow commas between values and
Index: src/language/dictionary/apply-dictionary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/apply-dictionary.c,v
retrieving revision 1.11
diff -u -p -r1.11 apply-dictionary.c
--- src/language/dictionary/apply-dictionary.c	5 Dec 2006 15:10:21 -0000	1.11
+++ src/language/dictionary/apply-dictionary.c	10 Dec 2006 03:30:28 -0000
@@ -24,6 +24,7 @@
 #include <data/any-reader.h>
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
+#include <data/missing-values.h>
 #include <data/procedure.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
@@ -86,32 +87,27 @@ cmd_apply_dictionary (struct lexer *lexe
             var_set_label (t, label);
         }
       
-      if (val_labs_count (s->val_labs) && var_is_long_string (t))
-	msg (SW, _("Cannot add value labels from source file to "
-		   "long string variable %s."),
-	     var_get_name (s));
-      else if (val_labs_count (s->val_labs))
-	{
-          if (val_labs_can_set_width (s->val_labs, var_get_width (t)))
+      if (var_has_value_labels (s))
+        {
+          if (!var_is_long_string (t))
             {
-              val_labs_destroy (t->val_labs);
-              t->val_labs = s->val_labs;
-              val_labs_set_width (t->val_labs, var_get_width (t));
-              s->val_labs = val_labs_create (var_get_width (s));
+              const struct val_labs *value_labels = var_get_value_labels (s);
+              if (val_labs_can_set_width (value_labels, var_get_width (t)))
+                var_set_value_labels (s, value_labels);
             }
-	}
-
+          else
+            msg (SW, _("Cannot add value labels from source file to "
+                       "long string variable %s."),
+                 var_get_name (s));
+        }
+      
       if (var_has_missing_values (s))
         {
           if (!var_is_long_string (t))
             {
-              struct missing_values miss;
-              mv_copy (&miss, var_get_missing_values (s));
-              if (mv_is_resizable (&miss, var_get_width (t))) 
-                {
-                  mv_resize (&miss, var_get_width (t));
-                  var_set_missing_values (t, &miss);
-                }
+              const struct missing_values *miss = var_get_missing_values (s);
+              if (mv_is_resizable (miss, var_get_width (t))) 
+                var_set_missing_values (t, miss);
             }
           else
             msg (SW, _("Cannot apply missing values from source file to "
Index: src/language/dictionary/formats.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/formats.c,v
retrieving revision 1.14
diff -u -p -r1.14 formats.c
--- src/language/dictionary/formats.c	5 Dec 2006 15:10:21 -0000	1.14
+++ src/language/dictionary/formats.c	10 Dec 2006 03:30:28 -0000
@@ -94,7 +94,7 @@ internal_cmd_formats (struct lexer *lexe
 	}
       if (!parse_format_specifier (lexer, &f)
           || !fmt_check_output (&f)
-          || !fmt_check_type_compat (&f, NUMERIC))
+          || !fmt_check_type_compat (&f, VAR_NUMERIC))
 	goto fail;
 
       if (!lex_match (lexer, ')'))
Index: src/language/dictionary/missing-values.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/missing-values.c,v
retrieving revision 1.13
diff -u -p -r1.13 missing-values.c
--- src/language/dictionary/missing-values.c	5 Dec 2006 15:10:21 -0000	1.13
+++ src/language/dictionary/missing-values.c	10 Dec 2006 03:30:28 -0000
@@ -22,7 +22,9 @@
 #include <stdlib.h>
 
 #include <data/data-in.h>
+#include <data/missing-values.h>
 #include <data/procedure.h>
+#include <data/value.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/lexer/lexer.h>
@@ -133,20 +135,15 @@ cmd_missing_values (struct lexer *lexer,
           
           for (i = 0; i < nv; i++) 
             {
-              if (!mv_is_resizable (&mv, var_get_width (v[i]))) 
+              if (mv_is_resizable (&mv, var_get_width (v[i]))) 
+                var_set_missing_values (v[i], &mv);
+              else 
                 {
                   msg (SE, _("Missing values provided are too long to assign "
                              "to variable of width %d."),
                        var_get_width (v[i]));
                   deferred_errors = true;
                 }
-              else 
-                {
-                  struct missing_values tmp;
-                  mv_copy (&tmp, &mv);
-                  mv_resize (&tmp, var_get_width (v[i]));
-                  var_set_missing_values (v[i], &tmp);
-                }
             }
         }
 
Index: src/language/dictionary/modify-variables.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/modify-variables.c,v
retrieving revision 1.13
diff -u -p -r1.13 modify-variables.c
--- src/language/dictionary/modify-variables.c	5 Dec 2006 15:10:21 -0000	1.13
+++ src/language/dictionary/modify-variables.c	10 Dec 2006 03:30:28 -0000
@@ -354,8 +354,12 @@ compare_variables_given_ordering (const 
   const struct ordering *ordering = ordering_;
 
   int result;
-  if (ordering->positional)
-    result = a->index < b->index ? -1 : a->index > b->index;
+  if (ordering->positional) 
+    {
+      size_t a_index = var_get_dict_index (a);
+      size_t b_index = var_get_dict_index (b);
+      result = a_index < b_index ? -1 : a_index > b_index; 
+    }
   else
     result = strcasecmp (var_get_name (a), var_get_name (b));
   if (!ordering->forward)
Index: src/language/dictionary/numeric.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/numeric.c,v
retrieving revision 1.17
diff -u -p -r1.17 numeric.c
--- src/language/dictionary/numeric.c	5 Dec 2006 15:10:21 -0000	1.17
+++ src/language/dictionary/numeric.c	10 Dec 2006 03:30:28 -0000
@@ -185,7 +185,7 @@ cmd_leave (struct lexer *lexer, struct d
   if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
     return CMD_CASCADING_FAILURE;
   for (i = 0; i < nv; i++)
-    v[i]->leave = true;
+    var_set_leave (v[i], true);
   free (v);
 
   return lex_end_of_command (lexer);
Index: src/language/dictionary/split-file.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/split-file.c,v
retrieving revision 1.12
diff -u -p -r1.12 split-file.c
--- src/language/dictionary/split-file.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/dictionary/split-file.c	10 Dec 2006 03:30:28 -0000
@@ -96,12 +96,12 @@ output_split_file_values (const struct d
 
       tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", var_get_name (v));
       
-      data_out (case_data (c, v->fv), print, temp_buf);
+      data_out (case_data (c, v), print, temp_buf);
       temp_buf[print->w] = 0;
 
       tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", print->w, temp_buf);
 
-      val_lab = val_labs_find (v->val_labs, *case_data (c, v->fv));
+      val_lab = var_lookup_value_label (v, case_data (c, v));
       if (val_lab)
 	tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
     }
Index: src/language/dictionary/sys-file-info.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/sys-file-info.c,v
retrieving revision 1.17
diff -u -p -r1.17 sys-file-info.c
--- src/language/dictionary/sys-file-info.c	5 Dec 2006 15:10:21 -0000	1.17
+++ src/language/dictionary/sys-file-info.c	10 Dec 2006 03:30:28 -0000
@@ -24,10 +24,13 @@
 
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
+#include <data/format.h>
+#include <data/missing-values.h>
 #include <data/procedure.h>
 #include <data/sys-file-reader.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
+#include <data/vector.h>
 #include <language/command.h>
 #include <language/data-io/file-handle.h>
 #include <language/lexer/lexer.h>
@@ -151,7 +154,7 @@ cmd_sysfile_info (struct lexer *lexer, s
   for (r = 1, i = 0; i < dict_get_var_cnt (d); i++)
     {
       struct variable *v = dict_get_var (d, i);
-      const int nvl = val_labs_count (v->val_labs);
+      const int nvl = val_labs_count (var_get_value_labels (v));
       
       if (r + 10 + nvl > nr)
 	{
@@ -275,7 +278,7 @@ cmd_display (struct lexer *lexer, struct
 	}
 
       if (sorted)
-	sort (vl, n, sizeof *vl, compare_var_ptr_names, NULL);
+	sort (vl, n, sizeof *vl, compare_var_ptrs_by_name, NULL);
 
       display_variables (vl, n, as);
 
@@ -399,7 +402,7 @@ display_variables (struct variable **vl,
 
       if (as == AS_DICTIONARY || as == AS_VARIABLES)
 	{
-	  int nvl = val_labs_count (v->val_labs);
+	  int nvl = val_labs_count (var_get_value_labels (v));
       
 	  if (r + 10 + nvl > nr)
 	    {
@@ -419,7 +422,8 @@ display_variables (struct variable **vl,
             }
 	  if (as != AS_NAMES)
 	    {
-	      tab_text (t, pc, r, TAT_PRINTF, "%d", v->index + 1);
+	      tab_text (t, pc, r, TAT_PRINTF, "%d",
+                        (int) var_get_dict_index (v) + 1);
 	      tab_hline (t, TAL_1, 0, nc - 1, r);
 	    }
 	  r++;
@@ -451,7 +455,7 @@ describe_variable (struct variable *v, s
 
   /* Put the name, var label, and position into the first row. */
   tab_text (t, 0, r, TAB_LEFT, var_get_name (v));
-  tab_text (t, 3, r, TAT_PRINTF, "%d", v->index + 1);
+  tab_text (t, 3, r, TAT_PRINTF, "%d", (int) var_get_dict_index (v) + 1);
 
   if (as == AS_DICTIONARY && var_has_label (v)) 
     {
@@ -524,8 +528,9 @@ describe_variable (struct variable *v, s
     }
 
   /* Value labels. */
-  if (as == AS_DICTIONARY && val_labs_count (v->val_labs))
+  if (as == AS_DICTIONARY && var_has_value_labels (v))
     {
+      const struct val_labs *val_labs = var_get_value_labels (v);
       struct val_labs_iterator *i;
       struct val_lab *vl;
       int orig_r = r;
@@ -537,8 +542,8 @@ describe_variable (struct variable *v, s
 #endif
 
       tab_hline (t, TAL_1, 1, 2, r);
-      for (vl = val_labs_first_sorted (v->val_labs, &i); vl != NULL;
-           vl = val_labs_next (v->val_labs, &i))
+      for (vl = val_labs_first_sorted (val_labs, &i); vl != NULL;
+           vl = val_labs_next (val_labs, &i))
         {
 	  char buf[128];
 
@@ -564,17 +569,6 @@ describe_variable (struct variable *v, s
   return r;
 }
 
-static int
-compare_vectors_by_name (const void *a_, const void *b_)
-{
-  struct vector *const *pa = a_;
-  struct vector *const *pb = b_;
-  struct vector *a = *pa;
-  struct vector *b = *pb;
-  
-  return strcasecmp (a->name, b->name);
-}
-
 /* Display a list of vectors.  If SORTED is nonzero then they are
    sorted alphabetically. */
 static void
@@ -596,7 +590,7 @@ display_vectors (const struct dictionary
   for (i = 0; i < nvec; i++)
     vl[i] = dict_get_vector (dict, i);
   if (sorted)
-    qsort (vl, nvec, sizeof *vl, compare_vectors_by_name);
+    qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name);
 
   t = tab_create (1, nvec + 1, 0);
   tab_headers (t, 0, 0, 1, 0);
@@ -606,7 +600,7 @@ display_vectors (const struct dictionary
   tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Vector"));
   tab_flags (t, SOMF_NO_TITLE);
   for (i = 0; i < nvec; i++)
-    tab_text (t, 0, i + 1, TAB_LEFT, vl[i]->name);
+    tab_text (t, 0, i + 1, TAB_LEFT, vector_get_name (vl[i]));
   tab_submit (t);
 
   free (vl);
Index: src/language/dictionary/value-labels.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/value-labels.c,v
retrieving revision 1.13
diff -u -p -r1.13 value-labels.c
--- src/language/dictionary/value-labels.c	5 Dec 2006 15:10:21 -0000	1.13
+++ src/language/dictionary/value-labels.c	10 Dec 2006 03:30:28 -0000
@@ -136,7 +136,7 @@ erase_labels (struct variable **vars, si
 
   /* Erase old value labels if desired. */
   for (i = 0; i < var_cnt; i++)
-    val_labs_clear (vars[i]->val_labs);
+    var_clear_value_labels (vars[i]);
 }
 
 /* Parse all the labels for the VAR_CNT variables in VARS and add
@@ -188,7 +188,7 @@ get_label (struct lexer *lexer, struct v
 	}
 
       for (i = 0; i < var_cnt; i++)
-        val_labs_replace (vars[i]->val_labs, value, ds_cstr (&label));
+        var_replace_value_label (vars[i], &value, ds_cstr (&label));
 
       ds_destroy (&label);
 
Index: src/language/dictionary/variable-label.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/variable-label.c,v
retrieving revision 1.12
diff -u -p -r1.12 variable-label.c
--- src/language/dictionary/variable-label.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/dictionary/variable-label.c	10 Dec 2006 03:30:28 -0000
@@ -76,14 +76,3 @@ cmd_variable_labels (struct lexer *lexer
 
 
 
-const char *
-var_to_string(const struct variable *var)
-{
-  const char *label;
-  
-  if ( !var ) 
-    return 0;
-
-  label = var_get_label (var);
-  return label ? label : var_get_name (var);
-}
Index: src/language/dictionary/vector.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/vector.c,v
retrieving revision 1.10
diff -u -p -r1.10 vector.c
--- src/language/dictionary/vector.c	11 Nov 2006 23:10:00 -0000	1.10
+++ src/language/dictionary/vector.c	10 Dec 2006 03:30:28 -0000
@@ -107,7 +107,7 @@ cmd_vector (struct lexer *lexer, struct 
 	    }
 
 	  if (!parse_variables (lexer, dict, &v, &nv,
-                                PV_SAME_TYPE | PV_DUPLICATE))
+                                PV_SAME_WIDTH | PV_DUPLICATE))
 	    goto fail;
 
           dict_create_vector (dict, vecnames, v, nv);
Index: src/language/expressions/evaluate.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/expressions/evaluate.c,v
retrieving revision 1.12
diff -u -p -r1.12 evaluate.c
--- src/language/expressions/evaluate.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/expressions/evaluate.c	10 Dec 2006 03:30:28 -0000
@@ -180,9 +180,9 @@ cmd_debug_evaluate (struct lexer *lexer,
             case_resize (c, old_value_cnt, dict_get_next_value_idx (d));
 
           if (lex_is_number (lexer))
-            case_data_rw (c, v->fv)->f = lex_tokval (lexer);
+            case_data_rw (c, v)->f = lex_tokval (lexer);
           else
-            memcpy (case_data_rw (c, v->fv)->s, ds_data (lex_tokstr (lexer)),
+            memcpy (case_data_rw (c, v)->s, ds_data (lex_tokstr (lexer)),
                     var_get_width (v));
           lex_get (lexer);
 
@@ -312,7 +312,7 @@ expr_debug_print_postfix (const struct e
           fprintf (stderr, "v<%s>", var_get_name (op->variable));
           break;
         case OP_vector:
-          fprintf (stderr, "vec<%s>", op->vector->name);
+          fprintf (stderr, "vec<%s>", vector_get_name (op->vector));
           break;
         case OP_integer:
           fprintf (stderr, "i<%d>", op->integer);
Index: src/language/expressions/helpers.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/expressions/helpers.h,v
retrieving revision 1.7
diff -u -p -r1.7 helpers.h
--- src/language/expressions/helpers.h	5 Nov 2006 05:20:53 -0000	1.7
+++ src/language/expressions/helpers.h	10 Dec 2006 03:30:28 -0000
@@ -19,6 +19,7 @@
 #include <data/settings.h>
 #include <data/value.h>
 #include <data/variable.h>
+#include <data/vector.h>
 #include <gsl-extras/gsl-extras.h>
 #include <language/expressions/public.h>
 #include <libpspp/compiler.h>
Index: src/language/expressions/operations.def
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/expressions/operations.def,v
retrieving revision 1.10
diff -u -p -r1.10 operations.def
--- src/language/expressions/operations.def	5 Dec 2006 15:10:21 -0000	1.10
+++ src/language/expressions/operations.def	10 Dec 2006 03:30:28 -0000
@@ -892,22 +892,22 @@ absorb_miss boolean function SYSMIS (x) 
 no_opt boolean function SYSMIS (num_var v)
      case c;
 {
-  return case_num (c, v->fv) == SYSMIS;
+  return case_num (c, v) == SYSMIS;
 }
 no_opt boolean function VALUE (num_var v)
      case c;
 {
-  return case_num (c, v->fv);
+  return case_num (c, v);
 }
 
 no_opt operator VEC_ELEM_NUM (idx)
      vector v;
      case c;
 {
-  if (idx >= 1 && idx <= v->cnt) 
+  if (idx >= 1 && idx <= vector_get_var_cnt (v)) 
     {
-      const struct variable *var = v->var[(int) idx - 1];
-      double value = case_num (c, var->fv);
+      const struct variable *var = vector_get_var (v, (size_t) idx - 1);
+      double value = case_num (c, var);
       return !var_is_num_user_missing (var, value) ? value : SYSMIS; 
     }
   else
@@ -915,11 +915,11 @@ no_opt operator VEC_ELEM_NUM (idx)
       if (idx == SYSMIS)
         msg (SE, _("SYSMIS is not a valid index value for vector "
                    "%s.  The result will be set to SYSMIS."),
-             v->name);
+             vector_get_name (v));
       else
         msg (SE, _("%g is not a valid index value for vector %s.  "
                    "The result will be set to SYSMIS."),
-             idx, v->name);
+             idx, vector_get_name (v));
       return SYSMIS;
     }
 }
@@ -929,21 +929,21 @@ absorb_miss no_opt string operator VEC_E
      vector v;
      case c;
 {
-  if (idx >= 1 && idx <= v->cnt)
+  if (idx >= 1 && idx <= vector_get_var_cnt (v))
     {
-      struct variable *var = v->var[(int) idx - 1];
-      return copy_string (e, case_str (c, var->fv), var_get_width (var));
+      struct variable *var = vector_get_var (v, (size_t) idx - 1);
+      return copy_string (e, case_str (c, var), var_get_width (var));
     }
   else
     {
       if (idx == SYSMIS)
         msg (SE, _("SYSMIS is not a valid index value for vector "
                    "%s.  The result will be set to the empty string."),
-             v->name);
+             vector_get_name (v));
       else
         msg (SE, _("%g is not a valid index value for vector %s.  "
                    "The result will be set to the empty string."),
-             idx, v->name);
+             idx, vector_get_name (v));
       return empty_string;
     }
 }
@@ -954,7 +954,7 @@ no_opt operator NUM_VAR ()
      case c;
      num_var v;
 {
-  double d = case_num (c, v->fv);
+  double d = case_num (c, v);
   return !var_is_num_user_missing (v, d) ? d : SYSMIS;
 }
 
@@ -964,7 +964,7 @@ no_opt string operator STR_VAR ()
      str_var v;
 {
   struct substring s = alloc_string (e, var_get_width (v));
-  memcpy (s.string, case_str (c, v->fv), var_get_width (v));
+  memcpy (s.string, case_str (c, v), var_get_width (v));
   return s;
 }
 
@@ -974,7 +974,7 @@ no_opt perm_only function LAG (num_var v
   struct ccase *c = lagged_case (ds, n_before);
   if (c != NULL)
     {
-      double x = case_num (c, v->fv);
+      double x = case_num (c, v);
       return !var_is_num_user_missing (v, x) ? x : SYSMIS;
     }
   else
@@ -987,7 +987,7 @@ no_opt perm_only function LAG (num_var v
   struct ccase *c = lagged_case (ds, 1);
   if (c != NULL)
     {
-      double x = case_num (c, v->fv);
+      double x = case_num (c, v);
       return !var_is_num_user_missing (v, x) ? x : SYSMIS;
     }
   else
@@ -1000,7 +1000,7 @@ no_opt perm_only string function LAG (st
 {
   struct ccase *c = lagged_case (ds, n_before);
   if (c != NULL)
-    return copy_string (e, case_str (c, v->fv), var_get_width (v));
+    return copy_string (e, case_str (c, v), var_get_width (v));
   else
     return empty_string;
 }
@@ -1011,7 +1011,7 @@ no_opt perm_only string function LAG (st
 {
   struct ccase *c = lagged_case (ds, 1);
   if (c != NULL)
-    return copy_string (e, case_str (c, v->fv), var_get_width (v));
+    return copy_string (e, case_str (c, v), var_get_width (v));
   else
     return empty_string;
 }
@@ -1020,14 +1020,14 @@ no_opt operator NUM_SYS ()
      case c;
      num_var v;
 {
-  return case_num (c, v->fv) == SYSMIS;
+  return case_num (c, v) == SYSMIS;
 }
 
 no_opt operator NUM_VAL ()
      case c;
      num_var v;
 {
-  return case_num (c, v->fv);
+  return case_num (c, v);
 }
 
 no_opt operator CASENUM ()
Index: src/language/expressions/parse.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/expressions/parse.c,v
retrieving revision 1.19
diff -u -p -r1.19 parse.c
--- src/language/expressions/parse.c	5 Dec 2006 15:10:21 -0000	1.19
+++ src/language/expressions/parse.c	10 Dec 2006 03:30:30 -0000
@@ -358,7 +358,7 @@ type_coercion_core (struct expression *e
       msg_disable ();
       if ((*node)->type == OP_format
           && fmt_check_input (&(*node)->format.f)
-          && fmt_check_type_compat (&(*node)->format.f, NUMERIC))
+          && fmt_check_type_compat (&(*node)->format.f, VAR_NUMERIC))
         {
           msg_enable ();
           if (do_coercion)
@@ -372,7 +372,7 @@ type_coercion_core (struct expression *e
       msg_disable ();
       if ((*node)->type == OP_format
           && fmt_check_output (&(*node)->format.f)
-          && fmt_check_type_compat (&(*node)->format.f, NUMERIC))
+          && fmt_check_type_compat (&(*node)->format.f, VAR_NUMERIC))
         {
           msg_enable ();
           if (do_coercion)
@@ -901,7 +901,7 @@ parse_vector_element (struct lexer *lexe
       || !lex_match (lexer, ')'))
     return NULL;
 
-  return expr_allocate_binary (e, (var_is_numeric (vector->var[0])
+  return expr_allocate_binary (e, (vector_get_type (vector) == VAR_NUMERIC
                                    ? OP_VEC_ELEM_NUM : OP_VEC_ELEM_STR),
                                element, expr_allocate_vector (e, vector));
 }
Index: src/language/lexer/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/lexer/ChangeLog,v
retrieving revision 1.19
diff -u -p -r1.19 ChangeLog
--- src/language/lexer/ChangeLog	3 Dec 2006 22:16:45 -0000	1.19
+++ src/language/lexer/ChangeLog	10 Dec 2006 03:30:30 -0000
@@ -1,3 +1,13 @@
+Sat Dec  9 18:46:11 2006  Ben Pfaff  <blp@gnu.org>
+
+	* variable-parser.h: New PV_SAME_WIDTH variable parsing option.
+
+	* variable-parser.c (add_variable): Implement new PV_SAME_WIDTH
+	option.
+	(parse_var_set_vars) Ditto.
+	(array_var_set_lookup_var_idx) Use new var_create, var_destroy
+	functions.
+
 Sat Dec  2 21:19:50 2006  Ben Pfaff  <blp@gnu.org>
 
 	General clean-up.
Index: src/language/lexer/variable-parser.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/lexer/variable-parser.c,v
retrieving revision 1.12
diff -u -p -r1.12 variable-parser.c
--- src/language/lexer/variable-parser.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/lexer/variable-parser.c	10 Dec 2006 03:30:30 -0000
@@ -30,6 +30,7 @@
 #include <data/procedure.h>
 #include <data/variable.h>
 #include <libpspp/alloc.h>
+#include <libpspp/assertion.h>
 #include <libpspp/bit-vector.h>
 #include <libpspp/hash.h>
 #include <libpspp/message.h>
@@ -175,11 +176,17 @@ add_variable (struct variable ***v, size
            && 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
+  else if ((pv_opts & (PV_SAME_TYPE | PV_SAME_WIDTH)) && *nv
            && var_get_type (add) != var_get_type ((*v)[0])) 
     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."),
+               "will be omitted from the list."),
+         var_get_name ((*v)[0]), add_name, add_name);
+  else if ((pv_opts & PV_SAME_WIDTH) && *nv
+           && var_get_width (add) != var_get_width ((*v)[0]))
+    msg (SE, _("%s and %s are string variables with different widths.  "
+               "All variables in this variable list must have the "
+               "same width.  %s will be omttied from the list."),
          var_get_name ((*v)[0]), add_name, add_name);
   else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) 
     msg (SE, _("Variable %s appears twice in variable list."), add_name);
@@ -229,11 +236,12 @@ parse_var_set_vars (struct lexer *lexer,
   assert (v != NULL);
   assert (nv != NULL);
 
-  /* 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);
+  /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE,
+     PV_SAME_WIDTH may be specified. */
+  assert (((pv_opts & PV_NUMERIC) != 0)
+          + ((pv_opts & PV_STRING) != 0)
+          + ((pv_opts & PV_SAME_TYPE) != 0)
+          + ((pv_opts & PV_SAME_WIDTH) != 0) <= 1);
 
   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
@@ -252,8 +260,13 @@ parse_var_set_vars (struct lexer *lexer,
       size_t i;
       
       included = xcalloc (var_set_get_cnt (vs), sizeof *included);
-      for (i = 0; i < *nv; i++)
-        included[(*v)[i]->index] = 1;
+      for (i = 0; i < *nv; i++) 
+        {
+          size_t index;
+          if (!var_set_lookup_var_idx (vs, var_get_name ((*v)[i]), &index))
+            NOT_REACHED ();
+          included[index] = 1; 
+        }
     }
   else
     included = NULL;
@@ -687,7 +700,7 @@ dict_var_set_lookup_var_idx (const struc
   struct variable *v = dict_lookup_var (d, name);
   if (v != NULL) 
     {
-      *idx = v->index;
+      *idx = var_get_dict_index (v);
       return true;
     }
   else
@@ -748,11 +761,12 @@ array_var_set_lookup_var_idx (const stru
                               size_t *idx) 
 {
   struct array_var_set *avs = vs->aux;
-  struct variable v, *vp, *const *vpp;
+  struct variable *v, *const *vpp;
 
-  strcpy (v.name, name);
-  vp = &v;
-  vpp = hsh_find (avs->name_tab, &vp);
+  v = var_create (name, 0);
+  vpp = hsh_find (avs->name_tab, &v);
+  var_destroy (v);
+  
   if (vpp != NULL) 
     {
       *idx = vpp - avs->var;
@@ -791,8 +805,8 @@ var_set_create_from_array (struct variab
   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);
+                              compare_var_ptrs_by_name, hash_var_ptr_by_name,
+                              NULL, NULL);
   for (i = 0; i < var_cnt; i++)
     if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
       {
Index: src/language/lexer/variable-parser.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/lexer/variable-parser.h,v
retrieving revision 1.5
diff -u -p -r1.5 variable-parser.h
--- src/language/lexer/variable-parser.h	11 Nov 2006 23:10:00 -0000	1.5
+++ src/language/lexer/variable-parser.h	10 Dec 2006 03:30:30 -0000
@@ -53,7 +53,8 @@ enum
     PV_NUMERIC = 0020,		/* Vars must be numeric. */
     PV_STRING = 0040,		/* Vars must be string. */
     PV_SAME_TYPE = 00100,	/* All vars must be the same type. */
-    PV_NO_SCRATCH = 00200 	/* Disallow scratch variables. */
+    PV_SAME_WIDTH = 00200,	/* All vars must be the same type and width. */
+    PV_NO_SCRATCH = 00400 	/* Disallow scratch variables. */
   };
 
 struct variable *parse_variable (struct lexer *, const struct dictionary *);
Index: src/language/stats/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/ChangeLog,v
retrieving revision 1.34
diff -u -p -r1.34 ChangeLog
--- src/language/stats/ChangeLog	7 Dec 2006 06:31:04 -0000	1.34
+++ src/language/stats/ChangeLog	10 Dec 2006 03:30:30 -0000
@@ -1,3 +1,8 @@
+Sat Dec  9 18:47:51 2006  Ben Pfaff  <blp@gnu.org>
+
+	* regression.q (is_depvar): Compare variable pointers instead of
+	variable names.
+
 Thu Dec  7 15:26:25 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
 	* examine.q: Allocated the categorical values for the dependent and 
Index: src/language/stats/aggregate.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/aggregate.c,v
retrieving revision 1.21
diff -u -p -r1.21 aggregate.c
--- src/language/stats/aggregate.c	5 Dec 2006 15:10:21 -0000	1.21
+++ src/language/stats/aggregate.c	10 Dec 2006 03:30:31 -0000
@@ -27,6 +27,7 @@
 #include <data/casefile.h>
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
+#include <data/format.h>
 #include <data/procedure.h>
 #include <data/settings.h>
 #include <data/storage-stream.h>
@@ -93,36 +94,36 @@ struct agr_func
   {
     const char *name;		/* Aggregation function name. */
     size_t n_args;              /* Number of arguments. */
-    int alpha_type;		/* When given ALPHA arguments, output type. */
+    enum var_type alpha_type;   /* When given ALPHA arguments, output type. */
     struct fmt_spec format;	/* Format spec if alpha_type != ALPHA. */
   };
 
 /* Attributes of aggregation functions. */
 static const struct agr_func agr_func_tab[] = 
   {
-    {"<NONE>",  0, -1,      {0, 0, 0}},
-    {"SUM",     0, -1,      {FMT_F, 8, 2}},
-    {"MEAN",	0, -1,      {FMT_F, 8, 2}},
-    {"SD",      0, -1,      {FMT_F, 8, 2}},
-    {"MAX",     0, ALPHA,   {-1, -1, -1}}, 
-    {"MIN",     0, ALPHA,   {-1, -1, -1}}, 
-    {"PGT",     1, NUMERIC, {FMT_F, 5, 1}},      
-    {"PLT",     1, NUMERIC, {FMT_F, 5, 1}},       
-    {"PIN",     2, NUMERIC, {FMT_F, 5, 1}},       
-    {"POUT",    2, NUMERIC, {FMT_F, 5, 1}},       
-    {"FGT",     1, NUMERIC, {FMT_F, 5, 3}},       
-    {"FLT",     1, NUMERIC, {FMT_F, 5, 3}},       
-    {"FIN",     2, NUMERIC, {FMT_F, 5, 3}},       
-    {"FOUT",    2, NUMERIC, {FMT_F, 5, 3}},       
-    {"N",       0, NUMERIC, {FMT_F, 7, 0}},       
-    {"NU",      0, NUMERIC, {FMT_F, 7, 0}},       
-    {"NMISS",   0, NUMERIC, {FMT_F, 7, 0}},       
-    {"NUMISS",  0, NUMERIC, {FMT_F, 7, 0}},       
-    {"FIRST",   0, ALPHA,   {-1, -1, -1}}, 
-    {"LAST",    0, ALPHA,   {-1, -1, -1}},
-    {NULL,      0, -1,      {-1, -1, -1}},
-    {"N",       0, NUMERIC, {FMT_F, 7, 0}},
-    {"NU",      0, NUMERIC, {FMT_F, 7, 0}},
+    {"<NONE>",  0, -1,          {0, 0, 0}},
+    {"SUM",     0, -1,          {FMT_F, 8, 2}},
+    {"MEAN",	0, -1,          {FMT_F, 8, 2}},
+    {"SD",      0, -1,          {FMT_F, 8, 2}},
+    {"MAX",     0, VAR_STRING,  {-1, -1, -1}}, 
+    {"MIN",     0, VAR_STRING,  {-1, -1, -1}}, 
+    {"PGT",     1, VAR_NUMERIC, {FMT_F, 5, 1}},      
+    {"PLT",     1, VAR_NUMERIC, {FMT_F, 5, 1}},       
+    {"PIN",     2, VAR_NUMERIC, {FMT_F, 5, 1}},       
+    {"POUT",    2, VAR_NUMERIC, {FMT_F, 5, 1}},       
+    {"FGT",     1, VAR_NUMERIC, {FMT_F, 5, 3}},       
+    {"FLT",     1, VAR_NUMERIC, {FMT_F, 5, 3}},       
+    {"FIN",     2, VAR_NUMERIC, {FMT_F, 5, 3}},       
+    {"FOUT",    2, VAR_NUMERIC, {FMT_F, 5, 3}},       
+    {"N",       0, VAR_NUMERIC, {FMT_F, 7, 0}},       
+    {"NU",      0, VAR_NUMERIC, {FMT_F, 7, 0}},       
+    {"NMISS",   0, VAR_NUMERIC, {FMT_F, 7, 0}},       
+    {"NUMISS",  0, VAR_NUMERIC, {FMT_F, 7, 0}},       
+    {"FIRST",   0, VAR_STRING,  {-1, -1, -1}}, 
+    {"LAST",    0, VAR_STRING,  {-1, -1, -1}},
+    {NULL,      0, -1,          {-1, -1, -1}},
+    {"N",       0, VAR_NUMERIC, {FMT_F, 7, 0}},
+    {"NU",      0, VAR_NUMERIC, {FMT_F, 7, 0}},
   };
 
 /* Missing value types. */
@@ -494,13 +495,15 @@ parse_aggregate_functions (struct lexer 
 		if (lex_token (lexer) == T_STRING)
 		  {
 		    arg[i].c = ds_xstrdup (lex_tokstr (lexer));
-		    type = ALPHA;
+		    type = VAR_STRING;
 		  }
 		else if (lex_is_number (lexer))
 		  {
 		    arg[i].f = lex_tokval (lexer);
-		    type = NUMERIC;
-		  } else {
+		    type = VAR_NUMERIC;
+		  }
+                else
+                  {
 		    msg (SE, _("Missing argument %d to %s."), i + 1,
                          function->name);
 		    goto error;
@@ -587,12 +590,12 @@ parse_aggregate_functions (struct lexer 
 		    v->string = xmalloc (var_get_width (src[i]));
 		  }
 
-		if (function->alpha_type == ALPHA)
+		if (function->alpha_type == VAR_STRING)
 		  destvar = dict_clone_var (agr->dict, v->src, dest[i]);
 		else
                   {
                     assert (var_is_numeric (v->src)
-                            || function->alpha_type == NUMERIC);
+                            || function->alpha_type == VAR_NUMERIC);
                     destvar = dict_create_var (agr->dict, dest[i], 0);
                     if (destvar != NULL) 
                       {
@@ -771,7 +774,7 @@ accumulate_aggregate_info (struct agr_pr
   for (iter = agr->agr_vars; iter; iter = iter->next)
     if (iter->src)
       {
-	const union value *v = case_data (input, iter->src->fv);
+	const union value *v = case_data (input, iter->src);
         int src_width = var_get_width (iter->src);
 
 	if (iter->include_missing
@@ -944,8 +947,8 @@ dump_aggregate_info (struct agr_proc *ag
       {
         struct variable *v = agr->break_vars[i];
         size_t value_cnt = var_get_value_cnt (v);
-        memcpy (case_data_rw (output, value_idx),
-                case_data (&agr->break_case, v->fv),
+        memcpy (case_data_rw_idx (output, value_idx),
+                case_data (&agr->break_case, v),
                 sizeof (union value) * value_cnt);
         value_idx += value_cnt; 
       }
@@ -956,7 +959,7 @@ dump_aggregate_info (struct agr_proc *ag
   
     for (i = agr->agr_vars; i; i = i->next)
       {
-	union value *v = case_data_rw (output, i->dest->fv);
+	union value *v = case_data_rw (output, i->dest);
 
 	if (agr->missing == COLUMNWISE && i->missing != 0
 	    && (i->function & FUNC) != N && (i->function & FUNC) != NU
Index: src/language/stats/autorecode.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/autorecode.c,v
retrieving revision 1.15
diff -u -p -r1.15 autorecode.c
--- src/language/stats/autorecode.c	5 Dec 2006 15:10:21 -0000	1.15
+++ src/language/stats/autorecode.c	10 Dec 2006 03:30:31 -0000
@@ -285,12 +285,12 @@ autorecode_trns_proc (void *trns_, struc
       union arc_value v;
 
       if (var_is_numeric (spec->src))
-        v.f = case_num (c, spec->src->fv);
+        v.f = case_num (c, spec->src);
       else
-        v.c = (char *) case_str (c, spec->src->fv);
+        v.c = (char *) case_str (c, spec->src);
       item = hsh_force_find (spec->items, &v);
 
-      case_data_rw (c, spec->dest->fv)->f = item->to;
+      case_data_rw (c, spec->dest)->f = item->to;
     }
   return TRNS_CONTINUE;
 }
@@ -357,9 +357,9 @@ autorecode_proc_func (const struct ccase
       union arc_value v, *vp, **vpp;
 
       if (var_is_numeric (arc->src_vars[i]))
-        v.f = case_num (c, arc->src_vars[i]->fv);
+        v.f = case_num (c, arc->src_vars[i]);
       else
-        v.c = (char *) case_str (c, arc->src_vars[i]->fv);
+        v.c = (char *) case_str (c, arc->src_vars[i]);
 
       vpp = (union arc_value **) hsh_probe (arc->src_values[i], &v);
       if (*vpp == NULL)
Index: src/language/stats/crosstabs.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/crosstabs.q,v
retrieving revision 1.24
diff -u -p -r1.24 crosstabs.q
--- src/language/stats/crosstabs.q	5 Dec 2006 15:10:21 -0000	1.24
+++ src/language/stats/crosstabs.q	10 Dec 2006 03:30:33 -0000
@@ -39,6 +39,7 @@
 #include <data/case.h>
 #include <data/data-out.h>
 #include <data/dictionary.h>
+#include <data/format.h>
 #include <data/procedure.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
@@ -131,9 +132,7 @@ struct var_range
 static inline struct var_range *
 get_var_range (struct variable *v) 
 {
-  assert (v != NULL);
-  assert (v->aux != NULL);
-  return v->aux;
+  return var_get_aux (v);
 }
 
 /* Indexes into crosstab.v. */
@@ -592,7 +591,7 @@ calc_general (const struct ccase *c, voi
 	assert (x != NULL);
 	for (j = 0; j < x->nvar; j++)
 	  {
-            const union value *v = case_data (c, x->vars[j]->fv);
+            const union value *v = case_data (c, x->vars[j]);
 	    if ((cmd.miss == CRS_TABLE && var_is_value_missing (x->vars[j], v))
 		|| (cmd.miss == CRS_INCLUDE
 		    && var_is_value_system_missing (x->vars[j], v)))
@@ -602,10 +601,10 @@ calc_general (const struct ccase *c, voi
 	      }
 	      
 	    if (var_is_numeric (x->vars[j]))
-	      te->values[j].f = case_num (c, x->vars[j]->fv);
+	      te->values[j].f = case_num (c, x->vars[j]);
 	    else
 	      {
-		memcpy (te->values[j].s, case_str (c, x->vars[j]->fv),
+		memcpy (te->values[j].s, case_str (c, x->vars[j]),
                         var_get_width (x->vars[j]));
 	      
 		/* Necessary in order to simplify comparisons. */
@@ -661,7 +660,7 @@ calc_integer (const struct ccase *c, voi
 	{
 	  struct variable *const v = x->vars[i];
           struct var_range *vr = get_var_range (v);
-	  double value = case_num (c, v->fv);
+	  double value = case_num (c, v);
 	  
 	  /* Note that the first test also rules out SYSMIS. */
 	  if ((value < vr->min || value >= vr->max)
@@ -680,10 +679,10 @@ calc_integer (const struct ccase *c, voi
       
       {
         struct variable *row_var = x->vars[ROW_VAR];
-	const int row = case_num (c, row_var->fv) - get_var_range (row_var)->min;
+	const int row = case_num (c, row_var) - get_var_range (row_var)->min;
 
         struct variable *col_var = x->vars[COL_VAR];
-	const int col = case_num (c, col_var->fv) - get_var_range (col_var)->min;
+	const int col = case_num (c, col_var) - get_var_range (col_var)->min;
 
 	const int col_dim = get_var_range (col_var)->count;
 
@@ -1667,7 +1666,7 @@ table_value_missing (struct tab_table *t
   struct substring s;
   const struct fmt_spec *print = var_get_print_format (var);
 
-  const char *label = val_labs_find (var->val_labs, *v);
+  const char *label = var_lookup_value_label (var, v);
   if (label) 
     {
       tab_text (table, c, r, TAB_LEFT, label);
Index: src/language/stats/descriptives.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/descriptives.c,v
retrieving revision 1.18
diff -u -p -r1.18 descriptives.c
--- src/language/stats/descriptives.c	5 Dec 2006 15:10:21 -0000	1.18
+++ src/language/stats/descriptives.c	10 Dec 2006 03:30:34 -0000
@@ -64,11 +64,10 @@ enum dsc_missing_type
    calculating a Z-score. */
 struct dsc_z_score
   {
-    int src_idx;                /* Source index into case data. */
-    int dst_idx;                /* Destination index into case data. */
+    struct variable *src_var;   /* Variable on which z-score is based. */
+    struct variable *z_var;     /* New z-score variable. */
     double mean;		/* Distribution mean. */
     double std_dev;		/* Distribution standard deviation. */
-    struct variable *v;         /* Variable on which z-score is based. */
   };
 
 /* DESCRIPTIVES transformation (for calculating Z-scores). */
@@ -596,7 +595,7 @@ descriptives_trns_proc (void *trns_, str
       assert(t->vars);
       for (vars = t->vars; vars < t->vars + t->var_cnt; vars++)
 	{
-	  double score = case_num (c, (*vars)->fv);
+	  double score = case_num (c, *vars);
 	  if ( score == SYSMIS
                || (!t->include_user_missing 
                    && var_is_num_user_missing (*vars, score)))
@@ -609,13 +608,13 @@ descriptives_trns_proc (void *trns_, str
       
   for (z = t->z_scores; z < t->z_scores + t->z_score_cnt; z++)
     {
-      double input = case_num (c, z->src_idx);
-      double *output = &case_data_rw (c, z->dst_idx)->f;
+      double input = case_num (c, z->src_var);
+      double *output = &case_data_rw (c, z->z_var)->f;
 
       if (z->mean == SYSMIS || z->std_dev == SYSMIS 
 	  || all_sysmis || input == SYSMIS 
 	  || (!t->include_user_missing
-              && var_is_num_user_missing (z->v, input)))
+              && var_is_num_user_missing (z->src_var, input)))
 	*output = SYSMIS;
       else
 	*output = (input - z->mean) / z->std_dev;
@@ -677,11 +676,10 @@ setup_z_trns (struct dsc_proc *dsc, stru
                                              var_to_string (dv->v)));
 
           z = &t->z_scores[cnt++];
-          z->src_idx = dv->v->fv;
-          z->dst_idx = dst_var->fv;
+          z->src_var = dv->v;
+          z->z_var = dst_var;
           z->mean = dv->stats[DSC_MEAN];
           z->std_dev = dv->stats[DSC_STDDEV];
-	  z->v = dv->v;
 	}
     }
 
@@ -741,7 +739,7 @@ calc_descriptives (const struct ccase *f
       for (i = 0; i < dsc->var_cnt; i++) 
         {
           struct dsc_var *dv = &dsc->vars[i];
-          double x = case_num (&c, dv->v->fv);
+          double x = case_num (&c, dv->v);
           
           if (dsc->missing_type != DSC_LISTWISE
               && (x == SYSMIS
@@ -783,7 +781,7 @@ calc_descriptives (const struct ccase *f
           for (i = 0; i < dsc->var_cnt; i++) 
             {
               struct dsc_var *dv = &dsc->vars[i];
-              double x = case_num (&c, dv->v->fv);
+              double x = case_num (&c, dv->v);
           
               if (dsc->missing_type != DSC_LISTWISE
                   && (x == SYSMIS
@@ -850,7 +848,7 @@ listwise_missing (struct dsc_proc *dsc, 
   for (i = 0; i < dsc->var_cnt; i++)
     {
       struct dsc_var *dv = &dsc->vars[i];
-      double x = case_num (c, dv->v->fv);
+      double x = case_num (c, dv->v);
 
       if (x == SYSMIS
           || (!dsc->include_user_missing
Index: src/language/stats/examine.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/examine.q,v
retrieving revision 1.19
diff -u -p -r1.19 examine.q
--- src/language/stats/examine.q	7 Dec 2006 06:31:04 -0000	1.19
+++ src/language/stats/examine.q	10 Dec 2006 03:30:35 -0000
@@ -649,13 +649,13 @@ factor_calc (const struct ccase *c, int 
       union value *indep_vals[2] ;
 
       indep_vals[0] = value_dup (
-				 case_data (c, fctr->indep_var[0]->fv),
+				 case_data (c, fctr->indep_var[0]),
 				 var_get_width (fctr->indep_var[0])
 				 );
 
       if ( fctr->indep_var[1] )
 	indep_vals[1] = value_dup (
-				   case_data (c, fctr->indep_var[1]->fv),
+				   case_data (c, fctr->indep_var[1]),
 				   var_get_width (fctr->indep_var[1])
 				   );
       else
@@ -692,7 +692,7 @@ factor_calc (const struct ccase *c, int 
 	{
 	  const struct variable *var = dependent_vars[v];
 	  union value *val = value_dup (
-					case_data (c, var->fv),
+					case_data (c, var),
 					var_get_width (var)
 					);
 
@@ -759,7 +759,7 @@ run_examine (const struct ccase *first, 
 	    {
 	      const struct variable *var = dependent_vars[v];
 	      union value *val = value_dup (
-						  case_data (&c, var->fv),
+						  case_data (&c, var),
 						  var_get_width (var)
 						  );
 
@@ -774,7 +774,7 @@ run_examine (const struct ccase *first, 
 	{
 	  const struct variable *var = dependent_vars[v];
 	  union value *val = value_dup (
-					case_data (&c, var->fv),
+					case_data (&c, var),
 					var_get_width (var)
 					);
 
@@ -1059,8 +1059,8 @@ show_summary (struct variable **dependen
 			    (i * n_factors ) + count +
 			    heading_rows,
 			    TAB_LEFT | TAT_TITLE,
-			    value_to_string ((*fs)->id[0],
-					     fctr->indep_var[0])
+			    var_get_value_name (fctr->indep_var[0],
+                                                (*fs)->id[0])
 			    );
 
 		  if (fctr->indep_var[1] && count > 0 )
@@ -1078,7 +1078,7 @@ show_summary (struct variable **dependen
 			  (i * n_factors ) + count +
 			  heading_rows,
 			  TAB_LEFT | TAT_TITLE,
-			  value_to_string ((*fs)->id[1], fctr->indep_var[1])
+			  var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
 			  );
 
 	      populate_summary (tbl, heading_columns,
@@ -1234,7 +1234,8 @@ show_extremes (struct variable **depende
 		  tab_text (tbl,
 			    1, row,
 			    TAB_LEFT | TAT_TITLE,
-			    value_to_string ((*fs)->id[0], fctr->indep_var[0])
+			    var_get_value_name (fctr->indep_var[0],
+                                                (*fs)->id[0])
 			    );
 		}
 
@@ -1246,7 +1247,7 @@ show_extremes (struct variable **depende
 	      if ( fctr->indep_var[1])
 		tab_text (tbl, 2, row,
 			  TAB_LEFT | TAT_TITLE,
-			  value_to_string ((*fs)->id[1], fctr->indep_var[1])
+			  var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
 			  );
 
 	      populate_extremes (tbl, heading_columns - 2,
@@ -1471,7 +1472,8 @@ show_descriptives (struct variable **dep
 		  tab_text (tbl,
 			    1, row,
 			    TAB_LEFT | TAT_TITLE,
-			    value_to_string ((*fs)->id[0], fctr->indep_var[0])
+			    var_get_value_name (fctr->indep_var[0],
+                                                (*fs)->id[0])
 			    );
 		}
 
@@ -1483,7 +1485,7 @@ show_descriptives (struct variable **dep
 	      if ( fctr->indep_var[1])
 		tab_text (tbl, 2, row,
 			  TAB_LEFT | TAT_TITLE,
-			  value_to_string ((*fs)->id[1], fctr->indep_var[1])
+			  var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
 			  );
 
 	      populate_descriptives (tbl, heading_columns - 2,
@@ -2097,7 +2099,8 @@ show_percentiles (struct variable **depe
 		  tab_text (tbl,
 			    1, row,
 			    TAB_LEFT | TAT_TITLE,
-			    value_to_string ((*fs)->id[0], fctr->indep_var[0])
+			    var_get_value_name (fctr->indep_var[0],
+                                                (*fs)->id[0])
 			    );
 
 
@@ -2111,7 +2114,7 @@ show_percentiles (struct variable **depe
 	      if ( fctr->indep_var[1])
 		tab_text (tbl, 2, row,
 			  TAB_LEFT | TAT_TITLE,
-			  value_to_string ((*fs)->id[1], fctr->indep_var[1])
+			  var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
 			  );
 
 
@@ -2213,7 +2216,7 @@ factor_to_string (const struct factor *f
 
   snprintf (buf2, 100, "%s = %s",
 	   var_to_string (fctr->indep_var[0]),
-	   value_to_string (fs->id[0], fctr->indep_var[0]));
+           var_get_value_name (fctr->indep_var[0], fs->id[0]));
 
   strcat (buf1, buf2);
 
@@ -2221,8 +2224,7 @@ factor_to_string (const struct factor *f
     {
       sprintf (buf2, "; %s = %s)",
 	      var_to_string (fctr->indep_var[1]),
-	      value_to_string (fs->id[1],
-			      fctr->indep_var[1]));
+              var_get_value_name (fctr->indep_var[1], fs->id[1]));
       strcat (buf1, buf2);
     }
   else
@@ -2247,11 +2249,12 @@ factor_to_string_concise (const struct f
   char buf2[100];
 
   snprintf (buf, 100, "%s",
-	   value_to_string (fs->id[0], fctr->indep_var[0]));
+            var_get_value_name (fctr->indep_var[0], fs->id[0]));
 
   if ( fctr->indep_var[1] )
     {
-      sprintf (buf2, ",%s)", value_to_string (fs->id[1], fctr->indep_var[1]) );
+      sprintf (buf2, ",%s)", var_get_value_name (fctr->indep_var[1],
+                                                 fs->id[1]) );
       strcat (buf, buf2);
     }
 
Index: src/language/stats/flip.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/flip.c,v
retrieving revision 1.16
diff -u -p -r1.16 flip.c
--- src/language/stats/flip.c	5 Dec 2006 15:10:21 -0000	1.16
+++ src/language/stats/flip.c	10 Dec 2006 03:30:35 -0000
@@ -104,7 +104,7 @@ cmd_flip (struct lexer *lexer, struct da
 
   flip = pool_create_container (struct flip_pgm, pool);
   flip->var = NULL;
-  flip->idx_to_fv = dict_get_compacted_idx_to_fv (dict);
+  flip->idx_to_fv = dict_get_compacted_dict_index_to_case_index (dict);
   pool_register (flip->pool, free, flip->idx_to_fv);
   flip->var_cnt = 0;
   flip->case_cnt = 0;
@@ -327,10 +327,11 @@ flip_sink_write (struct case_sink *sink,
   if (flip->new_names != NULL)
     {
       struct varname *v = pool_alloc (flip->pool, sizeof *v);
+      int fv = flip->idx_to_fv[var_get_dict_index (flip->new_names)];
       v->next = NULL;
       if (var_is_numeric (flip->new_names))
         {
-          double f = case_num (c, flip->idx_to_fv[flip->new_names->index]);
+          double f = case_num_idx (c, fv);
 
           if (f == SYSMIS)
             strcpy (v->name, "VSYSMIS");
@@ -344,8 +345,7 @@ flip_sink_write (struct case_sink *sink,
       else
 	{
 	  int width = MIN (var_get_width (flip->new_names), MAX_SHORT_STRING);
-	  memcpy (v->name, case_str (c, flip->idx_to_fv[flip->new_names->index]),
-                  width);
+	  memcpy (v->name, case_str_idx (c, fv), width);
 	  v->name[width] = 0;
 	}
       
@@ -361,8 +361,11 @@ flip_sink_write (struct case_sink *sink,
     {
       double out;
       
-      if (var_is_numeric (flip->var[i]))
-        out = case_num (c, flip->idx_to_fv[flip->var[i]->index]);
+      if (var_is_numeric (flip->var[i])) 
+        {
+          int fv = flip->idx_to_fv[var_get_dict_index (flip->var[i])];
+          out = case_num_idx (c, fv); 
+        }
       else
         out = SYSMIS;
       flip->output_buf[i].f = out;
@@ -547,7 +550,7 @@ flip_source_read (struct case_source *so
         }
 
       for (j = 0; j < flip->case_cnt; j++)
-        case_data_rw (c, j)->f = input_buf[j].f;
+        case_data_rw_idx (c, j)->f = input_buf[j].f;
       ok = write_case (wc_data);
     }
   free (input_buf);
Index: src/language/stats/frequencies.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/frequencies.q,v
retrieving revision 1.24
diff -u -p -r1.24 frequencies.q
--- src/language/stats/frequencies.q	5 Dec 2006 15:10:21 -0000	1.24
+++ src/language/stats/frequencies.q	10 Dec 2006 03:30:36 -0000
@@ -31,6 +31,7 @@
 
 #include <data/case.h>
 #include <data/dictionary.h>
+#include <data/format.h>
 #include <data/procedure.h>
 #include <data/settings.h>
 #include <data/value-labels.h>
@@ -269,9 +270,7 @@ struct var_freqs
 static inline struct var_freqs *
 get_var_freqs (const struct variable *v)
 {
-  assert (v != NULL);
-  assert (v->aux != NULL);
-  return v->aux;
+  return var_get_aux (v);
 }
 
 static void determine_charts (void);
@@ -516,7 +515,7 @@ calc (const struct ccase *c, void *aux U
   for (i = 0; i < n_variables; i++)
     {
       const struct variable *v = v_variables[i];
-      const union value *val = case_data (c, v->fv);
+      const union value *val = case_data (c, v);
       struct var_freqs *vf = get_var_freqs (v);
       struct freq_tab *ft = &vf->tab;
 
@@ -695,23 +694,22 @@ postcalc (void *aux UNUSED, const struct
    sorting a frequency table by FRQ_SORT using VAR_TYPE
    variables. */
 static hsh_compare_func *
-get_freq_comparator (int frq_sort, int var_type) 
+get_freq_comparator (int frq_sort, enum var_type var_type) 
 {
-  /* Note that q2c generates tags beginning with 1000. */
-  switch (frq_sort | (var_type << 16))
+  bool is_numeric = var_type == VAR_NUMERIC;
+  switch (frq_sort)
     {
-    case FRQ_AVALUE | (NUMERIC << 16):  return compare_value_numeric_a;
-    case FRQ_AVALUE | (ALPHA << 16):    return compare_value_alpha_a;
-    case FRQ_DVALUE | (NUMERIC << 16):  return compare_value_numeric_d;
-    case FRQ_DVALUE | (ALPHA << 16):    return compare_value_alpha_d;
-    case FRQ_AFREQ | (NUMERIC << 16):   return compare_freq_numeric_a;
-    case FRQ_AFREQ | (ALPHA << 16):     return compare_freq_alpha_a;
-    case FRQ_DFREQ | (NUMERIC << 16):   return compare_freq_numeric_d;
-    case FRQ_DFREQ | (ALPHA << 16):     return compare_freq_alpha_d;
-    default: NOT_REACHED ();
+    case FRQ_AVALUE:
+      return is_numeric ? compare_value_numeric_a : compare_value_alpha_a;
+    case FRQ_DVALUE:
+      return is_numeric ? compare_value_numeric_d : compare_value_alpha_d;
+    case FRQ_AFREQ:
+      return is_numeric ? compare_freq_numeric_a : compare_freq_alpha_a;
+    case FRQ_DFREQ:
+      return is_numeric ? compare_freq_numeric_d : compare_freq_alpha_d;
+    default:
+      NOT_REACHED ();
     }
-
-  return 0;
 }
 
 /* Returns true iff the value in struct freq F is non-missing
@@ -840,7 +838,7 @@ frq_custom_variables (struct lexer *lexe
       struct variable *v = v_variables[i];
       struct var_freqs *vf;
 
-      if (v->aux != NULL)
+      if (var_get_aux (v) != NULL)
 	{
 	  msg (SE, _("Variable %s specified multiple times on VARIABLES "
 		     "subcommand."), var_get_name (v));
@@ -933,7 +931,7 @@ frq_custom_grouped (struct lexer *lexer,
           }
 
 	for (i = 0; i < n; i++)
-          if (v[i]->aux == NULL)
+          if (var_get_aux (v[i]) == NULL)
             msg (SE, _("Variables %s specified on GROUPED but not on "
                        "VARIABLES."), var_get_name (v[i]));
           else 
@@ -1217,7 +1215,7 @@ dump_full (struct variable *v)
 
       if (lab)
 	{
-	  const char *label = val_labs_find (v->val_labs, f->v[0]);
+	  const char *label = var_lookup_value_label (v, &f->v[0]);
 	  if (label != NULL)
 	    tab_text (t, 0, r, TAB_LEFT, label);
 	}
@@ -1235,7 +1233,7 @@ dump_full (struct variable *v)
 
       if (lab)
 	{
-	  const char *label = val_labs_find (v->val_labs, f->v[0]);
+	  const char *label = var_lookup_value_label (v, &f->v[0]);
 	  if (label != NULL)
 	    tab_text (t, 0, r, TAB_LEFT, label);
 	}
@@ -1643,7 +1641,7 @@ freq_tab_to_slice_array(const struct fre
     {
       const struct freq *frq = &frq_tab->valid[i];
 
-      slices[i].label = value_to_string(frq->v, var);
+      slices[i].label = var_get_value_name (var, frq->v);
 
       slices[i].magnetude = frq->c;
     }
Index: src/language/stats/oneway.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/oneway.q,v
retrieving revision 1.16
diff -u -p -r1.16 oneway.q
--- src/language/stats/oneway.q	5 Dec 2006 15:10:21 -0000	1.16
+++ src/language/stats/oneway.q	10 Dec 2006 03:30:36 -0000
@@ -435,7 +435,8 @@ show_descriptives(void)
 	  gs = gs_array[count];
 
 	  tab_text (t, 1, row + count, 
-		    TAB_LEFT | TAT_TITLE ,value_to_string(&gs->id,indep_var));
+		    TAB_LEFT | TAT_TITLE, var_get_value_name(indep_var,
+                                                             &gs->id));
 
 	  /* Now fill in the numbers ... */
 
@@ -621,7 +622,7 @@ show_contrast_coeffs (short *bad_contras
       group_value = group_values[count];
 
       tab_text (t, count + 2, 1, TAB_CENTER | TAT_TITLE, 
-		value_to_string(group_value, indep_var));
+		var_get_value_name (indep_var, group_value));
 
       for (i = 0 ; i < cmd.sbc_contrast ; ++i ) 
 	{
@@ -917,7 +918,7 @@ run_oneway(const struct ccase *first, co
       if ( casefilter_variable_missing (filter, &c, indep_var))
 	continue;
 
-      indep_val = case_data (&c, indep_var->fv);
+      indep_val = case_data (&c, indep_var);
 	  
       hsh_insert ( global_group_hash, (void *) indep_val );
 
@@ -925,7 +926,7 @@ run_oneway(const struct ccase *first, co
 	{
 	  const struct variable *v = vars[i];
 
-	  const union value *val = case_data (&c, v->fv);
+	  const union value *val = case_data (&c, v);
 
           struct group_proc *gp = group_proc_get (vars[i]);
 	  struct hsh_table *group_hash = gp->group_hash;
Index: src/language/stats/rank.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/rank.q,v
retrieving revision 1.20
diff -u -p -r1.20 rank.q
--- src/language/stats/rank.q	5 Dec 2006 15:10:21 -0000	1.20
+++ src/language/stats/rank.q	10 Dec 2006 03:30:37 -0000
@@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fi
 #include "sort-criteria.h"
 
 #include <data/dictionary.h>
+#include <data/format.h>
+#include <data/missing-values.h>
 #include <data/procedure.h>
 #include <data/variable.h>
 #include <data/case.h>
@@ -247,13 +249,13 @@ rank_cmd (struct dataset *ds, const stru
   for (i = 0; i < n_splits ; i++) 
     {
       struct variable *v = dict_get_split_vars (dataset_dict (ds))[i];
-      criteria.crits[i].fv = v->fv;
+      criteria.crits[i].fv = var_get_case_index (v);
       criteria.crits[i].width = var_get_width (v);
       criteria.crits[i].dir = SRT_ASCEND;
     }
   for (i = 0; i < n_group_vars; i++) 
     {
-      criteria.crits[i + n_splits].fv = group_vars[i]->fv;
+      criteria.crits[i + n_splits].fv = var_get_case_index (group_vars[i]);
       criteria.crits[i + n_splits].width = var_get_width (group_vars[i]);
       criteria.crits[i + n_splits].dir = SRT_ASCEND;
     }
@@ -273,7 +275,7 @@ rank_cmd (struct dataset *ds, const stru
       /* Sort CF into SORTED_CF. */
       reader = casefile_get_destructive_reader (cf) ;
       criteria.crits[criteria.crit_cnt - 1] = sc->crits[i];
-      assert ( sc->crits[i].fv == src_vars[i]->fv );
+      assert ( sc->crits[i].fv == var_get_case_index (src_vars[i]) );
       sorted_cf = sort_execute (reader, &criteria);
       casefile_destroy (cf);
 
@@ -519,7 +521,7 @@ rank_cases (struct casereader *cr,
       if (!casereader_read_xfer (cr, &this_case))
         break;
       
-      this_value = case_data (&this_case, fv);
+      this_value = case_data_idx (&this_case, fv);
       c = dict_get_case_weight (dict, &this_case, &warn);
               
       lookahead = casereader_clone (cr);
@@ -527,7 +529,7 @@ rank_cases (struct casereader *cr,
       while (casereader_cnum (lookahead) < end
              && casereader_read_xfer (lookahead, &lookahead_case))
         {
-          const union value *lookahead_value = case_data (&lookahead_case, fv);
+          const union value *lookahead_value = case_data_idx (&lookahead_case, fv);
           int diff = compare_values (this_value, lookahead_value, width);
 
           if (diff != 0) 
@@ -553,12 +555,12 @@ rank_cases (struct casereader *cr,
         {
           for (i = 0; i < n_rank_specs; ++i) 
             {
-              const int dest_idx = rs[i].destvars[dest_var_index]->fv;
+              const struct variable *dst_var = rs[i].destvars[dest_var_index];
 
 	      if  ( value_is_missing (mv, this_value) )
-		case_data_rw (&this_case, dest_idx)->f = SYSMIS;
+		case_data_rw (&this_case, dst_var)->f = SYSMIS;
 	      else
-		case_data_rw (&this_case, dest_idx)->f = 
+		case_data_rw (&this_case, dst_var)->f = 
 		  rank_func[rs[i].rfunc](c, cc, cc_1, iter, w);
             }
           casefile_append_xfer (dest, &this_case); 
@@ -582,8 +584,8 @@ same_group (const struct ccase *a, const
   for (i = 0; i < crit->crit_cnt - 1; i++)
     {
       struct sort_criterion *c = &crit->crits[i];
-      if (compare_values (case_data (a, c->fv), case_data (b, c->fv),
-                          c->width) != 0)
+      if (compare_values (case_data_idx (a, c->fv),
+                          case_data_idx (b, c->fv), c->width) != 0)
         return false;
     }
 
@@ -612,7 +614,7 @@ rank_sorted_casefile (struct casefile *c
       struct ccase this_case;
       const union value *this_value ;
       double w = 0.0;
-      this_value = case_data( &group_case, ultimate_crit->fv);
+      this_value = case_data_idx( &group_case, ultimate_crit->fv);
 
       if ( !value_is_missing(mv, this_value) )
 	w = dict_get_case_weight (dict, &group_case, &warn);
@@ -620,7 +622,7 @@ rank_sorted_casefile (struct casefile *c
       while (casereader_read (lookahead, &this_case)) 
         {
 	  const union value *this_value = 
-	    case_data(&this_case, ultimate_crit->fv);
+	    case_data_idx(&this_case, ultimate_crit->fv);
           double c = dict_get_case_weight (dict, &this_case, &warn);
           if (!same_group (&group_case, &this_case, crit)) 
             {
@@ -661,7 +663,7 @@ create_resort_key (void *key_var_, struc
 {
   struct variable *key_var = key_var_;
 
-  case_data_rw(cc, key_var->fv)->f = case_num;
+  case_data_rw(cc, key_var)->f = case_num;
   
   return TRNS_CONTINUE;
 }
@@ -907,7 +909,7 @@ cmd_rank (struct lexer *lexer, struct da
   {
     struct sort_criteria criteria;
     struct sort_criterion restore_criterion ;
-    restore_criterion.fv = order->fv;
+    restore_criterion.fv = var_get_case_index (order);
     restore_criterion.width = 0;
     restore_criterion.dir = SRT_ASCEND;
 
Index: src/language/stats/regression.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/regression.q,v
retrieving revision 1.40
diff -u -p -r1.40 regression.q
--- src/language/stats/regression.q	7 Dec 2006 05:16:33 -0000	1.40
+++ src/language/stats/regression.q	10 Dec 2006 03:30:38 -0000
@@ -239,7 +239,7 @@ reg_stats_coeff (pspp_linreg_cache * c)
 	   */
 
 	  val = pspp_coeff_get_value (c->coeff[j], v);
-	  val_s = value_to_string (val, v);
+	  val_s = var_get_value_name (v, val);
 	  strncat (tmp, val_s, MAX_STRING);
 	}
 
@@ -566,12 +566,12 @@ regression_trns_pred_proc (void *t_, str
   n_vals = (*model->get_vars) (model, vars);
 
   vals = xnmalloc (n_vals, sizeof (*vals));
-  output = case_data_rw (c, model->pred->fv);
+  output = case_data_rw (c, model->pred);
   assert (output != NULL);
 
   for (i = 0; i < n_vals; i++)
     {
-      vals[i] = case_data (c, vars[i]->fv);
+      vals[i] = case_data (c, vars[i]);
     }
   output->f = (*model->predict) ((const struct variable **) vars,
 				 vals, model, n_vals);
@@ -606,14 +606,14 @@ regression_trns_resid_proc (void *t_, st
   n_vals = (*model->get_vars) (model, vars);
 
   vals = xnmalloc (n_vals, sizeof (*vals));
-  output = case_data_rw (c, model->resid->fv);
+  output = case_data_rw (c, model->resid);
   assert (output != NULL);
 
   for (i = 0; i < n_vals; i++)
     {
-      vals[i] = case_data (c, vars[i]->fv);
+      vals[i] = case_data (c, vars[i]);
     }
-  obs = case_data (c, model->depvar->fv);
+  obs = case_data (c, model->depvar);
   output->f = (*model->residual) ((const struct variable **) vars,
 				  vals, obs, model, n_vals);
   free (vals);
@@ -734,20 +734,16 @@ static void
 reg_print_categorical_encoding (FILE * fp, pspp_linreg_cache * c)
 {
   int i;
-  size_t j;
   int n_vars = 0;
   struct variable **varlist;
-  struct pspp_coeff *coeff;
-  const struct variable *v;
-  union value *val;
 
   fprintf (fp, "%s", reg_export_categorical_encode_1);
 
   varlist = xnmalloc (c->n_indeps, sizeof (*varlist));
   for (i = 1; i < c->n_indeps; i++)	/* c->coeff[0] is the intercept. */
     {
-      coeff = c->coeff[i];
-      v = pspp_coeff_get_var (coeff, 0);
+      struct pspp_coeff *coeff = c->coeff[i];
+      const struct variable *v = pspp_coeff_get_var (coeff, 0);
       if (var_is_alpha (v))
 	{
 	  if (!reg_inserted (v, varlist, n_vars))
@@ -770,20 +766,22 @@ reg_print_categorical_encoding (FILE * f
 
   for (i = 0; i < n_vars; i++)
     {
-      coeff = c->coeff[i];
+      size_t n_categories = cat_get_n_categories (varlist[i]);
+      size_t j;
+      
       fprintf (fp, "%s.name = \"%s\";\n\t",
                var_get_name (varlist[i]),
 	       var_get_name (varlist[i]));
       fprintf (fp, "%s.n_vals = %d;\n\t",
                var_get_name (varlist[i]),
-	       varlist[i]->obs_vals->n_categories);
+               n_categories);
 
-      for (j = 0; j < varlist[i]->obs_vals->n_categories; j++)
+      for (j = 0; j < n_categories; j++)
 	{
-	  val = cat_subscript_to_value ((const size_t) j, varlist[i]);
+          union value *val = cat_subscript_to_value (j, varlist[i]);
 	  fprintf (fp, "%s.values[%d] = \"%s\";\n\t",
                    var_get_name (varlist[i]), j,
-		   value_to_string (val, varlist[i]));
+		   var_get_value_name (varlist[i], val));
 	}
     }
   fprintf (fp, "%s", reg_export_categorical_encode_2);
@@ -959,14 +957,7 @@ cmd_regression (struct lexer *lexer, str
 static bool
 is_depvar (size_t k, const struct variable *v)
 {
-  /*
-     compare_var_names returns 0 if the variable
-     names match.
-   */
-  if (!compare_var_names (v, v_variables[k], NULL))
-    return true;
-
-  return false;
+  return v == v_variables[k];
 }
 
 /*
@@ -986,7 +977,7 @@ mark_missing_cases (const struct casefil
     {
       row = casereader_cnum (r) - 1;
 
-      val = case_data (&c, v->fv);
+      val = case_data (&c, v);
       cat_value_update (v, val);
       if (var_is_value_missing (v, val))
 	{
@@ -1199,7 +1190,7 @@ run_regression (const struct ccase *firs
 						   current case.
 						 */
 		{
-		  val = case_data (&c, v_variables[i]->fv);
+		  val = case_data (&c, v_variables[i]);
 		  /*
 		     Independent/dependent variable separation. The
 		     'variables' subcommand specifies a varlist which contains
@@ -1222,7 +1213,7 @@ run_regression (const struct ccase *firs
 			}
 		    }
 		}
-	      val = case_data (&c, cmd.v_dependent[k]->fv);
+	      val = case_data (&c, cmd.v_dependent[k]);
 	      gsl_vector_set (Y, row, val->f);
 	      row++;
 	    }
Index: src/language/stats/sort-criteria.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/sort-criteria.c,v
retrieving revision 1.5
diff -u -p -r1.5 sort-criteria.c
--- src/language/stats/sort-criteria.c	5 Dec 2006 15:10:21 -0000	1.5
+++ src/language/stats/sort-criteria.c	10 Dec 2006 03:30:38 -0000
@@ -115,7 +115,7 @@ sort_parse_criteria (struct lexer *lexer
       for (; prev_var_cnt < criteria->crit_cnt; prev_var_cnt++) 
         {
           struct sort_criterion *c = &criteria->crits[prev_var_cnt];
-          c->fv = (*vars)[prev_var_cnt]->fv;
+          c->fv = var_get_case_index ((*vars)[prev_var_cnt]);
           c->width = var_get_width ((*vars)[prev_var_cnt]);
           c->dir = direction;
         }
Index: src/language/stats/t-test.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/t-test.q,v
retrieving revision 1.16
diff -u -p -r1.16 t-test.q
--- src/language/stats/t-test.q	5 Dec 2006 15:10:21 -0000	1.16
+++ src/language/stats/t-test.q	10 Dec 2006 03:30:39 -0000
@@ -154,7 +154,7 @@ struct pair 
 
 static struct pair *pairs=0;
 
-static int parse_value (struct lexer *lexer, union value * v, int type) ;
+static int parse_value (struct lexer *lexer, union value * v, enum var_type);
 
 /* Structures and Functions for the Statistics Summary Box */
 struct ssbox;
@@ -309,7 +309,8 @@ cmd_t_test (struct lexer *lexer, struct 
 	  struct hsh_table *hash;
 	  struct variable *v;
 
-	  hash = hsh_create (n_pairs, compare_var_names, hash_var_name, 0, 0);
+	  hash = hsh_create (n_pairs, compare_vars_by_name, hash_var_by_name,
+          0, 0);
 
 	  for (i=0; i < n_pairs; ++i)
 	    {
@@ -565,9 +566,9 @@ tts_custom_pairs (struct lexer *lexer, s
 /* Parses the current token (numeric or string, depending on type)
     value v and returns success. */
 static int
-parse_value (struct lexer *lexer, union value * v, int type )
+parse_value (struct lexer *lexer, union value * v, enum var_type type)
 {
-  if (type == NUMERIC)
+  if (type == VAR_NUMERIC)
     {
       if (!lex_force_num (lexer))
 	return 0;
@@ -716,16 +717,16 @@ ssbox_independent_samples_populate(struc
 {
   int i;
 
-  char *val_lab0=0;
-  char *val_lab1=0;
+  const char *val_lab0;
+  const char *val_lab1;
   double indep_value[2];
 
   char prefix[2][3]={"",""};
 
   if ( var_is_numeric (indep_var) ) 
     {
-      val_lab0 = val_labs_find( indep_var->val_labs,gp.v.g_value[0]); 
-      val_lab1 = val_labs_find( indep_var->val_labs,gp.v.g_value[1]);
+      val_lab0 = var_lookup_value_label (indep_var, &gp.v.g_value[0]); 
+      val_lab1 = var_lookup_value_label (indep_var, &gp.v.g_value[1]);
     }
   else
     {
@@ -1435,7 +1436,7 @@ common_calc (const struct dictionary *di
       if (! casefilter_variable_missing (filter, c, v) )
 	{
 	  struct group_statistics *gs;
-	  const union value *val = case_data (c, v->fv);
+	  const union value *val = case_data (c, v);
 	  gs = &group_proc_get (cmd->v_variables[i])->ugs;
 
 	  gs->n += weight;
@@ -1507,7 +1508,7 @@ one_sample_calc (const struct dictionary
     {
       struct group_statistics *gs;
       struct variable *v = cmd->v_variables[i];
-      const union value *val = case_data (c, v->fv);
+      const union value *val = case_data (c, v);
 
       gs= &group_proc_get (cmd->v_variables[i])->ugs;
 
@@ -1582,8 +1583,8 @@ paired_calc (const struct dictionary *di
       struct variable *v0 = pairs[i].v[0];
       struct variable *v1 = pairs[i].v[1];
 
-      const union value *val0 = case_data (c, v0->fv);
-      const union value *val1 = case_data (c, v1->fv);
+      const union value *val0 = case_data (c, v0);
+      const union value *val1 = case_data (c, v1);
 
       if (  ! casefilter_variable_missing (filter, c, v0) && 
 	    ! casefilter_variable_missing (filter, c, v1) )
@@ -1708,12 +1709,12 @@ group_calc (const struct dictionary *dic
   if ( casefilter_variable_missing (filter, c, indep_var))
     return 0;
 
-  gv = case_data (c, indep_var->fv);
+  gv = case_data (c, indep_var);
 
   for(i=0; i< cmd->n_variables ; ++i) 
     {
       struct variable *var = cmd->v_variables[i];
-      const union value *val = case_data (c, var->fv);
+      const union value *val = case_data (c, var);
       struct hsh_table *grp_hash = group_proc_get (var)->group_hash;
       struct group_statistics *gs;
 
Index: src/language/tests/casefile-test.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/tests/casefile-test.c,v
retrieving revision 1.9
diff -u -p -r1.9 casefile-test.c
--- src/language/tests/casefile-test.c	11 Nov 2006 23:10:00 -0000	1.9
+++ src/language/tests/casefile-test.c	10 Dec 2006 03:30:39 -0000
@@ -160,8 +160,8 @@ test_casefile (int pattern, size_t value
             fail_test ("Premature end of casefile.");
           for (j = 0; j < value_cnt; j++) 
             {
-              double a = case_num (&read_case, j);
-              double b = case_num (&expected_case, j);
+              double a = case_num_idx (&read_case, j);
+              double b = case_num_idx (&expected_case, j);
               if (a != b)
                 fail_test ("Case %lu fails comparison.", (unsigned long) i); 
             }
@@ -180,7 +180,7 @@ get_random_case (struct ccase *c, size_t
   int i;
   case_create (c, value_cnt);
   for (i = 0; i < value_cnt; i++)
-    case_data_rw (c, i)->f = case_idx % 257 + i;
+    case_data_rw_idx (c, i)->f = case_idx % 257 + i;
 }
 
 static void
@@ -205,8 +205,8 @@ read_and_verify_random_case (struct case
     fail_test ("Premature end of casefile.");
   for (i = 0; i < value_cnt; i++) 
     {
-      double a = case_num (&read_case, i);
-      double b = case_num (&expected_case, i);
+      double a = case_num_idx (&read_case, i);
+      double b = case_num_idx (&expected_case, i);
       if (a != b)
         fail_test ("Case %lu fails comparison.", (unsigned long) case_idx); 
     }
Index: src/language/utilities/set.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/utilities/set.q,v
retrieving revision 1.23
diff -u -p -r1.23 set.q
--- src/language/utilities/set.q	5 Dec 2006 15:10:21 -0000	1.23
+++ src/language/utilities/set.q	10 Dec 2006 03:30:40 -0000
@@ -30,6 +30,7 @@
 #include <data/format.h>
 #include <data/procedure.h>
 #include <data/settings.h>
+#include <data/value.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/lexer/format-parser.h>
Index: src/language/xforms/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/xforms/ChangeLog,v
retrieving revision 1.7
diff -u -p -r1.7 ChangeLog
--- src/language/xforms/ChangeLog	1 Dec 2006 06:51:08 -0000	1.7
+++ src/language/xforms/ChangeLog	10 Dec 2006 03:30:40 -0000
@@ -1,3 +1,8 @@
+Sat Dec  9 18:48:20 2006  Ben Pfaff  <blp@gnu.org>
+
+	* compute.c (struct compute_trns): Remove `fv' member, which was
+	redundant with `variable'.
+
 Thu Nov 30 22:46:50 2006  Ben Pfaff  <blp@gnu.org>
 
 	* compute.c: Fix bug #17422, which reports that a variable created
Index: src/language/xforms/compute.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/xforms/compute.c,v
retrieving revision 1.12
diff -u -p -r1.12 compute.c
--- src/language/xforms/compute.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/xforms/compute.c	10 Dec 2006 03:30:40 -0000
@@ -26,6 +26,7 @@
 #include <data/procedure.h>
 #include <data/transformations.h>
 #include <data/variable.h>
+#include <data/vector.h>
 #include <language/command.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
@@ -58,7 +59,6 @@ struct compute_trns
 
     /* Variable lvalue, if variable != NULL. */
     struct variable *variable;   /* Destination variable, if any. */
-    int fv;			 /* `value' index of destination variable. */
     int width;			 /* Lvalue string width; 0=numeric. */
 
     /* Vector lvalue, if vector != NULL. */
@@ -120,8 +120,8 @@ compute_num (void *compute_, struct ccas
 
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
-    case_data_rw (c, compute->fv)->f = expr_evaluate_num (compute->rvalue, c,
-                                                          case_num); 
+    case_data_rw (c, compute->variable)->f
+      = expr_evaluate_num (compute->rvalue, c, case_num); 
   
   return TRNS_CONTINUE;
 }
@@ -141,18 +141,20 @@ compute_num_vec (void *compute_, struct 
 
       index = expr_evaluate_num (compute->element, c, case_num);
       rindx = floor (index + EPSILON);
-      if (index == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
+      if (index == SYSMIS
+          || rindx < 1 || rindx > vector_get_var_cnt (compute->vector))
         {
           if (index == SYSMIS)
-            msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value as "
-                       "an index into vector %s."), compute->vector->name);
+            msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value "
+                       "as an index into vector %s."),
+                 vector_get_name (compute->vector));
           else
             msg (SW, _("When executing COMPUTE: %g is not a valid value as "
                        "an index into vector %s."),
-                 index, compute->vector->name);
+                 index, vector_get_name (compute->vector));
           return TRNS_CONTINUE;
         }
-      case_data_rw (c, compute->vector->var[rindx - 1]->fv)->f
+      case_data_rw (c, vector_get_var (compute->vector, rindx - 1))->f
         = expr_evaluate_num (compute->rvalue, c, case_num);
     }
   
@@ -168,7 +170,7 @@ compute_str (void *compute_, struct ccas
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
     expr_evaluate_str (compute->rvalue, c, case_num,
-                       case_data_rw (c, compute->fv)->s, compute->width);
+                       case_data_rw (c, compute->variable)->s, compute->width);
   
   return TRNS_CONTINUE;
 }
@@ -193,20 +195,21 @@ compute_str_vec (void *compute_, struct 
         {
           msg (SW, _("When executing COMPUTE: SYSMIS is not a valid "
                      "value as an index into vector %s."),
-               compute->vector->name);
+               vector_get_name (compute->vector));
           return TRNS_CONTINUE; 
         }
-      else if (rindx < 1 || rindx > compute->vector->cnt)
+      else if (rindx < 1 || rindx > vector_get_var_cnt (compute->vector))
         {
           msg (SW, _("When executing COMPUTE: %g is not a valid value as "
                      "an index into vector %s."),
-               index, compute->vector->name);
+               index, vector_get_name (compute->vector));
           return TRNS_CONTINUE;
         }
 
-      vr = compute->vector->var[rindx - 1];
+      vr = vector_get_var (compute->vector, rindx - 1);
       expr_evaluate_str (compute->rvalue, c, case_num,
-                         case_data_rw (c, vr->fv)->s, var_get_width (vr));
+                         case_data_rw (c, vr)->s,
+                         var_get_width (vr));
     }
   
   return TRNS_CONTINUE;
@@ -257,7 +260,7 @@ cmd_if (struct lexer *lexer, struct data
 static trns_proc_func *
 get_proc_func (const struct lvalue *lvalue) 
 {
-  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
+  bool is_numeric = lvalue_get_type (lvalue) == VAR_NUMERIC;
   bool is_vector = lvalue_is_vector (lvalue);
 
   return (is_numeric
@@ -271,7 +274,7 @@ static struct expression *
 parse_rvalue (struct lexer *lexer, 
 	      const struct lvalue *lvalue, struct dataset *ds)
 {
-  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
+  bool is_numeric = lvalue_get_type (lvalue) == VAR_NUMERIC;
 
   return expr_parse (lexer, ds, is_numeric ? EXPR_NUMBER : EXPR_STRING);
 }
@@ -380,7 +383,7 @@ lvalue_get_type (const struct lvalue *lv
 {
   return (lvalue->variable != NULL
           ? var_get_type (lvalue->variable)
-          : var_get_type (lvalue->vector->var[0]));
+          : vector_get_type (lvalue->vector));
 }
 
 /* Returns true if LVALUE has a vector as its target. */
@@ -400,12 +403,11 @@ lvalue_finalize (struct lvalue *lvalue, 
   if (lvalue->vector == NULL)
     {
       compute->variable = lvalue->variable;
-      compute->fv = compute->variable->fv;
       compute->width = var_get_width (compute->variable);
 
       /* Goofy behavior, but compatible: Turn off LEAVE. */
-      if (dict_class_from_id (var_get_name (compute->variable)) != DC_SCRATCH)
-        compute->variable->leave = false;
+      if (!var_must_leave (compute->variable))
+        var_set_leave (compute->variable, false);
 
       /* Prevent lvalue_destroy from deleting variable. */
       lvalue->is_new_variable = false;
Index: src/language/xforms/count.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/xforms/count.c,v
retrieving revision 1.12
diff -u -p -r1.12 count.c
--- src/language/xforms/count.c	5 Dec 2006 15:10:21 -0000	1.12
+++ src/language/xforms/count.c	10 Dec 2006 03:30:40 -0000
@@ -277,7 +277,7 @@ count_numeric (struct criteria *crit, st
 
   for (i = 0; i < crit->var_cnt; i++)
     {
-      double x = case_num (c, crit->vars[i]->fv);
+      double x = case_num (c, crit->vars[i]);
       if (x == SYSMIS)
         counter += crit->count_system_missing;
       else if (crit->count_user_missing
@@ -311,7 +311,7 @@ count_string (struct criteria *crit, str
     {
       char **v;
       for (v = crit->values.str; v < crit->values.str + crit->value_cnt; v++)
-        if (!memcmp (case_str (c, crit->vars[i]->fv), *v,
+        if (!memcmp (case_str (c, crit->vars[i]), *v,
                      var_get_width (crit->vars[i])))
           {
 	    counter++;
@@ -341,7 +341,7 @@ count_trns_proc (void *trns_, struct cca
 	  counter += count_numeric (crit, c);
 	else
 	  counter += count_string (crit, c);
-      case_data_rw (c, dv->var->fv)->f = counter;
+      case_data_rw (c, dv->var)->f = counter;
     }
   return TRNS_CONTINUE;
 }
Index: src/language/xforms/recode.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/xforms/recode.c,v
retrieving revision 1.15
diff -u -p -r1.15 recode.c
--- src/language/xforms/recode.c	5 Dec 2006 15:10:21 -0000	1.15
+++ src/language/xforms/recode.c	10 Dec 2006 03:30:41 -0000
@@ -157,7 +157,7 @@ cmd_recode (struct lexer *lexer, struct 
 
       /* Ensure that all the output strings are at least as wide
          as the widest destination variable. */
-      if (trns->dst_type == ALPHA)
+      if (trns->dst_type == VAR_STRING)
         enlarge_dst_widths (trns);
 
       /* Create destination variables, if needed.
@@ -243,7 +243,7 @@ parse_mappings (struct lexer *lexer, str
 
           if (!parse_map_out (lexer, trns->pool, &out))
             return false;
-          dst_type = out.width == 0 ? NUMERIC : ALPHA;
+          dst_type = var_type_from_width (out.width);
           if (have_dst_type && dst_type != trns->dst_type)
             {
               msg (SE, _("Inconsistent target variable types.  "
@@ -262,9 +262,9 @@ parse_mappings (struct lexer *lexer, str
           set_map_in_generic (&in, MAP_CONVERT);
           add_mapping (trns, &map_allocated, &in);
               
-          dst_type = NUMERIC;
-          if (trns->src_type != ALPHA
-              || (have_dst_type && trns->dst_type != NUMERIC)) 
+          dst_type = VAR_NUMERIC;
+          if (trns->src_type != VAR_STRING
+              || (have_dst_type && trns->dst_type != VAR_NUMERIC)) 
             {
               msg (SE, _("CONVERT requires string input values and "
                          "numeric output values."));
@@ -293,7 +293,7 @@ parse_map_in (struct lexer *lexer, struc
 {
   if (lex_match_id (lexer, "ELSE"))
     set_map_in_generic (in, MAP_ELSE);
-  else if (src_type == NUMERIC)
+  else if (src_type == VAR_NUMERIC)
     {
       if (lex_match_id (lexer, "MISSING"))
         set_map_in_generic (in, MAP_MISSING);
@@ -446,7 +446,7 @@ parse_dst_vars (struct lexer *lexer, str
         {
           struct variable *v;
           v = trns->dst_vars[i] = dict_lookup_var (dict, trns->dst_names[i]);
-          if (v == NULL && trns->dst_type == ALPHA) 
+          if (v == NULL && trns->dst_type == VAR_STRING) 
             {
               msg (SE, _("There is no variable named "
                          "%s.  (All string variables specified "
@@ -465,8 +465,8 @@ parse_dst_vars (struct lexer *lexer, str
         {
           msg (SE, _("INTO is required with %s input values "
                      "and %s output values."),
-               var_type_adj (trns->src_type),
-               var_type_adj (trns->dst_type));
+               trns->src_type == VAR_NUMERIC ? _("numeric") : _("string"),
+               trns->dst_type == VAR_NUMERIC ? _("numeric") : _("string"));
           return false;
         }
     }
@@ -478,7 +478,7 @@ parse_dst_vars (struct lexer *lexer, str
         {
           msg (SE, _("Type mismatch.  Cannot store %s data in "
                      "%s variable %s."),
-               trns->dst_type == ALPHA ? _("string") : _("numeric"),
+               trns->dst_type == VAR_STRING ? _("string") : _("numeric"),
                var_is_alpha (v) ? _("string") : _("numeric"),
                var_get_name (v));
           return false;
@@ -628,17 +628,17 @@ recode_trns_proc (void *trns_, struct cc
       struct variable *src_var = trns->src_vars[i];
       struct variable *dst_var = trns->dst_vars[i];
 
-      const union value *src_data = case_data (c, src_var->fv);
-      union value *dst_data = case_data_rw (c, dst_var->fv);
+      const union value *src_data = case_data (c, src_var);
+      union value *dst_data = case_data_rw (c, dst_var);
 
       const struct map_out *out;
 
-      if (trns->src_type == NUMERIC) 
+      if (trns->src_type == VAR_NUMERIC) 
           out = find_src_numeric (trns, src_data->f, src_var);
       else
           out = find_src_string (trns, src_data->s, var_get_width (src_var));
 
-      if (trns->dst_type == NUMERIC) 
+      if (trns->dst_type == VAR_NUMERIC) 
         {
           if (out != NULL)
             dst_data->f = !out->copy_input ? out->value.f : src_data->f; 
Index: src/libpspp/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/ChangeLog,v
retrieving revision 1.44
diff -u -p -r1.44 ChangeLog
--- src/libpspp/ChangeLog	8 Dec 2006 22:24:08 -0000	1.44
+++ src/libpspp/ChangeLog	10 Dec 2006 03:30:41 -0000
@@ -1,3 +1,7 @@
+Sat Dec  9 18:48:55 2006  Ben Pfaff  <blp@gnu.org>
+
+	* misc.h (macro range): Removed, as it was unused.
+
 Sat Dec  9 07:19:01 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
 	* array.c: Removed gratuitous #include
Index: src/libpspp/misc.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/misc.h,v
retrieving revision 1.2
diff -u -p -r1.2 misc.h
--- src/libpspp/misc.h	25 Nov 2006 02:15:01 -0000	1.2
+++ src/libpspp/misc.h	10 Dec 2006 03:30:41 -0000
@@ -43,9 +43,6 @@
 #include <ieeefp.h>		/* Declares finite() under Solaris. */
 #endif
 
-/* Clamps A to be between B and C. */
-#define range(A, B, C) ((A) < (B) ? (B) : ((A) > (C) ? (C) : (A)))
-
 /* Divides nonnegative X by positive Y, rounding up. */
 #define DIV_RND_UP(X, Y) (((X) + ((Y) - 1)) / (Y))
 
Index: src/math/design-matrix.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/design-matrix.c,v
retrieving revision 1.5
diff -u -p -r1.5 design-matrix.c
--- src/math/design-matrix.c	7 Dec 2006 05:16:33 -0000	1.5
+++ src/math/design-matrix.c	10 Dec 2006 03:30:41 -0000
@@ -33,6 +33,7 @@
 #include <libpspp/message.h>
 #include <data/variable.h>
 #include <data/category.h>
+#include <data/value.h>
 
 #include <gsl/gsl_machine.h>
 #include <gsl/gsl_vector.h>
@@ -122,10 +123,10 @@ design_matrix_create (int n_variables,
 	}
       else if (var_is_alpha (v))
 	{
-	  assert (v->obs_vals != NULL);
+          struct cat_vals *obs_vals = var_get_obs_vals (v);
 	  (dm->vars + i)->last_column =
-	    (dm->vars + i)->first_column + v->obs_vals->n_categories - 2;
-	  n_cols += v->obs_vals->n_categories - 1;
+	    (dm->vars + i)->first_column + obs_vals->n_categories - 2;
+	  n_cols += obs_vals->n_categories - 1;
 	}
     }
   dm->m = gsl_matrix_calloc (n_data, n_cols);
Index: src/math/group.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/group.c,v
retrieving revision 1.3
diff -u -p -r1.3 group.c
--- src/math/group.c	15 Mar 2006 03:29:11 -0000	1.3
+++ src/math/group.c	10 Dec 2006 03:30:41 -0000
@@ -63,7 +63,11 @@ struct group_proc *
 group_proc_get (struct variable *v)
 {
   /* This is not ideal, obviously. */
-  if (v->aux == NULL) 
-    var_attach_aux (v, xmalloc (sizeof (struct group_proc)), var_dtor_free);
-  return v->aux;
+  struct group_proc *group = var_get_aux (v);
+  if (group == NULL) 
+    {
+      group = xmalloc (sizeof (struct group_proc));
+      var_attach_aux (v, group, var_dtor_free); 
+    }
+  return group;
 }
Index: src/math/levene.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/levene.c,v
retrieving revision 1.7
diff -u -p -r1.7 levene.c
--- src/math/levene.c	5 Nov 2006 00:35:44 -0000	1.7
+++ src/math/levene.c	10 Dec 2006 03:30:42 -0000
@@ -187,7 +187,7 @@ levene_calc (const struct dictionary *di
 {
   size_t i;
   bool warn = false;
-  const union value *gv = case_data (c, l->v_indep->fv);
+  const union value *gv = case_data (c, l->v_indep);
   struct group_statistics key;
   double weight = dict_get_case_weight (dict, c, &warn); 
 
@@ -198,7 +198,7 @@ levene_calc (const struct dictionary *di
       struct variable *var = l->v_dep[i];
       struct group_proc *gp = group_proc_get (var);
       double levene_z;
-      const union value *v = case_data (c, var->fv);
+      const union value *v = case_data (c, var);
       struct group_statistics *gs;
 
       gs = hsh_find(gp->group_hash,(void *) &key );
@@ -278,7 +278,7 @@ levene2_calc (const struct dictionary *d
 
   double weight = dict_get_case_weight (dict, c, &warn); 
 
-  const union value *gv = case_data (c, l->v_indep->fv);
+  const union value *gv = case_data (c, l->v_indep);
   struct group_statistics key;
 
   key.id = *gv;
@@ -287,7 +287,7 @@ levene2_calc (const struct dictionary *d
     {
       double levene_z;
       struct variable *var = l->v_dep[i] ;
-      const union value *v = case_data (c, var->fv);
+      const union value *v = case_data (c, var);
       struct group_statistics *gs;
 
       gs = hsh_find(group_proc_get (var)->group_hash,(void *) &key );
Index: src/math/sort.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/sort.c,v
retrieving revision 1.19
diff -u -p -r1.19 sort.c
--- src/math/sort.c	7 Dec 2006 06:31:04 -0000	1.19
+++ src/math/sort.c	10 Dec 2006 03:30:42 -0000
@@ -463,13 +463,14 @@ compare_record (const struct ccase *a, c
       
       if (c->width == 0)
         {
-          double af = case_num (a, c->fv);
-          double bf = case_num (b, c->fv);
+          double af = case_num_idx (a, c->fv);
+          double bf = case_num_idx (b, c->fv);
           
           result = af < bf ? -1 : af > bf;
         }
       else
-        result = memcmp (case_str (a, c->fv), case_str (b, c->fv), c->width);
+        result = memcmp (case_str_idx (a, c->fv),
+                         case_str_idx (b, c->fv), c->width);
 
       if (result != 0)
         return c->dir == SRT_ASCEND ? result : -result;
Index: src/output/table.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/output/table.c,v
retrieving revision 1.17
diff -u -p -r1.17 table.c
--- src/output/table.c	25 Nov 2006 02:15:01 -0000	1.17
+++ src/output/table.c	10 Dec 2006 03:30:43 -0000
@@ -31,7 +31,7 @@
 
 #include <data/data-out.h>
 #include <data/format.h>
-#include <data/variable.h>
+#include <data/value.h>
 #include <libpspp/alloc.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
Index: src/ui/flexifile.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/flexifile.c,v
retrieving revision 1.4
diff -u -p -r1.4 flexifile.c
--- src/ui/flexifile.c	29 Nov 2006 11:50:31 -0000	1.4
+++ src/ui/flexifile.c	10 Dec 2006 03:30:43 -0000
@@ -331,7 +331,7 @@ impl_resize (struct flexifile *ff, int n
 
       case_copy (&c, 0, &ff->cases[i], 0, posn);
       if ( n_values > 0 ) 
-	memset (case_data_rw(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
+	memset (case_data_rw_idx(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
       case_copy (&c, posn + n_values, 
 		 &ff->cases[i], posn, ff->value_cnt - posn);
 
Index: src/ui/gui/helper.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/helper.c,v
retrieving revision 1.8
diff -u -p -r1.8 helper.c
--- src/ui/gui/helper.c	22 Nov 2006 04:24:03 -0000	1.8
+++ src/ui/gui/helper.c	10 Dec 2006 03:30:43 -0000
@@ -1,3 +1,5 @@
+#include <config.h>
+
 #include "helper.h"
 #include <data/data-in.h>
 #include <data/data-out.h>
Index: src/ui/gui/missing-val-dialog.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/missing-val-dialog.c,v
retrieving revision 1.4
diff -u -p -r1.4 missing-val-dialog.c
--- src/ui/gui/missing-val-dialog.c	27 May 2006 08:36:10 -0000	1.4
+++ src/ui/gui/missing-val-dialog.c	10 Dec 2006 03:30:44 -0000
@@ -279,7 +279,7 @@ missing_val_dialog_show(struct missing_v
   gtk_widget_set_sensitive(dialog->discrete, FALSE);   
 
   gtk_widget_set_sensitive(GTK_WIDGET(dialog->button_range), 
-			   psppire_variable_get_type(dialog->pv) == NUMERIC);
+			   psppire_variable_get_type(dialog->pv) == VAR_NUMERIC);
 
   for(i = 0 ; i < 3 ; ++i ) 
     {
Index: src/ui/gui/psppire-case-file.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-case-file.c,v
retrieving revision 1.7
diff -u -p -r1.7 psppire-case-file.c
--- src/ui/gui/psppire-case-file.c	22 Nov 2006 04:24:03 -0000	1.7
+++ src/ui/gui/psppire-case-file.c	10 Dec 2006 03:30:44 -0000
@@ -247,7 +247,7 @@ psppire_case_file_get_value(const Psppir
 
   flexifile_get_case(FLEXIFILE(cf->flexifile), casenum, &c);
 
-  v = case_data(&c, idx);
+  v = case_data_idx(&c, idx);
 
   case_destroy(&c);
 
@@ -284,7 +284,7 @@ psppire_case_file_set_value(PsppireCaseF
     bytes = DIV_RND_UP(width, MAX_SHORT_STRING) * MAX_SHORT_STRING ;
 
   /* Cast away const in flagrant abuse of the casefile */
-  memcpy((union value *)case_data(&cc, idx), v, bytes);
+  memcpy((union value *)case_data_idx(&cc, idx), v, bytes);
 
   g_signal_emit(cf, signal[CASE_CHANGED], 0, casenum);
 
@@ -310,7 +310,7 @@ psppire_case_file_data_in(PsppireCaseFil
 
   /* Cast away const in flagrant abuse of the casefile */
   if (!data_in (input, fmt->type, 0, 0,
-                (union value *) case_data(&cc, idx), fmt_var_width (fmt)))
+                (union value *) case_data_idx(&cc, idx), fmt_var_width (fmt)))
     g_warning("Cant set value\n");
 
   g_signal_emit(cf, signal[CASE_CHANGED], 0, casenum);
Index: src/ui/gui/psppire-data-store.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-data-store.c,v
retrieving revision 1.20
diff -u -p -r1.20 psppire-data-store.c
--- src/ui/gui/psppire-data-store.c	22 Nov 2006 04:24:03 -0000	1.20
+++ src/ui/gui/psppire-data-store.c	10 Dec 2006 03:30:44 -0000
@@ -442,10 +442,10 @@ psppire_data_store_insert_new_case(Psppi
   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v) 
     {
       const struct PsppireVariable *pv = psppire_dict_get_variable(ds->dict, v);
-      if (ALPHA ==  psppire_variable_get_type(pv) ) 
+      if (VAR_STRING ==  psppire_variable_get_type(pv) ) 
 	continue;
 
-      case_data_rw (&cc, psppire_variable_get_fv (pv))->f = SYSMIS;
+      case_data_rw_idx (&cc, psppire_variable_get_fv (pv))->f = SYSMIS;
     }
 
   result = psppire_case_file_insert_case (ds->case_file, &cc, posn);
@@ -530,7 +530,7 @@ psppire_data_store_clear_datum (GSheetMo
 
   const gint index = psppire_variable_get_fv(pv) ;
 
-  if ( psppire_variable_get_type(pv) == NUMERIC) 
+  if ( psppire_variable_get_type(pv) == VAR_NUMERIC) 
     v.f = SYSMIS;
   else
     memcpy(v.s, "", MAX_SHORT_STRING);
Index: src/ui/gui/psppire-var-store.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-var-store.c,v
retrieving revision 1.13
diff -u -p -r1.13 psppire-var-store.c
--- src/ui/gui/psppire-var-store.c	3 Nov 2006 04:53:52 -0000	1.13
+++ src/ui/gui/psppire-var-store.c	10 Dec 2006 03:30:45 -0000
@@ -156,7 +156,7 @@ psppire_var_store_item_editable(PsppireV
   if ( !pv ) 
     return TRUE;
 
-  if ( ALPHA == psppire_variable_get_type(pv) && column == COL_DECIMALS ) 
+  if ( VAR_STRING == psppire_variable_get_type(pv) && column == COL_DECIMALS ) 
     return FALSE;
 
   write_spec = psppire_variable_get_write_spec(pv);
Index: src/ui/gui/psppire-variable.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-variable.c,v
retrieving revision 1.8
diff -u -p -r1.8 psppire-variable.c
--- src/ui/gui/psppire-variable.c	5 Dec 2006 15:10:22 -0000	1.8
+++ src/ui/gui/psppire-variable.c	10 Dec 2006 03:30:45 -0000
@@ -18,6 +18,8 @@
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     02110-1301, USA. */
 
+#include <config.h>
+
 #include <string.h>
 #include <stdlib.h>
 
@@ -51,7 +53,7 @@ psppire_variable_set_name(struct Psppire
 
   dict_rename_var(pv->dict->dict, pv->v, text);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
 
   return TRUE;
 }
@@ -66,7 +68,7 @@ psppire_variable_set_columns(struct Pspp
 
   var_set_display_width (pv->v, columns);
   
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
 
   return TRUE;
 }
@@ -80,7 +82,7 @@ psppire_variable_set_label(struct Psppir
 
   var_set_label (pv->v, label);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
 
   return TRUE;
 }
@@ -124,7 +126,7 @@ psppire_variable_set_width(struct Psppir
 	old_var_cnt = DIV_RND_UP(var_get_width (pv->v), MAX_SHORT_STRING);
       
       new_var_cnt = DIV_RND_UP(width, MAX_SHORT_STRING);
-      pv->v->width = width;
+      var_set_width (pv->v, width);
 
       psppire_dict_resize_variable(pv->dict, pv,
 				   old_var_cnt, new_var_cnt);
@@ -148,10 +150,7 @@ psppire_variable_set_type(struct Psppire
   else
     old_var_cnt = DIV_RND_UP (var_get_width (pv->v), MAX_SHORT_STRING);
 
-  if ( type == NUMERIC ) 
-    pv->v->width = 0;
-  else if (var_get_width (pv->v))
-    pv->v->width = 1;
+  var_set_width (pv->v, type == VAR_NUMERIC ? 0 : 1);
 
   if ( var_get_width (pv->v) == 0 ) 
     new_var_cnt = 1;
@@ -161,7 +160,7 @@ psppire_variable_set_type(struct Psppire
   psppire_dict_resize_variable(pv->dict, pv,
 			       old_var_cnt, new_var_cnt);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -180,7 +179,7 @@ psppire_variable_set_format(struct Psppi
     {
       msg_enable ();
       var_set_both_formats (pv->v, fmt);
-      psppire_dict_var_changed(pv->dict, pv->v->index);
+      psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
       return TRUE;
     }
   msg_enable ();
@@ -197,10 +196,9 @@ psppire_variable_set_value_labels(const 
   g_return_val_if_fail(pv->dict, FALSE);
   g_return_val_if_fail(pv->v, FALSE);
 
-  val_labs_destroy(pv->v->val_labs);
-  pv->v->val_labs = val_labs_copy(vls);
+  var_set_value_labels (pv->v, vls);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -214,7 +212,7 @@ psppire_variable_set_missing(const struc
 
   var_set_missing_values (pv->v, miss);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -226,7 +224,7 @@ psppire_variable_set_write_spec(const st
 
   var_set_write_format (pv->v, &fmt);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -238,7 +236,7 @@ psppire_variable_set_print_spec(const st
 
   var_set_print_format (pv->v, &fmt);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -253,7 +251,7 @@ psppire_variable_set_alignment(struct Ps
 
   var_set_alignment (pv->v, align);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -267,7 +265,7 @@ psppire_variable_set_measure(struct Pspp
 
   var_set_measure (pv->v, measure + 1);
 
-  psppire_dict_var_changed(pv->dict, pv->v->index);
+  psppire_dict_var_changed(pv->dict, var_get_dict_index (pv->v));
   return TRUE;
 }
 
@@ -329,7 +327,7 @@ psppire_variable_get_value_labels(const 
   g_return_val_if_fail(pv, NULL);
   g_return_val_if_fail(pv->v, NULL);
 
-  return pv->v->val_labs;
+  return var_get_value_labels (pv->v);
 }
 
 
@@ -379,7 +377,7 @@ psppire_variable_get_fv(const struct Psp
   g_return_val_if_fail(pv, -1);
   g_return_val_if_fail(pv->v, -1);
 
-  return pv->v->fv;
+  return var_get_case_index (pv->v);
 }
 
 
@@ -390,6 +388,6 @@ psppire_variable_get_index(const struct 
   g_return_val_if_fail(pv, -1);
   g_return_val_if_fail(pv->v, -1);
 
-  return pv->v->index;
+  return var_get_dict_index (pv->v);
 }
 
Index: src/ui/gui/psppire-variable.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-variable.h,v
retrieving revision 1.3
diff -u -p -r1.3 psppire-variable.h
--- src/ui/gui/psppire-variable.h	24 Jun 2006 09:08:50 -0000	1.3
+++ src/ui/gui/psppire-variable.h	10 Dec 2006 03:30:45 -0000
@@ -28,6 +28,8 @@
 #include <data/variable.h>
 #include "psppire-dict.h"
 
+struct val_labs;
+
 /* Don't use any of these members.
    Use accessor functions instead.
 */
Index: src/ui/gui/val-labs-dialog.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/val-labs-dialog.c,v
retrieving revision 1.4
diff -u -p -r1.4 val-labs-dialog.c
--- src/ui/gui/val-labs-dialog.c	31 May 2006 07:38:03 -0000	1.4
+++ src/ui/gui/val-labs-dialog.c	10 Dec 2006 03:30:45 -0000
@@ -22,6 +22,8 @@
 /*  This module describes the behaviour of the Value Labels dialog box,
     used for input of the value labels in the variable sheet */
 
+#include <config.h>
+
 #include <string.h>
 
 #include "helper.h"
Index: src/ui/gui/var-sheet.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/var-sheet.c,v
retrieving revision 1.8
diff -u -p -r1.8 var-sheet.c
--- src/ui/gui/var-sheet.c	29 Jul 2006 09:37:18 -0000	1.8
+++ src/ui/gui/var-sheet.c	10 Dec 2006 03:30:45 -0000
@@ -372,7 +372,7 @@ var_sheet_cell_change_entry (GtkSheet * 
 		{
 		case COL_WIDTH:
 		  r_min = fmt->d + 1;
-		  r_max = (psppire_variable_get_type(pv) == ALPHA) ? MAX_STRING : 40;
+		  r_max = (psppire_variable_get_type(pv) == VAR_STRING) ? MAX_STRING : 40;
 		  break;
 		case COL_DECIMALS:
 		  r_min = 0 ; 
Index: src/ui/gui/var-type-dialog.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/var-type-dialog.c,v
retrieving revision 1.6
diff -u -p -r1.6 var-type-dialog.c
--- src/ui/gui/var-type-dialog.c	3 Nov 2006 04:53:52 -0000	1.6
+++ src/ui/gui/var-type-dialog.c	10 Dec 2006 03:30:46 -0000
@@ -819,14 +819,14 @@ on_var_type_ok_clicked(GtkWidget *w, gpo
     gint decimals = atoi(gtk_entry_get_text
 			 (GTK_ENTRY(dialog->entry_decimals)));
 
-    gint new_type = NUMERIC;
+    gint new_type = VAR_NUMERIC;
     gint new_width = 0;
     bool result = false;
     struct fmt_spec spec;
     switch (dialog->active_button) 
       {
       case BUTTON_STRING:
-	new_type = ALPHA;
+	new_type = VAR_STRING;
 	new_width = width;
 	result = make_output_format_try(&spec, FMT_A, width, 0);
 	break;
