---
 doc/.cvsignore                             |    3 
 doc/automake.mk                            |   18 
 doc/data-file-format.texi                  |    2 
 doc/dev-concepts.texi                      | 2458 ++++++++++++++++++++++++++++
 doc/dev-data.texi                          |   47 
 doc/dev-intro.texi                         |   21 
 doc/dev-output.texi                        |    2 
 doc/dev-syntax.texi                        |    2 
 doc/pspp-dev.texinfo                       |  113 +
 doc/pspp.texinfo                           |    8 
 doc/utilities.texi                         |    1 
 doc/variables.texi                         |    2 
 src/data/automake.mk                       |    2 
 src/data/calendar.c                        |    4 
 src/data/case.h                            |    6 
 src/data/data-in.h                         |   10 
 src/data/data-out.c                        |    9 
 src/data/dict-class.c                      |   60 
 src/data/dict-class.h                      |   42 
 src/data/dictionary.c                      |   91 -
 src/data/dictionary.h                      |  114 -
 src/data/format.c                          |   36 
 src/data/format.h                          |   31 
 src/data/missing-values.c                  |  137 -
 src/data/missing-values.h                  |   77 
 src/data/por-file-reader.c                 |   11 
 src/data/procedure.c                       |    4 
 src/data/short-names.h                     |    3 
 src/data/sys-file-reader.c                 |    7 
 src/data/sys-file-writer.c                 |    4 
 src/data/val-type.h                        |   55 
 src/data/value-labels.c                    |  156 -
 src/data/value-labels.h                    |   34 
 src/data/value.c                           |   32 
 src/data/value.h                           |   38 
 src/data/vardict.h                         |    3 
 src/data/variable.c                        |   93 -
 src/data/variable.h                        |   60 
 src/data/vector.c                          |    4 
 src/data/vector.h                          |    2 
 src/language/data-io/data-list.c           |    2 
 src/language/data-io/file-handle.q         |    2 
 src/language/data-io/get.c                 |    4 
 src/language/data-io/list.q                |    5 
 src/language/dictionary/formats.c          |    2 
 src/language/dictionary/missing-values.c   |    2 
 src/language/dictionary/modify-variables.c |    4 
 src/language/dictionary/vector.c           |   10 
 src/language/expressions/evaluate.c        |    2 
 src/language/expressions/parse.c           |    6 
 src/language/lexer/lexer.c                 |    2 
 src/language/lexer/variable-parser.c       |    8 
 src/language/stats/aggregate.c             |   46 
 src/language/stats/descriptives.c          |    4 
 src/language/stats/flip.c                  |    3 
 src/language/stats/frequencies.q           |    8 
 src/language/stats/rank.q                  |   13 
 src/language/stats/regression.q            |   13 
 src/language/stats/t-test.q                |    6 
 src/language/xforms/compute.c              |    4 
 src/language/xforms/recode.c               |   35 
 src/libpspp/model-checker.c                |    1 
 src/math/factor-stats.c                    |    1 
 src/math/moments.c                         |    1 
 src/math/percentiles.c                     |    1 
 src/ui/gui/missing-val-dialog.c            |    8 
 src/ui/gui/val-labs-dialog.c               |    2 
 src/ui/gui/var-display.c                   |    6 
 src/ui/gui/var-type-dialog.c               |    4 
 69 files changed, 3386 insertions(+), 621 deletions(-)

Index: b/doc/.cvsignore
===================================================================
--- a/doc/.cvsignore
+++ b/doc/.cvsignore
@@ -1,6 +1,9 @@
 Makefile
 Makefile.in
 ni.texi
+pspp-dev.info
 pspp.info*
+stamp-1
 stamp-vti
+version-dev.texi
 version.texi
Index: b/doc/automake.mk
===================================================================
--- a/doc/automake.mk
+++ b/doc/automake.mk
@@ -1,13 +1,12 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-info_TEXINFOS = doc/pspp.texinfo 
+info_TEXINFOS = doc/pspp.texinfo doc/pspp-dev.texinfo
 
 doc_pspp_TEXINFOS = doc/version.texi \
 	doc/bugs.texi \
 	doc/command-index.texi \
 	doc/concept-index.texi \
 	doc/configuring.texi \
-	doc/data-file-format.texi \
 	doc/data-io.texi \
 	doc/data-selection.texi \
 	doc/expressions.texi \
@@ -21,8 +20,6 @@ doc_pspp_TEXINFOS = doc/version.texi \
 	doc/license.texi \
 	doc/ni.texi \
 	doc/not-implemented.texi \
-	doc/portable-file-format.texi \
-	doc/q2c.texi \
 	doc/statistics.texi \
 	doc/transformation.texi \
 	doc/regression.texi \
@@ -30,9 +27,18 @@ doc_pspp_TEXINFOS = doc/version.texi \
 	doc/variables.texi \
 	doc/fdl.texi 
 
+doc_pspp_dev_TEXINFOS = doc/version-dev.texi \
+	doc/dev-intro.texi \
+	doc/dev-concepts.texi \
+	doc/dev-syntax.texi \
+	doc/dev-data.texi \
+	doc/dev-output.texi \
+	doc/data-file-format.texi \
+	doc/portable-file-format.texi \
+	doc/q2c.texi
+
 EXTRA_DIST += doc/pspp.man \
-	doc/get-commands.pl \
-	$(doc_pspp_TEXINFOS)
+	doc/get-commands.pl
 
 doc/ni.texi: $(top_srcdir)/src/language/command.def doc/get-commands.pl
 	@$(MKDIR_P)  doc
Index: b/doc/data-file-format.texi
===================================================================
--- a/doc/data-file-format.texi
+++ b/doc/data-file-format.texi
@@ -191,7 +191,7 @@ format and using 24-hour time.  If the t
 field is arbitrarily set to @samp{00:00:00}.
 
 @item char file_label[64];
-File label declared by the user, if any (@pxref{FILE LABEL}).
+File label declared by the user, if any (@pxref{FILE LABEL,,,pspp}).
 Padded on the right with spaces.
 
 @item char padding[3];
Index: b/doc/dev-concepts.texi
===================================================================
--- /dev/null
+++ b/doc/dev-concepts.texi
@@ -0,0 +1,2458 @@
+@node Basic Concepts
+@chapter Basic Concepts
+
+This chapter introduces basic data structures and other concepts
+needed for developing in PSPP.
+
+@menu
+* Values::
+* Input and Output Formats::
+* User-Missing Values::
+* Value Labels::
+* Variables::
+* Dictionaries::
+* Cases::
+* Data Sets::
+* Coding Conventions::
+@end menu
+
+@node Values
+@section Values
+
+@cindex value
+The unit of data in PSPP is a @dfn{value}.
+
+@cindex width
+@cindex string value
+@cindex numeric value
+@cindex MAX_STRING
+Values are classified by @dfn{type} and @dfn{width}.  The
+type of a value is either @dfn{numeric} or @dfn{string} (sometimes
+called alphanumeric).  The width of a string value ranges from 1 to
+@code{MAX_STRING} bytes.  The width of a numeric value is artificially
+defined to be 0; thus, the type of a value can be inferred from its
+width.
+
+Some support is provided for working with value types and widths, in
+@file{data/val-type.h}:
+
+@deftypefn Macro int MAX_STRING
+Maximum width of a string value, in bytes, currently 32,767.
+@end deftypefn
+
+@deftypefun bool val_type_is_valid (enum val_type @var{val_type})
+Returns true if @var{val_type} is a valid value type, that is,
+either @code{VAL_NUMERIC} or @code{VAL_STRING}.  Useful for
+assertions.
+@end deftypefun
+
+@deftypefun {enum val_type} val_type_from_width (int @var{width})
+Returns @code{VAL_NUMERIC} if @var{width} is 0 and thus represents the
+width of a numeric value, otherwise @code{VAL_STRING} to indicate that
+@var{width} is the width of a string value.
+@end deftypefun
+
+The following subsections describe how values of each type are
+represented.
+
+@menu
+* Numeric Values::
+* String Values::
+* Runtime Typed Values::
+@end menu
+
+@node Numeric Values
+@subsection Numeric Values
+
+A value known to be numeric at compile time is represented as a
+@code{double}.  PSPP provides three values of @code{double} for
+special purposes, defined in @file{data/val-type.h}:
+
+@deftypefn Macro double SYSMIS
+The @dfn{system-missing value}, used to represent a datum whose true
+value is unknown, such as a survey question that was not answered by
+the respondent, or undefined, such as the result of division by zero.
+PSPP propagates the system-missing value through calculations and
+compensates for missing values in statistical analyses.  @xref{Missing
+Observations,,,pspp}, for a PSPP user's view of missing values.
+
+PSPP currently defines @code{SYSMIS} as @code{-DBL_MAX}, that is, the
+greatest finite negative value of @code{double}.  It is best not to
+depend on this definition, because PSPP may transition to using an
+IEEE NaN (not a number) instead at some point in the future.
+@end deftypefn
+
+@deftypefn Macro double LOWEST
+@deftypefnx Macro double HIGHEST
+The greatest finite negative (except for @code{SYSMIS}) and positive
+values of @code{double}, respectively.  These values do not ordinarily
+appear in user data files.  Instead, they are used to implement
+endpoints of open-ended ranges that are occasionally permitted in PSPP
+syntax, e.g.@: @code{5 THRU HI} as a range of missing values
+(@pxref{MISSING VALUES,,,pspp}).
+@end deftypefn
+
+@node String Values
+@subsection String Values
+
+A value known at compile time to have string type is represented as an
+array of @code{char}.  String values do not necessarily represent
+readable text strings and may contain arbitrary 8-bit data, including
+null bytes, control codes, and bytes with the high bit set.  Thus,
+string values are not null-terminated strings, but rather opaque
+arrays of bytes.
+
+@code{SYSMIS}, @code{LOWEST}, and @code{HIGHEST} have no equivalents
+as string values.  Usually, PSPP fills an unknown or undefined string
+values with spaces, but PSPP does not treat such a string as a special
+case when it processes it later.
+
+@cindex MAX_STRING
+@code{MAX_STRING}, the maximum length of a string value, is defined in
+@file{data/val-type.h}.
+
+@node Runtime Typed Values
+@subsection Runtime Typed Values
+
+When a value's type is only known at runtime, it is often represented
+as a @union{value}, defined in @file{data/value.h}.  @union{value} has
+two members: a @code{double} named @samp{f} to store a numeric value
+and an array of @code{char} named @samp{s} to a store a string value.
+A @union{value} does not identify the type or width of the data it
+contains.  Code that works with @union{values}s must therefore have
+external knowledge of its content, often through the type and width of
+a @struct{variable} (@pxref{Variables}).
+
+@cindex MAX_SHORT_STRING
+@cindex short string
+@cindex long string
+@cindex string value
+The array of @code{char} in @union{value} has only a small, fixed
+capacity of @code{MAX_SHORT_STRING} bytes.  A value that
+fits within this capacity is called a @dfn{short string}.  Any wider
+string value, which must be represented by more than one
+@union{value}, is called a @dfn{long string}.
+
+@deftypefn Macro int MAX_SHORT_STRING
+Maximum width of a short string value, never less than 8 bytes.  It is
+wider than 8 bytes on systems where @code{double} is either larger
+than 8 bytes or has stricter alignment than 8 bytes.
+@end deftypefn
+
+@deftypefn Macro int MIN_LONG_STRING
+Minimum width of a long string value, that is, @code{MAX_SHORT_STRING
++ 1}.
+@end deftypefn
+
+Long string variables are slightly harder to work with than short
+string values, because they cannot be conveniently and efficiently
+allocated as block scope variables or structure members.  The PSPP
+language exposes this inconvenience to the user: there are many
+circumstances in PSPP syntax where short strings are allowed but not
+long strings.  Short string variables, for example, may have
+user-missing values, but long string variables may not (@pxref{Missing
+Observations,,,pspp}).
+
+PSPP provides a few functions for working with @union{value}s.  The
+most useful are described below.  To use these functions, recall that
+a numeric value has a width of 0.
+
+@deftypefun size_t value_cnt_from_width (int @var{width})
+Returns the number of consecutive @union{value}s that must be
+allocated to store a value of the given @var{width}.  For a numeric or
+short string value, the return value is 1; for long string
+variables, it is greater than 1.
+@end deftypefun
+
+@deftypefun void value_copy (union value *@var{dst}, @
+                             const union value *@var{src}, @
+                             int @var{width})
+Copies a value of the given @var{width} from the @union{value} array
+starting at @var{src} to the one starting at @var{dst}.  The two
+arrays must not overlap.
+@end deftypefun
+
+@deftypefun void value_set_missing (union value *@var{value}, int @var{width})
+Sets @var{value} to @code{SYSMIS} if it is numeric or to all spaces if
+it is alphanumeric, according to @var{width}.  @var{value} must point
+to the start of a @union{value} array of the given @var{width}.
+@end deftypefun
+
+@anchor{value_is_resizable}
+@deftypefun bool value_is_resizable (const union value *@var{value}, int @var{old_width}, int @var{new_width})
+Determines whether @var{value} may be resized from @var{old_width} to
+@var{new_width}.  Resizing is possible if the following criteria are
+met.  First, @var{old_width} and @var{new_width} must be both numeric
+or both string widths.  Second, if @var{new_width} is a short string
+width and less than @var{old_width}, resizing is allowed only if bytes
+@var{new_width} through @var{old_width} in @var{value} contain only
+spaces.
+
+These rules are part of those used by @func{mv_is_resizable} and
+@func{val_labs_can_set_width}.
+@end deftypefun
+
+@deftypefun void value_resize (union value *@var{value}, int @var{old_width}, int @var{new_width})
+Resizes @var{value} from @var{old_width} to @var{new_width}, which
+must be allowed by the rules stated above.  This has an effect only if
+@var{new_width} is greater than @var{old_width}, in which case the
+bytes newly added to @var{value} are cleared to spaces.
+@end deftypefun
+
+@node Input and Output Formats
+@section Input and Output Formats
+
+Input and output formats specify how to convert data fields to and
+from data values (@pxref{Input and Output Formats,,,pspp}).  PSPP uses
+@struct{fmt_spec} to represent input and output formats.
+
+Function prototypes and other declarations related to formats are in
+the @file{<data/format.h>} header.
+
+@deftp {Structure} {struct fmt_spec}
+An input or output format, with the following members:
+
+@table @code
+@item enum fmt_type type
+The format type (see below).
+
+@item int w
+Field width, in bytes.  The width of numeric fields is always between
+1 and 40 bytes, and the width of string fields is always between 1 and
+65534 bytes.  However, many individual types of formats place stricter
+limits on field width (see @ref{fmt_max_input_width},
+@ref{fmt_max_output_width}).
+
+@item int d
+Number of decimal places, in character positions.  For format types
+that do not allow decimal places to be specified, this value must be
+0.  Format types that do allow decimal places have type-specific and
+often width-specific restrictions on @code{d} (see
+@ref{fmt_max_input_decimals}, @ref{fmt_max_output_decimals}).
+@end table
+@end deftp
+
+@deftp {Enumeration} {enum fmt_type}
+An enumerated type representing an input or output format type.  Each
+PSPP input and output format has a corresponding enumeration constant
+prefixed by @samp{FMT}: @code{FMT_F}, @code{FMT_COMMA},
+@code{FMT_DOT}, and so on.
+@end deftp
+
+The following sections describe functions for manipulating formats and
+the data in fields represented by formats.
+
+@menu
+* Constructing and Verifying Formats::
+* Format Utility Functions::
+* Obtaining Properties of Format Types::
+* Numeric Formatting Styles::
+* Formatted Data Input and Output::
+@end menu
+
+@node Constructing and Verifying Formats
+@subsection Constructing and Verifying Formats
+
+These functions construct @struct{fmt_spec}s and verify that they are
+valid.
+
+@deftypefun {struct fmt_spec} fmt_for_input (enum fmt_type @var{type}, int @var{w}, int @var{d})
+@deftypefunx {struct fmt_spec} fmt_for_output (enum fmt_type @var{type}, int @var{w}, int @var{d})
+Constructs a @struct{fmt_spec} with the given @var{type}, @var{w}, and
+@var{d}, asserts that the result is a valid input (or output) format,
+and returns it.
+@end deftypefun
+
+@anchor{fmt_for_output_from_input}
+@deftypefun {struct fmt_spec} fmt_for_output_from_input (const struct fmt_spec *@var{input})
+Given @var{input}, which must be a valid input format, returns the
+equivalent output format.  @xref{Input and Output Formats,,,pspp}, for
+the rules for converting input formats into output formats.
+@end deftypefun
+
+@deftypefun {struct fmt_spec} fmt_default_for_width (int @var{width})
+Returns the default output format for a variable of the given
+@var{width}.  For a numeric variable, this is F8.2 format; for a
+string variable, it is the A format of the given @var{width}.
+@end deftypefun
+
+The following functions check whether a @struct{fmt_spec} is valid for
+various uses and return true if so, false otherwise.  When any of them
+returns false, it also outputs an explanatory error message using
+@func{msg}.  To suppress error output, enclose a call to one of these
+functions by a @func{msg_disable}/@func{msg_enable} pair.
+
+@deftypefun bool fmt_check (const struct fmt_spec *@var{format}, bool @var{for_input})
+@deftypefunx bool fmt_check_input (const struct fmt_spec *@var{format})
+@deftypefunx bool fmt_check_output (const struct fmt_spec *@var{format})
+Checks whether @var{format} is a valid input format (for
+@func{fmt_check_input}, or @func{fmt_check} if @var{for_input}) or
+output format (for @func{fmt_check_output}, or @func{fmt_check} if not
+@var{for_input}).
+@end deftypefun
+
+@deftypefun bool fmt_check_type_compat (const struct fmt_spec *@var{format}, enum val_type @var{type})
+Checks whether @var{format} matches the value type @var{type}, that
+is, if @var{type} is @code{VAL_NUMERIC} and @var{format} is a numeric
+format or @var{type} is @code{VAL_STRING} and @var{format} is a string
+format.
+@end deftypefun
+
+@deftypefun bool fmt_check_width_compat (const struct fmt_spec *@var{format}, int @var{width})
+Checks whether @var{format} may be used as an output format for a
+value of the given @var{width}.
+
+@func{fmt_var_width}, described in
+the following section, can be also be used to determine the value
+width needed by a format.
+@end deftypefun
+
+@node Format Utility Functions
+@subsection Format Utility Functions
+
+These functions work with @struct{fmt_spec}s.
+
+@deftypefun int fmt_var_width (const struct fmt_spec *@var{format})
+Returns the width for values associated with @var{format}.  If
+@var{format} is a numeric format, the width is 0; if @var{format} is
+an A format, then the width @code{@var{format}->w}; otherwise,
+@var{format} is an AHEX format and its width is @code{@var{format}->w
+/ 2}.
+@end deftypefun
+
+@deftypefun char *fmt_to_string (const struct fmt_spec *@var{format}, char @var{s}[FMT_STRING_LEN_MAX + 1])
+Converts @var{format} to a human-readable format specifier in @var{s}
+and returns @var{s}.  @var{format} need not be a valid input or output
+format specifier, e.g.@: it is allowed to have an excess width or
+decimal places.  In particular, if @var{format} has decimals, they are
+included in the output string, even if @var{format}'s type does not
+allow decimals, to allow accurately presenting incorrect formats to
+the user.
+@end deftypefun
+
+@deftypefun bool fmt_equal (const struct fmt_spec *@var{a}, const struct fmt_spec *@var{b})
+Compares @var{a} and @var{b} memberwise and returns true if they are
+identical, false otherwise.  @var{format} need not be a valid input or
+output format specifier.
+@end deftypefun
+
+@node Obtaining Properties of Format Types
+@subsection Obtaining Properties of Format Types
+
+These functions work with @enum{fmt_type}s instead of the higher-level
+@struct{fmt_spec}s.  Their primary purpose is to report properties of
+each possible format type, which in turn allows clients to abstract
+away many of the details of the very heterogeneous requirements of
+each format type.
+
+The first group of functions works with format type names.
+
+@deftypefun const char *fmt_name (enum fmt_type @var{type})
+Returns the name for the given @var{type}, e.g.@: @code{"COMMA"} for
+@code{FMT_COMMA}.
+@end deftypefun
+
+@deftypefun bool fmt_from_name (const char *@var{name}, enum fmt_type *@var{type})
+Tries to find the @enum{fmt_type} associated with @var{name}.  If
+successful, sets @code{*@var{type}} to the type and returns true;
+otherwise, returns false without modifying @code{*@var{type}}.
+@end deftypefun
+
+The functions below query basic limits on width and decimal places for
+each kind of format.
+
+@deftypefun bool fmt_takes_decimals (enum fmt_type @var{type})
+Returns true if a format of the given @var{type} is allowed to have a
+nonzero number of decimal places (the @code{d} member of
+@struct{fmt_spec}), false if not.
+@end deftypefun
+
+@deftypefun int fmt_min_input_width (enum fmt_type @var{type})
+@deftypefunx int fmt_max_input_width (enum fmt_type @var{type})
+@deftypefunx int fmt_min_output_width (enum fmt_type @var{type})
+@deftypefunx int fmt_max_output_width (enum fmt_type @var{type})
+Returns the minimum or maximum width (the @code{w} member of
+@struct{fmt_spec}) allowed for an input or output format of the
+specified @var{type}.
+@end deftypefun
+
+@deftypefun int fmt_max_input_decimals (enum fmt_type @var{type}, int @var{width})
+@deftypefunx int fmt_max_output_decimals (enum fmt_type @var{type}, int @var{width})
+Returns the maximum number of decimal places allowed for an input or
+output format, respectively, of the given @var{type} and @var{width}.
+Returns 0 if the specified @var{type} does not allow any decimal
+places or if @var{width} is too narrow to allow decimal places.
+@end deftypefun
+
+@deftypefun int fmt_step_width (enum fmt_type @var{type})
+Returns the ``width step'' for a @struct{fmt_spec} of the given
+@var{type}.  A @struct{fmt_spec}'s width must be a multiple of its
+type's width step.  Most format types have a width step of 1, so that
+their formats' widths may be any integer within the valid range, but
+hexadecimal numeric formats and AHEX string formats have a width step
+of 2.
+@end deftypefun
+
+These functions allow clients to broadly determine how each kind of
+input or output format behaves.
+
+@deftypefun bool fmt_is_string (enum fmt_type @var{type})
+@deftypefunx bool fmt_is_numeric (enum fmt_type @var{type})
+Returns true if @var{type} is a format for numeric or string values,
+respectively, false otherwise.
+@end deftypefun
+
+@deftypefun enum fmt_category fmt_get_category (enum fmt_type @var{type})
+Returns the category within which @var{type} falls.
+
+@deftp {Enumeration} {enum fmt_category}
+A group of format types.  Format type categories correspond to the
+input and output categories described in the PSPP user documentation
+(@pxref{Input and Output Formats,,,pspp}).
+
+Each format is in exactly one category.  The categories have bitwise
+disjoint values to make it easy to test whether a format type is in
+one of multiple categories, e.g.@:
+
+@example
+if (fmt_get_category (type) & (FMT_CAT_DATE | FMT_CAT_TIME))
+  @{
+    /* @dots{}@r{@code{type} is a date or time format}@dots{} */
+  @}
+@end example
+
+The format categories are:
+@table @code
+@item FMT_CAT_BASIC
+Basic numeric formats.
+
+@item FMT_CAT_CUSTOM
+Custom currency formats.
+
+@item FMT_CAT_LEGACY
+Legacy numeric formats.
+
+@item FMT_CAT_BINARY
+Binary formats.
+
+@item FMT_CAT_HEXADECIMAL
+Hexadecimal formats.
+
+@item FMT_CAT_DATE
+Date formats.
+
+@item FMT_CAT_TIME
+Time formats.
+
+@item FMT_CAT_DATE_COMPONENT
+Date component formats.
+
+@item FMT_CAT_STRING
+String formats.
+@end table
+@end deftp
+@end deftypefun
+
+The PSPP input and output routines use the following pair of functions
+to convert @enum{fmt_type}s to and from the separate set of codes used
+in system and portable files:
+
+@deftypefun int fmt_to_io (enum fmt_type @var{type})
+Returns the format code used in system and portable files that
+corresponds to @var{type}.
+@end deftypefun
+
+@deftypefun bool fmt_from_io (int @var{io}, enum fmt_type *@var{type})
+Converts @var{io}, a format code used in system and portable files,
+into a @enum{fmt_type} in @code{*@var{type}}.  Returns true if
+successful, false if @var{io} is not valid.
+@end deftypefun
+
+These functions reflect the relationship between input and output
+formats.
+
+@deftypefun enum fmt_type fmt_input_to_output (enum fmt_type @var{type})
+Returns the output format type that is used by default by DATA LIST
+and other input procedures when @var{type} is specified as an input
+format.  The conversion from input format to output format is more
+complicated than simply changing the format.
+@xref{fmt_for_output_from_input}, for a function that performs the
+entire conversion.
+@end deftypefun
+
+@deftypefun bool fmt_usable_for_input (enum fmt_type @var{type})
+Returns true if @var{type} may be used as an input format type, false
+otherwise.  The custom currency formats, in particular, may be used
+for output but not for input.
+
+All format types are valid for output.
+@end deftypefun
+
+The final group of format type property functions obtain
+human-readable templates that illustrate the formats graphically.
+
+@deftypefun const char *fmt_date_template (enum fmt_type @var{type})
+Returns a formatting template for @var{type}, which must be a date or
+time format type.  These formats are used by @func{data_in} and
+@func{data_out} to guide parsing and formatting date and time data.
+@end deftypefun
+
+@deftypefun char *fmt_dollar_template (const struct fmt_spec *@var{format})
+Returns a string of the form @code{$#,###.##} according to
+@var{format}, which must be of type @code{FMT_DOLLAR}.  The caller
+must free the string with @code{free}.
+@end deftypefun
+
+@node Numeric Formatting Styles
+@subsection Numeric Formatting Styles
+
+Each of the basic numeric formats (F, E, COMMA, DOT, DOLLAR, PCT) and
+custom currency formats (CCA, CCB, CCC, CCD, CCE) has an associated
+numeric formatting style, represented by @struct{fmt_number_style}.
+Input and output conversion of formats that have numeric styles is
+determined mainly by the style, although the formatting rules have
+special cases that are not represented within the style.
+
+@deftp {Structure} {struct fmt_number_style}
+A structure type with the following members:
+
+@table @code
+@item struct substring neg_prefix
+@itemx struct substring prefix
+@itemx struct substring suffix
+@itemx struct substring neg_suffix
+A set of strings used a prefix to negative numbers, a prefix to every
+number, a suffix to every number, and a suffix to negative numbers,
+respectively.  Each of these strings is no more than
+@code{FMT_STYLE_AFFIX_MAX} bytes (currently 16) bytes in length.
+These strings must be freed with @func{ss_dealloc} when no longer
+needed.
+
+@item decimal
+The character used as a decimal point.  It must be either @samp{.} or
+@samp{,}.
+
+@item grouping
+The character used for grouping digits to the left of the decimal
+point.  It may be @samp{.} or @samp{,}, in which case it must not be
+equal to @code{decimal}, or it may be set to 0 to disable grouping.
+@end table
+@end deftp
+
+The following functions are provided for working with numeric
+formatting styles.
+
+@deftypefun {struct fmt_number_style *} fmt_number_style_create (void)
+Creates and returns a new @struct{fmt_number_style} with all of the
+prefixes and suffixes set to the empty string, @samp{.} as the decimal
+point character, and grouping disables.
+@end deftypefun
+
+@deftypefun void fmt_number_style_destroy (struct fmt_number_style *@var{style})
+Destroys @var{style}, freeing its storage.
+@end deftypefun
+
+@deftypefun int fmt_affix_width (const struct fmt_number_style *@var{style})
+Returns the total length of @var{style}'s @code{prefix} and @code{suffix}.
+@end deftypefun
+
+@deftypefun int fmt_neg_affix_width (const struct fmt_number_style *@var{style})
+Returns the total length of @var{style}'s @code{neg_prefix} and
+@code{neg_suffix}.
+@end deftypefun
+
+PSPP maintains a global set of number styles for each of the basic
+numeric formats and custom currency formats.  The following functions
+work with these global styles:
+
+@deftypefun {const struct fmt_number_style *} fmt_get_style (enum fmt_type @var{type})
+Returns the numeric style for the given format @var{type}.
+@end deftypefun
+
+@deftypefun void fmt_set_style (enum fmt_type @var{type}, struct fmt_number_style *@var{style})
+Replaces the current numeric style for format @var{type} by the given
+@var{style}, which becomes owned by the callee.  @var{type} must be a
+custom currency format and @var{style} must follow all the rules for
+numeric styles explained above.
+@end deftypefun
+
+@deftypefun int fmt_decimal_char (enum fmt_type @var{type})
+Returns the decimal point character for the given format @var{type}.
+Equivalent to @code{fmt_get_style (@var{type})->decimal}.
+@end deftypefun
+
+@deftypefun int fmt_grouping_char (enum fmt_type @var{type})
+Returns the grouping character for the given format @var{type}, or 0
+if @var{type} output should not be grouped.  Equivalent to
+@code{fmt_get_style (@var{type})->grouping}.
+@end deftypefun
+
+@deftypefun void fmt_set_decimal (char @var{decimal})
+Changes the decimal point character for the basic numeric formats to
+@var{decimal}, which must be @samp{.} or @samp{,}.  The F, E, COMMA,
+DOLLAR, and PCT will use the specified decimal point character, and the
+opposite character for grouping where appropriate.  The DOT format
+uses the reverse choices.
+@end deftypefun
+
+@node Formatted Data Input and Output
+@subsection Formatted Data Input and Output
+
+These functions provide the ability to convert data fields into
+@union{value}s and vice versa.
+
+@deftypefun bool data_in (struct substring @var{input}, enum legacy_encoding @var{legacy_encoding}, enum fmt_type @var{type}, int @var{implied_decimals}, int @var{first_column}, union value *@var{output}, int @var{width})
+Parses @var{input} as a field containing data in the given format
+@var{type}.  The resulting value is stored in @var{output}, which has
+the given @var{width}.  For consistency, @var{width} must be 0 if
+@var{type} is a numeric format type and greater than 0 if @var{type}
+is a string format type.
+
+Ordinarily @var{legacy_encoding} should be @code{LEGACY_NATIVE},
+indicating that @var{input} is encoded in the character set
+conventionally used on the host machine.  It may be set to
+@code{LEGACY_EBCDIC} to cause @var{input} to be re-encoded from EBCDIC
+during data parsing.
+
+If @var{input} is the empty string (with length 0), @var{output} is set
+to the value set on SET BLANKS (@pxref{SET BLANKS,,,pspp}) for a
+numeric value, or to all spaces for a string value.  This applies
+regardless of the usual parsing requirements for @var{type}.
+
+If @var{implied_decimals} is greater than zero, then the numeric
+result is shifted right by @var{implied_decimals} decimal places if
+@var{input} does not contain a decimal point character or an exponent.
+Only certain numeric format types support implied decimal places; for
+string formats and other numeric formats, @var{implied_decimals} has
+no effect.  DATA LIST FIXED is the primary user of this feature
+(@pxref{DATA LIST FIXED,,,pspp}).  Other callers should generally
+specify 0 for @var{implied_decimals}, to disable this feature.
+
+When @var{input} contains invalid input data, @func{data_in} outputs a
+message using @func{msg} (@pxref{msg}).  If @var{first_column} is
+nonzero, it is included in any such error message as the 1-based
+column number of the start of the field.  The last column in the field
+is calculated as @math{@var{first_column} + @var{input} - 1}.  To
+suppress error output, enclose the call to @func{data_in} by calls to
+@func{msg_disable} and @func{msg_enable}.
+
+This function returns true on success, false if a message was output
+(even if suppressed).  Overflow and underflow provoke warnings but are
+not propagated to the caller as errors.
+
+This function is declared in @file{data/data-in.h}.
+@end deftypefun
+
+@deftypefun void data_out (const union value *@var{input}, const struct fmt_spec *@var{format}, char *@var{output})
+@deftypefunx void data_out_legacy (const union value *@var{input}, enum legacy_encoding @var{legacy_encoding}, const struct fmt_spec *@var{format}, char *@var{output})
+Converts the data pointed to by @var{input} into a data field in
+@var{output} according to output format specifier @var{format}, which
+must be a valid output format.  Exactly @code{@var{format}->w} bytes
+are written to @var{output}.  The width of @var{input} is also
+inferred from @var{format} using an algorithm equivalent to
+@func{fmt_var_width}.
+
+If @func{data_out} is called, or @func{data_out_legacy} is called with
+@var{legacy_encoding} set to @code{LEGACY_NATIVE}, @var{output} will
+be encoded in the character set conventionally used on the host
+machine.  If @var{legacy_encoding} is set to @code{LEGACY_EBCDIC},
+@var{output} will be re-encoded from EBCDIC during data output.
+
+When @var{input} contains data that cannot be represented in the given
+@var{format}, @func{data_out} may output a message using @func{msg}
+(@pxref{msg}), although the current implementation does not
+consistently do so.  To suppress error output, enclose the call to
+@func{data_out} by calls to @func{msg_disable} and @func{msg_enable}.
+
+This function is declared in @file{data/data-out.h}.
+@end deftypefun
+
+@node User-Missing Values
+@section User-Missing Values
+
+In addition to the system-missing value for numeric values, each
+variable has a set of user-missing values (@pxref{MISSING
+VALUES,,,pspp}).  A set of user-missing values is represented by
+@struct{missing_values}.
+
+It is rarely necessary to interact directly with a
+@struct{missing_values} object.  Instead, the most common operation,
+querying whether a particular value is a missing value for a given
+variable, is most conveniently executed through functions on
+@struct{variable}.  @xref{Variable Missing Values}, for details.
+
+A @struct{missing_values} is essentially a set of @union{value}s that
+have a common value width (@pxref{Values}).  For a set of
+missing values associated with a variable (the common case), the set's
+width is the same as the variable's width.  The contents of a set of
+missing values is subject to some restrictions.  Regardless of width,
+a set of missing values is allowed to be empty.  Otherwise, its
+possible contents depend on its width:
+
+@table @asis
+@item 0 (numeric values)
+Up to three discrete numeric values, or a range of numeric values
+(which includes both ends of the range), or a range plus one discrete
+numeric value.
+
+@item 1@dots{}@t{MAX_SHORT_STRING} - 1 (short string values)
+Up to three discrete string values (with the same width as the set).
+
+@item @t{MAX_SHORT_STRING}@dots{}@t{MAX_STRING} (long string values)
+Always empty.
+@end table
+
+These somewhat arbitrary restrictions are the same as those imposed by
+SPSS.  In PSPP we could easily eliminate these restrictions, but doing
+so would also require us to extend the system file format in an
+incompatible way, which we consider a bad tradeoff.
+
+Function prototypes and other declarations related to missing values
+are declared in @file{data/missing-values.h}.
+
+@deftp {Structure} {struct missing_values}
+Opaque type that represents a set of missing values.
+@end deftp
+
+The most often useful functions for missing values are those for
+testing whether a given value is missing, described in the following
+section.  Several other functions for creating, inspecting, and
+modifying @struct{missing_values} objects are described afterward, but
+these functions are much more rarely useful.  No function for
+destroying a @struct{missing_values} is provided, because
+@struct{missing_values} does not contain any pointers or other
+references to resources that need deallocation.
+
+@menu
+* Testing for Missing Values::
+* Initializing User-Missing Value Sets::
+* Changing User-Missing Value Set Width::
+* Inspecting User-Missing Value Sets::
+* Modifying User-Missing Value Sets::
+@end menu
+
+@node Testing for Missing Values
+@subsection Testing for Missing Values
+
+The most often useful functions for missing values are those for
+testing whether a given value is missing, described here.  However,
+using one of the corresponding missing value testing functions for
+variables can be even easier (@pxref{Variable Missing Values}).
+
+@deftypefun bool mv_is_value_missing (const struct missing_values *@var{mv}, const union value *@var{value}, enum mv_class @var{class})
+@deftypefunx bool mv_is_num_missing (const struct missing_values *@var{mv}, double @var{value}, enum mv_class @var{class})
+@deftypefunx bool mv_is_str_missing (const struct missing_values *@var{mv}, const char @var{value}[], enum mv_class @var{class})
+Tests whether @var{value} is in one of the categories of missing
+values given by @var{class}.  Returns true if so, false otherwise.
+
+@var{mv} determines the width of @var{value} and provides the set of
+user-missing values to test.
+
+The only difference among these functions in the form in which
+@var{value} is provided, so you may use whichever function is most
+convenient.
+
+The @var{class} argument determines the exact kinds of missing values
+that the functions test for:
+
+@deftp Enumeration {enum mv_class}
+@table @t
+@item MV_USER
+Returns true if @var{value} is in the set of user-missing values given
+by @var{mv}.
+
+@item MV_SYSTEM
+Returns true if @var{value} is system-missing.  (If @var{mv}
+represents a set of string values, then @var{value} is never
+system-missing.)
+
+@item MV_ANY
+@itemx MV_USER | MV_SYSTEM
+Returns true if @var{value} is user-missing or system-missing.
+
+@item MV_NONE
+Always returns false, that is, @var{value} is never considered
+missing.
+@end table
+@end deftp
+@end deftypefun
+
+@node Initializing User-Missing Value Sets
+@subsection Initializing User-Missing Value Sets
+
+@deftypefun void mv_init (struct missing_values *@var{mv}, int @var{width})
+Initializes @var{mv} as a set of user-missing values.  The set is
+initially empty.  Any values added to it must have the specified
+@var{width}.
+@end deftypefun
+
+@deftypefun void mv_copy (struct missing_values *@var{mv}, const struct missing_values *@var{old})
+Initializes @var{mv} as a copy of the existing set of user-missing
+values @var{old}.
+@end deftypefun
+
+@deftypefun void mv_clear (struct missing_values *@var{mv})
+Empties the user-missing value set @var{mv}, retaining its existing
+width.
+@end deftypefun
+
+@node Changing User-Missing Value Set Width
+@subsection Changing User-Missing Value Set Width
+
+A few PSPP language constructs copy sets of user-missing values from
+one variable to another.  When the source and target variables have
+the same width, this is simple.  But when the target variable's width
+might be different from the source variable's, it takes a little more
+work.  The functions described here can help.
+
+In fact, it is usually unnecessary to call these functions directly.
+Most of the time @func{var_set_missing_values}, which uses
+@func{mv_resize} internally to resize the new set of missing values to
+the required width, may be used instead.
+@xref{var_set_missing_values}, for more information.
+
+@deftypefun bool mv_is_resizable (const struct missing_values *@var{mv}, int @var{new_width})
+Tests whether @var{mv}'s width may be changed to @var{new_width} using
+@func{mv_resize}.  Returns true if it is allowed, false otherwise.
+
+If @var{new_width} is a long string width, @var{mv} may be resized
+only if it is empty.  Otherwise, if @var{mv} contains any missing
+values, then it may be resized only if each missing value may be
+resized, as determined by @func{value_is_resizable}
+(@pxref{value_is_resizable}).
+@end deftypefun
+
+@anchor{mv_resize}
+@deftypefun void mv_resize (struct missing_values *@var{mv}, int @var{width})
+Changes @var{mv}'s width to @var{width}.  @var{mv} and @var{width}
+must satisfy the constraints explained above.
+
+When a string missing value set's width is increased, each
+user-missing value is padded on the right with spaces to the new
+width.
+@end deftypefun
+
+@node Inspecting User-Missing Value Sets
+@subsection Inspecting User-Missing Value Sets
+
+These functions inspect the properties and contents of
+@struct{missing_values} objects.
+
+The first set of functions inspects the discrete values that numeric
+and short string sets of user-missing values may contain:
+
+@deftypefun bool mv_is_empty (const struct missing_values *@var{mv})
+Returns true if @var{mv} contains no user-missing values, false if it
+contains at least one user-missing value (either a discrete value or a
+numeric range).
+@end deftypefun
+
+@deftypefun int mv_get_width (const struct missing_values *@var{mv})
+Returns the width of the user-missing values that @var{mv} represents.
+@end deftypefun
+
+@deftypefun int mv_n_values (const struct missing_values *@var{mv})
+Returns the number of discrete user-missing values included in
+@var{mv}.  The return value will be between 0 and 3.  For sets of
+numeric user-missing values that include a range, the return value
+will be 0 or 1.
+@end deftypefun
+
+@deftypefun bool mv_has_value (const struct missing_values *@var{mv})
+Returns true if @var{mv} has at least one discrete user-missing
+values, that is, if @func{mv_n_values} would return nonzero for
+@var{mv}.
+@end deftypefun
+
+@deftypefun void mv_get_value (const struct missing_values *@var{mv}, union value *@var{value}, int @var{index})
+Copies the discrete user-missing value in @var{mv} with the given
+@var{index} into @var{value}.  The index must be less than the number
+of discrete user-missing values in @var{mv}, as reported by
+@func{mv_n_values}.
+@end deftypefun
+
+The second set of functions inspects the single range of values that
+numeric sets of user-missing values may contain:
+
+@deftypefun bool mv_has_range (const struct missing_values *@var{mv})
+Returns true if @var{mv} includes a range, false otherwise.
+@end deftypefun
+
+@deftypefun void mv_get_range (const struct missing_values *@var{mv}, double *@var{low}, double *@var{high})
+Stores the low endpoint of @var{mv}'s range in @code{*@var{low}} and
+the high endpoint of the range in @code{*@var{high}}.  @var{mv} must
+include a range.
+@end deftypefun
+
+@node Modifying User-Missing Value Sets
+@subsection Modifying User-Missing Value Sets
+
+These functions modify the contents of @struct{missing_values}
+objects.
+
+The first set of functions applies to all sets of user-missing values:
+
+@deftypefun bool mv_add_value (struct missing_values *@var{mv}, const union value *@var{value})
+@deftypefunx bool mv_add_str (struct missing_values *@var{mv}, const char @var{value}[])
+@deftypefunx bool mv_add_num (struct missing_values *@var{mv}, double @var{value})
+Attempts to add the given discrete @var{value} to set of user-missing
+values @var{mv}.  @var{value} must have the same width as @var{mv}.
+Returns true if @var{value} was successfully added, false if the set
+could not accept any more discrete values.  (Always returns false if
+@var{mv} is a set of long string user-missing values.)
+
+These functions are equivalent, except for the form in which
+@var{value} is provided, so you may use whichever function is most
+convenient.
+@end deftypefun
+
+@deftypefun void mv_pop_value (struct missing_values *@var{mv}, union value *@var{value})
+Removes a discrete value from @var{mv} (which must contain at least
+one discrete value) and stores it in @var{value}.
+@end deftypefun
+
+@deftypefun void mv_replace_value (struct missing_values *@var{mv}, const union value *@var{value}, int @var{index})
+Replaces the discrete value with the given @var{index} in @var{mv}
+(which must contain at least @var{index} + 1 discrete values) with
+@var{value}.
+@end deftypefun
+
+The second set of functions applies only to numeric sets of
+user-missing values:
+
+@deftypefun bool mv_add_range (struct missing_values *@var{mv}, double @var{low}, double @var{high})
+Attempts to add a numeric range covering @var{low}@dots{}@var{high}
+(inclusive on both ends) to @var{mv}, which must be a numeric set of
+user-missing values.  Returns true if the range is successful added,
+false on failure.  Fails if @var{mv} already contains a range, or if
+@var{mv} contains more than one discrete value, or if @var{low} >
+@var{high}.
+@end deftypefun
+
+@deftypefun void mv_pop_range (struct missing_values *@var{mv}, double *@var{low}, double *@var{high})
+Given @var{mv}, which must be a numeric set of user-missing values
+that contains a range, removes that range from @var{mv} and stores its
+low endpoint in @code{*@var{low}} and its high endpoint in
+@code{*@var{high}}.
+@end deftypefun
+
+@node Value Labels
+@section Value Labels
+
+Each variable has a set of value labels (@pxref{VALUE LABELS,,,pspp}),
+represented as @struct{val_labs}.  A @struct{val_labs} is essentially
+a map from @union{value}s to strings.  All of the values in a set of
+value labels have the same width, which for a set of value labels
+owned by a variable (the common case) is the same as its variable.
+
+Numeric and short string sets of value labels may contain any number
+of entries.  Long string sets of value labels may not contain any
+value labels at all, due to a corresponding restriction in SPSS.  In
+PSPP we could easily eliminate this restriction, but doing so would
+also require us to extend the system file format in an incompatible
+way, which we consider a bad tradeoff.
+
+It is rarely necessary to interact directly with a @struct{val_labs}
+object.  Instead, the most common operation, looking up the label for
+a value of a given variable, can be conveniently executed through
+functions on @struct{variable}.  @xref{Variable Value Labels}, for
+details.
+
+Function prototypes and other declarations related to missing values
+are declared in @file{data/value-labels.h}.
+
+@deftp {Structure} {struct val_labs}
+Opaque type that represents a set of value labels.
+@end deftp
+
+The most often useful function for value labels is
+@func{val_labs_find}, for looking up the label associated with a
+value.
+
+@deftypefun {char *} val_labs_find (const struct val_labs *@var{val_labs}, union value @var{value})
+Looks in @var{val_labs} for a label for the given @var{value}.
+Returns the label, if one is found, or a null pointer otherwise.
+@end deftypefun
+
+Several other functions for working with value labels are described in
+the following section, but these are more rarely useful.
+
+@menu
+* Value Labels Creation and Destruction::
+* Value Labels Properties::
+* Value Labels Adding and Removing Labels::
+* Value Labels Iteration::
+@end menu
+
+@node Value Labels Creation and Destruction
+@subsection Creation and Destruction
+
+These functions create and destroy @struct{val_labs} objects.
+
+@deftypefun {struct val_labs *} val_labs_create (int @var{width})
+Creates and returns an initially empty set of value labels with the
+given @var{width}.
+@end deftypefun
+
+@deftypefun {struct val_labs *} val_labs_clone (const struct val_labs *@var{val_labs})
+Creates and returns a set of value labels whose width and contents are
+the same as those of @var{var_labs}.
+@end deftypefun
+
+@deftypefun void val_labs_clear (struct val_labs *@var{var_labs})
+Deletes all value labels from @var{var_labs}.
+@end deftypefun
+
+@deftypefun void val_labs_destroy (struct val_labs *@var{var_labs})
+Destroys @var{var_labs}, which must not be referenced again.
+@end deftypefun
+
+@node Value Labels Properties
+@subsection Value Labels Properties
+
+These functions inspect and manipulate basic properties of
+@struct{val_labs} objects.
+
+@deftypefun size_t val_labs_count (const struct val_labs *@var{val_labs})
+Returns the number of value labels in @var{val_labs}.
+@end deftypefun
+
+@deftypefun bool val_labs_can_set_width (const struct val_labs *@var{val_labs}, int @var{new_width})
+Tests whether @var{val_labs}'s width may be changed to @var{new_width}
+using @func{val_labs_set_width}.  Returns true if it is allowed, false
+otherwise.
+
+A set of value labels may be resized to a given width only if each
+value in it may be resized to that width, as determined by
+@func{value_is_resizable} (@pxref{value_is_resizable}).
+@end deftypefun
+
+@deftypefun void val_labs_set_width (struct val_labs *@var{val_labs}, int @var{new_width})
+Changes the width of @var{val_labs}'s values to @var{new_width}, which
+must be a valid new width as determined by
+@func{val_labs_can_set_width}.
+
+If @var{new_width} is a long string width, this function deletes all
+value labels from @var{val_labs}.
+@end deftypefun
+
+@node Value Labels Adding and Removing Labels
+@subsection Adding and Removing Labels
+
+These functions add and remove value labels from a @struct{val_labs}
+object.  These functions apply only to numeric and short string sets
+of value labels.  They have no effect on long string sets of value
+labels, since these sets are always empty.
+
+@deftypefun bool val_labs_add (struct val_labs *@var{val_labs}, union value @var{value}, const char *@var{label})
+Adds @var{label} to in @var{var_labs} as a label for @var{value},
+which must have the same width as the set of value labels.  Returns
+true if successful, false if @var{value} already has a label or if
+@var{val_labs} has long string width.
+@end deftypefun
+
+@deftypefun void val_labs_replace (struct val_labs *@var{val_labs}, union value @var{value}, const char *@var{label})
+Adds @var{label} to in @var{var_labs} as a label for @var{value},
+which must have the same width as the set of value labels.  If
+@var{value} already has a label in @var{var_labs}, it is replaced.
+Has no effect if @var{var_labs} has long string width.
+@end deftypefun
+
+@deftypefun bool val_labs_remove (struct val_labs *@var{val_labs}, union value @var{value})
+Removes from @var{val_labs} any label for @var{value}, which must have
+the same width as the set of value labels.  Returns true if a label
+was removed, false otherwise.
+@end deftypefun
+
+@node Value Labels Iteration
+@subsection Iterating through Value Labels
+
+These functions allow iteration through the set of value labels
+represented by a @struct{val_labs} object.  They are usually used in
+the context of a @code{for} loop:
+
+@example
+struct val_labs val_labs;
+struct val_labs_iterator *i;
+struct val_lab *vl;
+
+@dots{}
+
+for (vl = val_labs_first (val_labs, &i); vl != NULL;
+     vl = val_labs_next (val_labs, &i))
+  @{
+    @dots{}@r{do something with @code{vl}}@dots{}
+  @}
+@end example
+
+The value labels in a @struct{val_labs} must not be modified as it is
+undergoing iteration.
+
+@deftp {Structure} {struct val_lab}
+Represents a value label for iteration purposes, with two
+client-visible members:
+
+@table @code
+@item union value value
+Value being labeled, of the same width as the @struct{val_labs} being
+iterated.
+
+@item const char *label
+The label, as a null-terminated string.
+@end table
+@end deftp
+
+@deftp {Structure} {struct val_labs_iterator}
+Opaque object that represents the current state of iteration through a
+set of value value labels.  Automatically destroyed by successful
+completion of iteration.  Must be destroyed manually in other
+circumstances, by calling @func{val_labs_done}.
+@end deftp
+
+@deftypefun {struct val_lab *} val_labs_first (const struct val_labs *@var{val_labs}, struct val_labs_iterator **@var{iterator})
+If @var{val_labs} contains at least one value label, starts an
+iteration through @var{val_labs}, initializes @code{*@var{iterator}}
+to point to a newly allocated iterator, and returns the first value
+label in @var{val_labs}.  If @var{val_labs} is empty, sets
+@code{*@var{iterator}} to null and returns a null pointer.
+
+This function creates iterators that traverse sets of value labels in
+no particular order.
+@end deftypefun
+
+@deftypefun {struct val_lab *} val_labs_first_sorted (const struct val_labs *@var{val_labs}, struct val_labs_iterator **@var{iterator})
+Same as @func{val_labs_first}, except that the created iterator
+traverses the set of value labels in ascending order of value.
+@end deftypefun
+
+@deftypefun {struct val_lab *} val_labs_next (const struct val_labs *@var{val_labs}, struct val_labs_iterator **@var{iterator})
+Advances an iterator created with @func{val_labs_first} or
+@func{val_labs_first_sorted} to the next value label, which is
+returned.  If the set of value labels is exhausted, returns a null
+pointer after freeing @code{*@var{iterator}} and setting it to a null
+pointer.
+@end deftypefun
+
+@deftypefun void val_labs_done (struct val_labs_iterator **@var{iterator})
+Frees @code{*@var{iterator}} and sets it to a null pointer.  Does
+not need to be called explicitly if @func{val_labs_next} returns a
+null pointer, indicating that all value labels have been visited.
+@end deftypefun
+
+@node Variables
+@section Variables
+
+A PSPP variable is represented by @struct{variable}, an opaque type
+declared in @file{data/variable.h} along with related declarations.
+@xref{Variables,,,pspp}, for a description of PSPP variables from a
+user perspective.
+
+PSPP is unusual among computer languages in that, by itself, a PSPP
+variable does not have a value.  Instead, a variable in PSPP takes on
+a value only in the context of a case, which supplies one value for
+each variable in a set of variables (@pxref{Cases}).  The set of
+variables in a case, in turn, are ordinarily part of a dictionary
+(@pxref{Dictionaries}).
+
+Every variable has several attributes, most of which correspond
+directly to one of the variable attributes visible to PSPP users
+(@pxref{Attributes,,,pspp}).
+
+The following sections describe variable-related functions and macros.
+
+@menu
+* Variable Name::
+* Variable Type and Width::
+* Variable Missing Values::
+* Variable Value Labels::
+* Variable Print and Write Formats::
+* Variable Labels::
+* Variable GUI Attributes::
+* Variable Leave Status::
+* Dictionary Class::
+* Variable Creation and Destruction::
+* Variable Short Names::
+* Variable Relationships::
+* Variable Auxiliary Data::
+* Variable Categorical Values::
+@end menu
+
+@node Variable Name
+@subsection Variable Name
+
+A variable name is a string between 1 and @code{VAR_NAME_LEN} bytes
+long that satisfies the rules for PSPP identifiers
+(@pxref{Tokens,,,pspp}).  Variable names are mixed-case and treated
+case-insensitively.
+
+@deftypefn Macro int VAR_NAME_LEN
+Maximum length of a variable name, in bytes, currently 64.
+@end deftypefn
+
+Only one commonly useful function relates to variable names:
+
+@deftypefun {const char *} var_get_name (const struct variable *@var{var})
+Returns @var{var}'s variable name as a C string.
+@end deftypefun
+
+A few other functions are much more rarely used.  Some of these
+functions are used internally by the dictionary implementation:
+
+@anchor{var_set_name}
+@deftypefun {void} var_set_name (struct variable *@var{var}, const char *@var{new_name})
+Changes the name of @var{var} to @var{new_name}, which must be a
+``plausible'' name as defined below.
+
+This function cannot be applied to a variable that is part of a
+dictionary.  Use @func{dict_rename_var} instead (@pxref{Dictionary
+Renaming Variables}).
+@end deftypefun
+
+@anchor{var_is_plausible_name}
+@deftypefun {bool} var_is_valid_name (const char *@var{name}, bool @var{issue_error})
+@deftypefunx {bool} var_is_plausible_name (const char *@var{name}, bool @var{issue_error})
+Tests @var{name} for validity or ``plausibility.''  Returns true if
+the name is acceptable, false otherwise.  If the name is not
+acceptable and @var{issue_error} is true, also issues an error message
+explaining the violation.
+
+A valid name is one that fully satisfies all of the requirements for
+variable names (@pxref{Tokens,,,pspp}).  A ``plausible'' name is
+simply a string whose length is in the valid range and that is not a
+reserved word.  PSPP accepts plausible but invalid names as variable
+names in some contexts where the character encoding scheme is
+ambiguous, as when reading variable names from system files.
+@end deftypefun
+
+@deftypefun {enum dict_class} var_get_dict_class (const struct variable *@var{var})
+Returns the dictionary class of @var{var}'s name (@pxref{Dictionary
+Class}).
+@end deftypefun
+
+@node Variable Type and Width
+@subsection Variable Type and Width
+
+A variable's type and width are the type and width of its values
+(@pxref{Values}).
+
+@deftypefun {enum val_type} var_get_type (const struct variable *@var{var})
+Returns the type of variable @var{var}.
+@end deftypefun
+
+@deftypefun int var_get_width (const struct variable *@var{var})
+Returns the width of variable @var{var}.
+@end deftypefun
+
+@deftypefun void var_set_width (struct variable *@var{var}, int @var{width})
+Sets the width of variable @var{var} to @var{width}.  The width of a
+variable should not normally be changed after the variable is created,
+so this function is rarely used.  This function cannot be applied to a
+variable that is part of a dictionary.
+@end deftypefun
+
+@deftypefun bool var_is_numeric (const struct variable *@var{var})
+Returns true if @var{var} is a numeric variable, false otherwise.
+@end deftypefun
+
+@deftypefun bool var_is_alpha (const struct variable *@var{var})
+Returns true if @var{var} is an alphanumeric (string) variable, false
+otherwise.
+@end deftypefun
+
+@deftypefun bool var_is_short_string (const struct variable *@var{var})
+Returns true if @var{var} is a string variable of width
+@code{MAX_SHORT_STRING} or less, false otherwise.
+@end deftypefun
+
+@deftypefun bool var_is_long_string (const struct variable *var{var})
+Returns true if @var{var} is a string variable of width greater than
+@code{MAX_SHORT_STRING}, false otherwise.
+@end deftypefun
+
+@deftypefun size_t var_get_value_cnt (const struct variable *@var{var})
+Returns the number of @union{value}s needed to hold an instance of
+variable @var{var}.  @code{var_get_value_cnt (var)} is equivalent to
+@code{value_cnt_from_width (var_get_width (var))}.
+@end deftypefun
+
+@node Variable Missing Values
+@subsection Variable Missing Values
+
+A numeric or short string variable may have a set of user-missing values
+(@pxref{MISSING VALUES,,,pspp}), represented as a
+@struct{missing_values} (@pxref{User-Missing Values}).
+
+The most frequent operation on a variable's missing values is to query
+whether a value is user- or system-missing:
+
+@deftypefun bool var_is_value_missing (const struct variable *@var{var}, const union value *@var{value}, enum mv_class @var{class})
+@deftypefunx bool var_is_num_missing (const struct variable *@var{var}, double @var{value}, enum mv_class @var{class})
+@deftypefunx bool var_is_str_missing (const struct variable *@var{var}, const char @var{value}[], enum mv_class @var{class})
+Tests whether @var{value} is a missing value of the given @var{class}
+for variable @var{var} and returns true if so, false otherwise.
+@func{var_is_num_missing} may only be applied to numeric variables;
+@func{var_is_str_missing} may only be applied to string variables.
+For string variables, @var{value} must contain exactly as many
+characters as @var{var}'s width.
+
+@code{var_is_@var{type}_missing (@var{var}, @var{value}, @var{class})}
+is equivalent to @code{mv_is_@var{type}_missing
+(var_get_missing_values (@var{var}), @var{value}, @var{class})}.
+@end deftypefun
+
+In addition, a few functions are provided to work more directly with a
+variable's @struct{missing_values}:
+
+@deftypefun {const struct missing_values *} var_get_missing_values (const struct variable *@var{var})
+Returns the @struct{missing_values} associated with @var{var}.  The
+caller must not modify the returned structure.  The return value is
+always non-null.
+@end deftypefun
+
+@anchor{var_set_missing_values}
+@deftypefun {void} var_set_missing_values (struct variable *@var{var}, const struct missing_values *@var{miss})
+Changes @var{var}'s missing values to a copy of @var{miss}, or if
+@var{miss} is a null pointer, clears @var{var}'s missing values.  If
+@var{miss} is non-null, it must have the same width as @var{var} or be
+resizable to @var{var}'s width (@pxref{mv_resize}).  The caller
+retains ownership of @var{miss}.
+@end deftypefun
+
+b@deftypefun void var_clear_missing_values (struct variable *@var{var})
+Clears @var{var}'s missing values.  Equivalent to
+@code{var_set_missing_values (@var{var}, NULL)}.
+@end deftypefun
+
+@deftypefun bool var_has_missing_values (const struct variable *@var{var})
+Returns true if @var{var} has any missing values, false if it has
+none.  Equivalent to @code{mv_is_empty (var_get_missing_values (@var{var}))}.
+@end deftypefun
+
+@node Variable Value Labels
+@subsection Variable Value Labels
+
+A numeric or short string variable may have a set of value labels
+(@pxref{VALUE LABELS,,,pspp}), represented as a @struct{val_labs}
+(@pxref{Value Labels}).  The most commonly useful functions for value
+labels return the value label associated with a value:
+
+@deftypefun {const char *} var_lookup_value_label (const struct variable *@var{var}, const union value *@var{value})
+Looks for a label for @var{value} in @var{var}'s set of value labels.
+Returns the label if one exists, otherwise a null pointer.
+@end deftypefun
+
+@deftypefun {const char *} var_get_value_name (const struct variable *@var{var}, const union value *@var{value})
+Looks for a label for @var{value} in @var{var}'s set of value labels.
+Returns the label if one exists.  If none exists, formats @var{label}
+using @var{var}'s print format (@pxref{Variable Formats}) in a static
+buffer and returns the buffer.
+
+@quotation Important
+This function's use of a static buffer means that it must be used with
+care.
+@end quotation
+@end deftypefun
+
+The underlying @struct{val_labs} structure may also be accessed
+directly using the functions described below.
+
+@deftypefun bool var_has_value_labels (const struct variable *@var{var})
+Returns true if @var{var} has at least one value label, false
+otherwise.
+@end deftypefun
+
+@deftypefun {const struct val_labs *} var_get_value_labels (const struct variable *@var{var})
+Returns the @struct{val_labs} associated with @var{var}.  If @var{var}
+has no value labels, then the return value may or may not be a null
+pointer.
+
+The variable retains ownership of the returned @struct{val_labs},
+which the caller must not attempt to modify.
+@end deftypefun
+
+@deftypefun void var_set_value_labels (struct variable *@var{var}, const struct val_labs *@var{val_labs})
+Replaces @var{var}'s value labels by a copy of @var{val_labs}.  The
+caller retains ownership of @var{val_labs}.  If @var{val_labs} is a
+null pointer, then @var{var}'s value labels, if any, are deleted.
+@end deftypefun
+
+@deftypefun void var_clear_value_labels (struct variable *@var{var})
+Deletes @var{var}'s value labels.  Equivalent to
+@code{var_set_value_labels (@var{var}, NULL)}.
+@end deftypefun
+
+A final group of functions offers shorthands for operations that would
+otherwise require getting the value labels from a variable, copying
+them, modifying them, and then setting the modified value labels into
+the variable (making a second copy):
+
+@deftypefun bool var_add_value_label (struct variable *@var{var}, const union value *@var{value}, const char *@var{label})
+Attempts to add a copy of @var{label} as a label for @var{value} for
+the given @var{var}.  If @var{value} already has a label, then the old
+label is retained.  Returns true if a label is added, false if there
+was an existing label for @var{value} or if @var{var} is a long string
+variable.  Either way, the caller retains ownership of @var{value} and
+@var{label}.
+@end deftypefun
+
+@deftypefun void var_replace_value_label (struct variable *@var{var}, const union value *@var{value}, const char *@var{label})
+Attempts to add a copy of @var{label} as a label for @var{value} for
+the given @var{var}.  If @var{value} already has a label, then
+@var{label} replaces the old label.  Either way, the caller retains
+ownership of @var{value} and @var{label}.
+
+If @var{var} is a long string variable, this function has no effect.
+@end deftypefun
+
+@node Variable Print and Write Formats
+@subsection Variable Print and Write Formats
+
+Each variable has an associated pair of output formats, called its
+@dfn{print format} and @dfn{write format}.  @xref{Input and Output
+Formats,,,pspp}, for an introduction to formats.  @xref{Input and
+Output Formats}, for a developer's description of format
+representation.
+
+The print format is used to convert a variable's data values to
+strings for human-readable output.  The write format is used similarly
+for machine-readable output, primarily by the WRITE transformation
+(@pxref{WRITE,,,pspp}).  Most often a variable's print and write
+formats are the same.
+
+A newly created variable by default has format F8.2 if it is numeric
+or an A format with the same width as the variable if it is string.
+Many creators of variables override these defaults.
+
+Both the print format and write format are output formats.  Input
+formats are not part of @struct{variable}.  Instead, input programs
+and transformations keep track of variable input formats themselves.
+
+The following functions work with variable print and write formats.
+
+@deftypefun {const struct fmt_spec *} var_get_print_format (const struct variable *@var{var})
+@deftypefunx {const struct fmt_spec *} var_get_write_format (const struct variable *@var{var})
+Returns @var{var}'s print or write format, respectively.
+@end deftypefun
+
+@deftypefun void var_set_print_format (struct variable *@var{var}, const struct fmt_spec *@var{format})
+@deftypefunx void var_set_write_format (struct variable *@var{var}, const struct fmt_spec *@var{format})
+@deftypefunx void var_set_both_formats (struct variable *@var{var}, const struct fmt_spec *@var{format})
+Sets @var{var}'s print format, write format, or both formats,
+respectively, to a copy of @var{format}.
+@end deftypefun
+
+@node Variable Labels
+@subsection Variable Labels
+
+A variable label is a string that describes a variable.  Variable
+labels may contain spaces and punctuation not allowed in variable
+names.  @xref{VARIABLE LABELS,,,pspp}, for a user-level description of
+variable labels.
+
+The most commonly useful functions for variable labels are those to
+retrieve a variable's label:
+
+@deftypefun {const char *} var_to_string (const struct variable *@var{var})
+Returns @var{var}'s variable label, if it has one, otherwise
+@var{var}'s name.  In either case the caller must not attempt to
+modify or free the returned string.
+
+This function is useful for user output.
+@end deftypefun
+
+@deftypefun {const char *} var_get_label (const struct variable *@var{var})
+Returns @var{var}'s variable label, if it has one, or a null pointer
+otherwise.
+@end deftypefun
+
+A few other variable label functions are also provided:
+
+@deftypefun void var_set_label (struct variable *@var{var}, const char *@var{label})
+Sets @var{var}'s variable label to a copy of @var{label}, or removes
+any label from @var{var} if @var{label} is a null pointer or contains
+only spaces.  Leading and trailing spaces are removed from the
+variable label and its remaining content is truncated at 255 bytes.
+@end deftypefun
+
+@deftypefun void var_clear_label (struct variable *@var{var})
+Removes any variable label from @var{var}.
+@end deftypefun
+
+@deftypefun bool var_has_label (const struct variable *@var{var})
+Returns true if @var{var} has a variable label, false otherwise.
+@end deftypefun
+
+@node Variable GUI Attributes
+@subsection GUI Attributes
+
+These functions and types access and set attributes that are mainly
+used by graphical user interfaces.  Their values are also stored in
+and retrieved from system files (but not portable files).
+
+The first group of functions relate to the measurement level of
+numeric data.  New variables are assigned a nominal level of
+measurement by default.
+
+@deftp {Enumeration} {enum measure}
+Measurement level.  Available values are:
+
+@table @code
+@item MEASURE_NOMINAL
+Numeric data values are arbitrary.  Arithmetic operations and
+numerical comparisons of such data are not meaningful.
+
+@item MEASURE_ORDINAL
+Numeric data values indicate progression along a rank order.
+Arbitrary arithmetic operations such as addition are not meaningful on
+such data, but inequality comparisons (less, greater, etc.) have
+straightforward interpretations.
+
+@item MEASURE_SCALE
+Ratios, sums, etc. of numeric data values have meaningful
+interpretations.
+@end table
+
+PSPP does not have a separate category for interval data, which would
+naturally fall between the ordinal and scale measurement levels.
+@end deftp
+
+@deftypefun bool measure_is_valid (enum measure @var{measure})
+Returns true if @var{measure} is a valid level of measurement, that
+is, if it is one of the @code{enum measure} constants listed above,
+and false otherwise.
+@end deftypefun
+
+@deftypefun enum measure var_get_measure (const struct variable *@var{var})
+@deftypefunx void var_set_measure (struct variable *@var{var}, enum measure @var{measure})
+Gets or sets @var{var}'s measurement level.
+@end deftypefun
+
+The following set of functions relates to the width of on-screen
+columns used for displaying variable data in a graphical user
+interface environment.  The unit of measurement is the width of a
+character.  For proportionally spaced fonts, this is based on the
+average width of a character.
+
+@deftypefun int var_get_display_width (const struct variable *@var{var})
+@deftypefunx void var_set_display_width (struct variable *@var{var}, int @var{display_width})
+Gets or sets @var{var}'s display width.
+@end deftypefun
+
+@anchor{var_default_display_width}
+@deftypefun int var_default_display_width (int @var{width})
+Returns the default display width for a variable with the given
+@var{width}.  The default width of a numeric variable is 8.  The
+default width of a string variable is @var{width} or 32, whichever is
+less.
+@end deftypefun
+
+The final group of functions work with the justification of data when
+it is displayed in on-screen columns.  New variables are by default
+right-justified.
+
+@deftp {Enumeration} {enum alignment}
+Text justification.  Possible values are @code{ALIGN_LEFT},
+@code{ALIGN_RIGHT}, and @code{ALIGN_CENTRE}.
+@end deftp
+
+@deftypefun bool alignment_is_valid (enum alignment @var{alignment})
+Returns true if @var{alignment} is a valid alignment, that is, if it
+is one of the @code{enum alignment} constants listed above, and false
+otherwise.
+@end deftypefun
+
+@deftypefun enum alignment var_get_alignment (const struct variable *@var{var})
+@deftypefunx void var_set_alignment (struct variable *@var{var}, enum alignment @var{alignment})
+Gets or sets @var{var}'s alignment.
+@end deftypefun
+
+@node Variable Leave Status
+@subsection Variable Leave Status
+
+Commonly, most or all data in a case come from an input file, read
+with a command such as DATA LIST or GET, but data can also be
+generated with transformations such as COMPUTE.  In the latter case
+the question of a datum's ``initial value'' can arise.  For example,
+the value of a piece of generated data can recursively depend on its
+own value:
+@example
+COMPUTE X = X + 1.
+@end example
+Another situation where the initial value of a variable arises is when
+its value is not set at all for some cases, e.g.@: below, @code{Y} is
+set only for the first 10 cases:
+@example
+DO IF #CASENUM <= 10.
++ COMPUTE Y = 1.
+END IF.
+@end example
+
+By default, the initial value of a datum in either of these situations
+is the system-missing value for numeric values and spaces for string
+values.  This means that, above, X would be system-missing and that Y
+would be 1 for the first 10 cases and system-missing for the
+remainder.
+
+PSPP also supports retaining the value of a variable from one case to
+another, using the LEAVE command (@pxref{LEAVE,,,pspp}).  The initial
+value of such a variable is 0 if it is numeric and spaces if it is a
+string.  If the command @samp{LEAVE X Y} is appended to the above
+example, then X would have value 1 in the first case and increase by 1
+in every succeeding case, and Y would have value 1 for the first 10
+cases and 0 for later cases.
+
+The LEAVE command has no effect on data that comes from an input file
+or whose values do not depend on a variable's initial value.
+
+The value of scratch variables (@pxref{Scratch Variables,,,pspp}) are
+always left from one case to another.
+
+The following functions work with a variable's leave status.
+
+@deftypefun bool var_get_leave (const struct variable *@var{var})
+Returns true if @var{var}'s value is to be retained from case to case,
+false if it is reinitialized to system-missing or spaces.
+@end deftypefun
+
+@deftypefun void var_set_leave (struct variable *@var{var}, bool @var{leave})
+If @var{leave} is true, marks @var{var} to be left from case to case;
+if @var{leave} is false, marks @var{var} to be reinitialized for each
+case.
+
+If @var{var} is a scratch variable, @var{leave} must be true.
+@end deftypefun
+
+@deftypefun bool var_must_leave (const struct variable *@var{var})
+Returns true if @var{var} must be left from case to case, that is, if
+@var{var} is a scratch variable.
+@end deftypefun
+
+@node Dictionary Class
+@subsection Dictionary Class
+
+Occasionally it is useful to classify variables into @dfn{dictionary
+classes} based on their names.  Dictionary classes are represented by
+@enum{dict_class}.  This type and other declarations for dictionary
+classes are in the @file{<data/dict-class.h>} header.
+
+@deftp {Enumeration} {enum dict_class}
+The dictionary classes are:
+
+@table @code
+@item DC_ORDINARY
+An ordinary variable, one whose name does not begin with @samp{$} or
+@samp{#}.
+
+@item DC_SYSTEM
+A system variable, one whose name begins with @samp{$}.  @xref{System
+Variables,,,pspp}.
+
+@item DC_SCRATCH
+A scratch variable, one whose name begins with @samp{#}.
+@xref{Scratch Variables,,,pspp}.
+@end table
+
+The values for dictionary classes are bitwise disjoint, which allows
+them to be used in bit-masks.  An extra enumeration constant
+@code{DC_ALL}, whose value is the bitwise-@i{or} of all of the above
+constants, is provided to aid in this purpose.
+@end deftp
+
+One example use of dictionary classes arises in connection with PSPP
+syntax that uses @code{@var{a} TO @var{b}} to name the variables in a
+dictionary from @var{a} to @var{b} (@pxref{Sets of Variables,,,pspp}).
+This syntax requires @var{a} and @var{b} to be in the same dictionary
+class.  It limits the variables that it includes to those in that
+dictionary class.
+
+The following functions relate to dictionary classes.
+
+@deftypefun {enum dict_class} dict_class_from_id (const char *@var{name})
+Returns the ``dictionary class'' for the given variable @var{name}, by
+looking at its first letter.
+@end deftypefun
+
+@deftypefun {const char *} dict_class_to_name (enum dict_class @var{dict_class})
+Returns a name for the given @var{dict_class} as an adjective, e.g.@:
+@code{"scratch"}.
+
+This function should probably not be used in new code as it can lead
+to difficulties for internationalization.
+@end deftypefun
+
+@node Variable Creation and Destruction
+@subsection Variable Creation and Destruction
+
+Only rarely should PSPP code create or destroy variables directly.
+Ordinarily, variables are created within a dictionary and destroying
+by individual deletion from the dictionary or by destroying the entire
+dictionary at once.  The functions here enable the exceptional case,
+of creation and destruction of variables that are not associated with
+any dictionary.  These functions are used internally in the dictionary
+implementation.
+
+@anchor{var_create}
+@deftypefun {struct variable *} var_create (const char *@var{name}, int @var{width})
+Creates and returns a new variable with the given @var{name} and
+@var{width}.  The new variable is not part of any dictionary.  Use
+@func{dict_create_var}, instead, to create a variable in a dictionary
+(@pxref{Dictionary Creating Variables}).
+
+@var{name} should be a valid variable name and must be a ``plausible''
+variable name (@pxref{Variable Name}).  @var{width} must be between 0
+and @code{MAX_STRING}, inclusive (@pxref{Values}).
+
+The new variable has no user-missing values, value labels, or variable
+label.  Numeric variables initially have F8.2 print and write formats,
+right-justified display alignment, and scale level of measurement.
+String variables are created with A print and write formats,
+left-justified display alignment, and nominal level of measurement.
+The initial display width is determined by
+@func{var_default_display_width} (@pxref{var_default_display_width}).
+
+The new variable initially has no short name (@pxref{Variable Short
+Names}) and no auxiliary data (@pxref{Variable Auxiliary data}).
+@end deftypefun
+
+@anchor{var_clone}
+@deftypefun {struct variable *} var_clone (const struct variable *@var{old_var})
+Creates and returns a new variable with the same attributes as
+@var{old_var}, with a few exceptions.  First, the new variable is not
+part of any dictionary, regardless of whether @var{old_var} was in a
+dictionary.  Use @func{dict_clone_var}, instead, to add a clone of a
+variable to a dictionary.
+
+Second, the new variable is not given any short name, even if
+@var{old_var} had a short name.  This is because the new variable is
+likely to be immediately renamed, in which case the short name would
+be incorrect (@pxref{Variable Short Names}).
+
+Finally, @var{old_var}'s auxiliary data, if any, is not copied to the
+new variable (@pxref{Variable Auxiliary Data}).
+@end deftypefun
+
+@deftypefun {void} var_destroy (struct variable *@var{var})
+Destroys @var{var} and frees all associated storage, including its
+auxiliary data, if any.  @var{var} must not be part of a dictionary.
+To delete a variable from a dictionary and destroy it, use
+@func{dict_delete_var} (@pxref{Dictionary Deleting Variables}).
+@end deftypefun
+
+@node Variable Short Names
+@subsection Variable Short Names
+
+PSPP variable names may be up to 64 (@code{VAR_NAME_LEN}) bytes long.
+The system and portable file formats, however, were designed when
+variable names were limited to 8 bytes in length.  Since then, the
+system file format has been augmented with an extension record that
+explains how the 8-byte short names map to full-length names
+(@pxref{Long Variable Names Record}), but the short names are still
+present.  Thus, the continued presence of the short names is more or
+less invisible to PSPP users, but every variable in a system file
+still has a short name that must be unique.
+
+PSPP can generate unique short names for variables based on their full
+names at the time it creates the data file.  If all variables' full
+names are unique in their first 8 bytes, then the short names are
+simply prefixes of the full names; otherwise, PSPP changes them so
+that they are unique.
+
+By itself this algorithm interoperates well with other software that
+can read system files, as long as that software understands the
+extension record that maps short names to long names.  When the other
+software does not understand the extension record, it can produce
+surprising results.  Consider a situation where PSPP reads a system
+file that contains two variables named RANKINGSCORE, then the user
+adds a new variable named RANKINGSTATUS, then saves the modified data
+as a new system file.  A program that does not understand long names
+would then see one of these variables under the name RANKINGS---either
+one, depending on the algorithm's details---and the other under a
+different name.  The effect could be very confusing: by adding a new
+and apparently unrelated variable in PSPP, the user effectively
+renamed the existing variable.
+
+To counteract this potential problem, every @struct{variable} may have
+a short name.  A variable created by the system or portable file
+reader receives the short name from that data file.  When a variable
+with a short name is written to a system or portable file, that
+variable receives priority over other long names whose names begin
+with the same 8 bytes but which were not read from a data file under
+that short name.
+
+Variables not created by the system or portable file reader have no
+short name by default.
+
+A variable with a full name of 8 bytes or less in length has absolute
+priority for that name when the variable is written to a system file,
+even over a second variable with that assigned short name.
+
+PSPP does not enforce uniqueness of short names, although the short
+names read from any given data file will always be unique.  If two
+variables with the same short name are written to a single data file,
+neither one receives priority.
+
+The following macros and functions relate to short names.
+
+@defmac SHORT_NAME_LEN
+Maximum length of a short name, in bytes.  Its value is 8.
+@end defmac
+
+@deftypefun {const char *} var_get_short_name (const struct variable *@var{var})
+Returns @var{var}'s short name, or a null pointer if @var{var} has not
+been assigned a short name.
+@end deftypefun
+
+@deftypefun void var_set_short_name (struct variable *@var{var}, const char *@var{short_name})
+Sets @var{var}'s short name to @var{short_name}, or removes
+@var{var}'s short name if @var{short_name} is a null pointer.  If it
+is non-null, then @var{short_name} must be a plausible name for a
+variable (@pxref{var_is_plausible_name}).  The name will be truncated
+to 8 bytes in length and converted to all-uppercase.
+@end deftypefun
+
+@deftypefun void var_clear_short_name (struct variable *@var{var})
+Removes @var{var}'s short name.
+@end deftypefun
+
+@node Variable Relationships
+@subsection Variable Relationships
+
+Variables have close relationships with dictionaries
+(@pxref{Dictionaries}) and cases (@pxref{Cases}).  A variable is
+usually a member of some dictionary, and a case is often used to store
+data for the set of variables in a dictionary.
+
+These functions report on these relationships.  They may be applied
+only to variables that are in a dictionary.
+
+@deftypefun size_t var_get_dict_index (const struct variable *@var{var})
+Returns @var{var}'s index within its dictionary.  The first variable
+in a dictionary has index 0, the next variable index 1, and so on.
+
+The dictionary index can be influenced using dictionary functions such
+as dict_reorder_var (@pxref{dict_reorder_var}).
+@end deftypefun
+
+@deftypefun size_t var_get_case_index (const struct variable *@var{var})
+Returns @var{var}'s index within a case.  The case index is an index
+into an array of @union{value} large enough to contain all the data in
+the dictionary.
+
+The returned case index can be used to access the value of @var{var}
+within a case for its dictionary, as in e.g.@: @code{case_data_idx
+(case, var_get_case_index (@var{var}))}, but ordinarily it is more
+convenient to use the data access functions that do variable-to-index
+translation internally, as in e.g.@: @code{case_data (case,
+@var{var})}.
+@end deftypefun
+
+@node Variable Auxiliary Data
+@subsection Variable Auxiliary Data
+
+Each @struct{variable} can have a single pointer to auxiliary data of
+type @code{void *}.  These functions manipulate a variable's auxiliary
+data.
+
+Use of auxiliary data is discouraged because of its lack of
+flexibility.  Only one client can make use of auxiliary data on a
+given variable at any time, even though many clients could usefully
+associate data with a variable.
+
+To prevent multiple clients from attempting to use a variable's single
+auxiliary data field at the same time, we adopt the convention that
+use of auxiliary data in the active file dictionary is restricted to
+the currently executing command.  In particular, transformations must
+not attach auxiliary data to a variable in the active file in the
+expectation that it can be used later when the active file is read and
+the transformation is executed.  To help enforce this restriction,
+auxiliary data is deleted from all variables in the active file
+dictionary after the execution of each PSPP command.
+
+This convention for safe use of auxiliary data applies only to the
+active file dictionary.  Rules for other dictionaries may be
+established separately.
+
+Auxiliary data should be replaced by a more flexible mechanism at some
+point, but no replacement mechanism has been designed or implemented
+so far.
+
+The following functions work with variable auxiliary data.
+
+@deftypefun {void *} var_get_aux (const struct variable *@var{var})
+Returns @var{var}'s auxiliary data, or a null pointer if none has been
+assigned.
+@end deftypefun
+
+@deftypefun {void *} var_attach_aux (const struct variable *@var{var}, void *@var{aux}, void (*@var{aux_dtor}) (struct variable *))
+Sets @var{var}'s auxiliary data to @var{aux}, which must not be null.
+@var{var} must not already have auxiliary data.
+
+Before @var{var}'s auxiliary data is cleared by @code{var_clear_aux},
+@var{aux_dtor}, if non-null, will be called with @var{var} as its
+argument.  It should free any storage associated with @var{aux}, if
+necessary.  @code{var_dtor_free} may be appropriate for use as
+@var{aux_dtor}:
+
+@deffn {Function} void var_dtor_free (struct variable *@var{var})
+Frees @var{var}'s auxiliary data by calling @code{free}.
+@end deffn
+@end deftypefun
+
+@deftypefun void var_clear_aux (struct variable *@var{var})
+Removes auxiliary data, if any, from @var{var}, first calling the
+destructor passed to @code{var_attach_aux}, if one was provided.
+
+Use @code{dict_clear_aux} to remove auxiliary data from every variable
+in a dictionary (@pxref{dict_clear_aux}).
+@end deftypefun
+
+@deftypefun {void *} var_detach_aux (struct variable *@var{var})
+Removes auxiliary data, if any, from @var{var}, and returns it.
+Returns a null pointer if @var{var} had no auxiliary data.
+
+Any destructor passed to @code{var_attach_aux} is not called, so the
+caller is responsible for freeing storage associated with the returned
+auxiliary data.
+@end deftypefun
+
+@node Variable Categorical Values
+@subsection Variable Categorical Values
+
+Some statistical procedures require a list of all the values that a
+categorical variable takes on.  Arranging such a list requires making
+a pass through the data, so PSPP caches categorical values in
+@struct{variable}.
+
+When variable auxiliary data is revamped to support multiple clients
+as described in the previous section, categorical values are an
+obvious candidate.  The form in which they are currently supported is
+inelegant.
+
+Categorical values are not robust against changes in the data.  That
+is, there is currently no way to detect that a transformation has
+changed data values, meaning that categorical values lists for the
+changed variables must be recomputed.  PSPP is in fact in need of a
+general-purpose caching and cache-invalidation mechanism, but none
+has yet been designed and built.
+
+The following functions work with cached categorical values.
+
+@deftypefun {struct cat_vals *} var_get_obs_vals (const struct variable *@var{var})
+Returns @var{var}'s set of categorical values.  Yields undefined
+behavior if @var{var} does not have any categorical values.
+@end deftypefun
+
+@deftypefun void var_set_obs_vals (const struct variable *@var{var}, struct cat_vals *@var{cat_vals})
+Destroys @var{var}'s categorical values, if any, and replaces them by
+@var{cat_vals}, ownership of which is transferred to @var{var}.  If
+@var{cat_vals} is a null pointer, then @var{var}'s categorical values
+are cleared.
+@end deftypefun
+
+@deftypefun bool var_has_obs_vals (const struct variable *@var{var})
+Returns true if @var{var} has a set of categorical values, false
+otherwise.
+@end deftypefun
+
+@node Dictionaries
+@section Dictionaries
+
+Each data file in memory or on disk has an associated dictionary,
+whose primary purpose is to describe the data in the file.
+@xref{Variables,,,pspp}, for a PSPP user's view of a dictionary.
+
+A data file stored in a PSPP format, either as a system or portable
+file, has a representation of its dictionary embedded in it.  Other
+kinds of data files are usually not self-describing enough to
+construct a dictionary unassisted, so the dictionaries for these files
+must be specified explicitly with PSPP commands such as @cmd{DATA
+LIST}.
+
+The most important content of a dictionary is an array of variables,
+which must have unique names.  A dictionary also conceptually contains
+a mapping from each of its variables to a location within a case
+(@pxref{Cases}), although in fact these mappings are stored within
+individual variables.
+
+System variables are not members of any dictionary (@pxref{System
+Variables,,,pspp}).
+
+Dictionaries are represented by @struct{dictionary}.  Declarations
+related to dictionaries are in the @file{<data/dictionary.h>} header.
+
+The following sections describe functions for use with dictionaries.
+
+@menu
+* Dictionary Variable Access::
+* Dictionary Creating Variable::
+* Dictionary Deleting Variables::
+* Dictionary Reordering Variables::
+* Dictionary Renaming Variables::
+* Dictionary Weight Variable::
+* Dictionary Filter Variable::
+* Dictionary Case Limit::
+* Dictionary Split Variables::
+* Dictionary File Label::
+* Dictionary Documents::
+@end menu
+
+@node Dictionary Variable Access
+@subsection Accessing Variables
+
+The most common operations on a dictionary simply retrieve a
+@code{struct variable *} of an individual variable based on its name
+or position.
+
+@deftypefun {struct variable *} dict_lookup_var (const struct dictionary *@var{dict}, const char *@var{name})
+@deftypefunx {struct variable *} dict_lookup_var_assert (const struct dictionary *@var{dict}, const char *@var{name})
+Looks up and returns the variable with the given @var{name} within
+@var{dict}.  Name lookup is not case-sensitive.
+
+@code{dict_lookup_var} returns a null pointer if @var{dict} does not
+contain a variable named @var{name}.  @code{dict_lookup_var_assert}
+asserts that such a variable exists.
+@end deftypefun
+
+@deftypefun {struct variable *} dict_get_var (const struct dictionary *@var{dict}, size_t @var{position})
+Returns the variable at the given @var{position} in @var{dict}.
+@var{position} must be less than the number of variables in @var{dict}
+(see below).
+@end deftypefun
+
+@deftypefun size_t dict_get_var_cnt (const struct dictionary *@var{dict})
+Returns the number of variables in @var{dict}.
+@end deftypefun
+
+Another pair of functions allows retrieving a number of variables at
+once.  These functions are more rarely useful.
+
+@deftypefun void dict_get_vars (const struct dictionary *@var{dict}, const struct variable ***@var{vars}, size_t *@var{cnt}, enum dict_class @var{exclude})
+@deftypefunx void dict_get_vars_mutable (const struct dictionary *@var{dict}, struct variable ***@var{vars}, size_t *@var{cnt}, enum dict_class @var{exclude})
+Retrieves all of the variables in @var{dict}, in their original order,
+except that any variables in the dictionary classes specified
+@var{exclude}, if any, are excluded (@pxref{Dictionary Class}).
+Pointers to the variables are stored in an array allocated with
+@code{malloc}, and a pointer to the first element of this array is
+stored in @code{*@var{vars}}.  The caller is responsible for freeing
+this memory when it is no longer needed.  The number of variables
+retrieved is stored in @code{*@var{cnt}}.
+
+The presence or absence of @code{DC_SYSTEM} in @var{exclude} has no
+effect, because dictionaries never include system variables.
+@end deftypefun
+
+One additional function is available.  This function is most often
+used in assertions, but it is not restricted to such use.
+
+@deftypefun bool dict_contains_var (const struct dictionary *@var{dict}, const struct variable *@var{var})
+Tests whether @var{var} is one of the variables in @var{dict}.
+Returns true if so, false otherwise.
+@end deftypefun
+
+@node Dictionary Creating Variable
+@subsection Creating Variables
+
+These functions create a new variable and insert it into a dictionary
+in a single step.
+
+There is no provision for inserting an already created variable into a
+dictionary.  There is no reason that such a function could not be
+written, but so far there has been no need for one.
+
+The names provided to one of these functions should be valid variable
+names and must be plausible variable names (@pxref{Variable Names}).
+
+If a variable with the same name already exists in the dictionary, the
+non-@code{assert} variants of these functions return a null pointer,
+without modifying the dictionary.  The @code{assert} variants, on the
+other hand, assert that no duplicate name exists.
+
+A variable may be in only one dictionary at any given time.
+
+@deftypefun {struct variable *} dict_create_var (struct dictionary *@var{dict}, const char *@var{name}, int @var{width})
+@deftypefunx {struct variable *} dict_create_var_assert (struct dictionary *@var{dict}, const char *@var{name}, int @var{width})
+Creates a new variable with the given @var{name} and @var{width}, as
+if through a call to @code{var_create} with those arguments
+(@pxref{var_create}), appends the new variable to @var{dict}'s array
+of variables, and returns the new variable.
+@end deftypefun
+
+@deftypefun {struct variable *} dict_clone_var (struct dictionary *@var{dict}, const struct variable *@var{old_var}, const char *@var{name})
+@deftypefunx {struct variable *} dict_clone_var_assert (struct dictionary *@var{dict}, const struct variable *@var{old_var}, const char *@var{name})
+Creates a new variable as a clone of @var{var}, inserts the new
+variable into @var{dict}, and returns the new variable.  The new
+variable is named @var{name}.  Other properties of the new variable
+are copied from @var{old_var}, except for those not copied by
+@code{var_clone} (@pxref{var_clone}).
+
+@var{var} does not need to be a member of any dictionary.
+@end deftypefun
+
+@node Dictionary Deleting Variables
+@subsection Deleting Variables
+
+These functions remove variables from a dictionary's array of
+variables.  They also destroy the removed variables and free their
+associated storage.
+
+Deleting a variable to which there might be external pointers is a bad
+idea.  In particular, deleting variables from the active file
+dictionary is a risky proposition, because transformations can retain
+references to arbitrary variables.  Therefore, no variable should be
+deleted from the active file dictionary when any transformations are
+active, because those transformations might reference the variable to
+be deleted.  The safest time to delete a variable is just after a
+procedure has been executed, as done by @cmd{DELETE VARIABLES}.
+
+Deleting a variable automatically removes references to that variable
+from elsewhere in the dictionary as a weighting variable, filter
+variable, @cmd{SPLIT FILE} variable, or member of a vector.
+
+No functions are provided for removing a variable from a dictionary
+without destroying that variable.  As with insertion of an existing
+variable, there is no reason that this could not be implemented, but
+so far there has been no need.
+
+@deftypefun void dict_delete_var (struct dictionary *@var{dict}, struct variable *@var{var})
+Deletes @var{var} from @var{dict}, of which it must be a member.
+@end deftypefun
+
+@deftypefun void dict_delete_vars (struct dictionary *@var{dict}, struct variable *const *@var{vars}, size_t @var{count})
+Deletes the @var{count} variables in array @var{vars} from @var{dict}.
+All of the variables in @var{vars} must be members of @var{dict}.  No
+variable may be included in @var{vars} more than once.
+@end deftypefun
+
+@deftypefun void dict_delete_consecutive_vars (struct dictionary *@var{dict}, size_t @var{idx}, size_t @var{count})
+Deletes the variables in sequential positions
+@var{idx}@dots{}@var{idx} + @var{count} (exclusive) from @var{dict},
+which must contain at least @var{idx} + @var{count} variables.
+@end deftypefun
+
+@deftypefun void dict_delete_scratch_vars (struct dictionary *@var{dict})
+Deletes all scratch variables from @var{dict}.
+@end deftypefun
+
+@node Dictionary Reordering Variables
+@subsection Changing Variable Order
+
+The variables in a dictionary are stored in an array.  These functions
+change the order of a dictionary's array of variables without changing
+which variables are in the dictionary.
+
+@deftypefun void dict_reorder_var (struct dictionary *@var{dict}, struct variable *@var{var}, size_t @var{new_index})
+Moves @var{var}, which must be in @var{dict}, so that it is at
+position @var{new_index} in @var{dict}'s array of variables.  Other
+variables in @var{dict}, if any, retain their relative positions.
+@var{new_index} must be less than the number of variables in
+@var{dict}.
+@end deftypefun
+
+@deftypefun void dict_reorder_vars (struct dictionary *@var{dict}, struct variable *const *@var{new_order}, size_t @var{count})
+Moves the @var{count} variables in @var{new_order} to the beginning of
+@var{dict}'s array of variables in the specified order.  Other
+variables in @var{dict}, if any, retain their relative positions.
+
+All of the variables in @var{new_order} must be in @var{dict}.  No
+duplicates are allowed within @var{new_order}, which means that
+@var{count} must be no greater than the number of variables in
+@var{dict}.
+@end deftypefun
+
+@node Dictionary Renaming Variables
+@subsection Renaming Variables
+
+These functions change the names of variables within a dictionary.
+The @func{var_set_name} function (@pxref{var_set_name}) cannot be
+applied directly to a variable that is in a dictionary, because
+@struct{dictionary} contains an index by name that @func{var_set_name}
+would not update.  The following functions take care to update the
+index as well.  They also ensure that variable renaming does not cause
+a dictionary to contain a duplicate variable name.
+
+@deftypefun void dict_rename_var (struct dictionary *@var{dict}, struct variable *@var{var}, const char *@var{new_name})
+Changes the name of @var{var}, which must be in @var{dict}, to
+@var{new_name}.  A variable named @var{new_name} must not already be
+in @var{dict}, unless @var{new_name} is the same as @var{var}'s
+current name.
+@end deftypefun
+
+@deftypefun bool dict_rename_vars (struct dictionary *@var{dicT}, struct variable **@var{vars}, char **@var{new_names}, size_t @var{count}, char **@var{err_name})
+Renames each of the @var{count} variables in @var{vars} to the name in
+the corresponding position of @var{new_names}.  If the renaming would
+result in a duplicate variable name, returns false and stores one of
+the names that would be be duplicated into @code{*@var{err_name}}, if
+@var{err_name} is non-null.  Otherwise, the renaming is successful,
+and true is returned.
+@end deftypefun
+
+@node Dictionary Weight Variable
+@subsection Weight Variable
+
+A data set's cases may optionally be weighted by the value of a
+numeric variable.  @xref{WEIGHT,,,pspp}, for a user view of weight
+variables.
+
+The weight variable is written to and read from system and portable
+files.
+
+The most commonly useful function related to weighting is a
+convenience function to retrieve a weighting value from a case.
+
+@deftypefun double dict_get_case_weight (const struct dictionary *@var{dict}, const struct ccase *@var{case}, bool *@var{warn_on_invalid})
+Retrieves and returns the value of the weighting variable specified by
+@var{dict} from @var{case}.  Returns 1.0 if @var{dict} has no
+weighting variable.
+
+Returns 0.0 if @var{c}'s weight value is user- or system-missing,
+zero, or negative.  In such a case, if @var{warn_on_invalid} is
+non-null and @code{*@var{warn_on_invalid}} is true,
+@func{dict_get_case_weight} also issues an error message and sets
+@code{*@var{warn_on_invalid}} to false.  To disable error reporting,
+pass a null pointer or a pointer to false as @var{warn_on_invalid} or
+use a @func{msg_disable}/@func{msg_enable} pair.
+@end deftypefun
+
+The dictionary also has a pair of functions for getting and setting
+the weight variable.
+
+@deftypefun {struct variable *} dict_get_weight (const struct dictionary *@var{dict})
+Returns @var{dict}'s current weighting variable, or a null pointer if
+the dictionary does not have a weighting variable.
+@end deftypefun
+
+@deftypefun void dict_set_weight (struct dictionary *@var{dict}, struct variable *@var{var})
+Sets @var{dict}'s weighting variable to @var{var}.  If @var{var} is
+non-null, it must be a numeric variable in @var{dict}.  If @var{var}
+is null, then @var{dict}'s weighting variable, if any, is cleared.
+@end deftypefun
+
+@node Dictionary Filter Variable
+@subsection Filter Variable
+
+When the active file is read by a procedure, cases can be excluded
+from analysis based on the values of a @dfn{filter variable}.
+@xref{FILTER,,,pspp}, for a user view of filtering.
+
+These functions store and retrieve the filter variable.  They are
+rarely useful, because the data analysis framework automatically
+excludes from analysis the cases that should be filtered.
+
+@deftypefun {struct variable *} dict_get_filter (const struct dictionary *@var{dict})
+Returns @var{dict}'s current filter variable, or a null pointer if the
+dictionary does not have a filter variable.
+@end deftypefun
+
+@deftypefun void dict_set_filter (struct dictionary *@var{dict}, struct variable *@var{var})
+Sets @var{dict}'s filter variable to @var{var}.  If @var{var} is
+non-null, it must be a numeric variable in @var{dict}.  If @var{var}
+is null, then @var{dict}'s filter variable, if any, is cleared.
+@end deftypefun
+
+@node Dictionary Case Limit
+@subsection Case Limit
+
+The limit on cases analyzed by a procedure, set by the @cmd{N OF
+CASES} command (@pxref{N OF CASES,,,pspp}), is stored as part of the
+dictionary.  The dictionary does not, on the other hand, play any role
+in enforcing the case limit (a job done by data analysis framework
+code).
+
+A case limit of 0 means that the number of cases is not limited.
+
+These functions are rarely useful, because the data analysis framework
+automatically excludes from analysis any cases beyond the limit.
+
+@deftypefun casenumber dict_get_case_limit (const struct dictionary *@var{dict})
+Returns the current case limit for @var{dict}.
+@end deftypefun
+
+@deftypefun void dict_set_case_limit (struct dictionary *@var{dict}, casenumber @var{limit})
+Sets @var{dict}'s case limit to @var{limit}.
+@end deftypefun
+
+@node Dictionary Split Variables
+@subsection Split Variables
+
+The user may use the @cmd{SPLIT FILE} command (@pxref{SPLIT
+FILE,,,pspp}) to select a set of variables on which to split the
+active file into groups of cases to be analyzed independently in each
+statistical procedure.  The set of split variables is stored as part
+of the dictionary, although the effect on data analysis is implemented
+by each individual statistical procedure.
+
+Split variables may be numeric or short or long string variables.
+
+The most useful functions for split variables are those to retrieve
+them.  Even these functions are rarely useful directly: for the
+purpose of breaking cases into groups based on the values of the split
+variables, it is usually easier to use
+@func{casegrouper_create_splits}.
+
+@deftypefun {const struct variable *const *} dict_get_split_vars (const struct dictionary *@var{dict})
+Returns a pointer to an array of pointers to split variables.  If and
+only if there are no split variables, returns a null pointer.  The
+caller must not modify or free the returned array.
+@end deftypefun
+
+@deftypefun size_t dict_get_split_cnt (const struct dictionary *@var{dict})
+Returns the number of split variables.
+@end deftypefun
+
+The following functions are also available for working with split
+variables.
+
+@deftypefun void dict_set_split_vars (struct dictionary *@var{dict}, struct variable *const *@var{vars}, size_t @var{cnt})
+Sets @var{dict}'s split variables to the @var{cnt} variables in
+@var{vars}.  If @var{cnt} is 0, then @var{dict} will not have any
+split variables.  The caller retains ownership of @var{vars}.
+@end deftypefun
+
+@deftypefun void dict_unset_split_var (struct dictionary *@var{dict}, struct variable *@var{var})
+Removes @var{var}, which must be a variable in @var{dict}, from
+@var{dict}'s split of split variables.
+@end deftypefun
+
+@node Dictionary File Label
+@subsection File Label
+
+A dictionary may optionally have an associated string that describes
+its contents, called its file label.  The user may set the file label
+with the @cmd{FILE LABEL} command (@pxref{FILE LABEL,,,pspp}).
+
+These functions set and retrieve the file label.
+
+@deftypefun {const char *} dict_get_label (const struct dictionary *@var{dict})
+Returns @var{dict}'s file label.  If @var{dict} does not have a label,
+returns a null pointer.
+@end deftypefun
+
+@deftypefun void dict_set_label (struct dictionary *@var{dict}, const char *@var{label})
+Sets @var{dict}'s label to @var{label}.  If @var{label} is non-null,
+then its content, truncated to at most 60 bytes, becomes the new file
+label.  If @var{label} is null, then @var{dict}'s label is removed.
+
+The caller retains ownership of @var{label}.
+@end deftypefun
+
+@node Dictionary Documents
+@subsection Documents
+
+A dictionary may include an arbitrary number of lines of explanatory
+text, called the dictionary's documents.  For compatibility, document
+lines have a fixed width, and lines that are not exactly this width
+are truncated or padded with spaces as necessary to bring them to the
+correct width.
+
+PSPP users can use the @cmd{DOCUMENT} (@pxref{DOCUMENT,,,psppp}),
+@cmd{ADD DOCUMENT} (@pxref{ADD DOCUMENT,,,psppp}), and @cmd{DROP
+DOCUMENTS} (@pxref{DROP DOCUMENTS,,,pspp}) commands to manipulate
+documents.
+
+@deftypefn Macro int DOC_LINE_LENGTH
+The fixed length of a document line, in bytes, defined to 80.
+@end deftypefn
+
+The following functions work with whole sets of documents.  They
+accept or return sets of documents formatted as null-terminated
+strings that are an exact multiple of @code{DOC_LINE_LENGTH}
+bytes in length.
+
+@deftypefun {const char *} dict_get_documents (const struct dictionary *@var{dict})
+Returns the documents in @var{dict}, or a null pointer if @var{dict}
+has no documents.
+@end deftypefun
+
+@deftypefun void dict_set_documents (struct dictionary *@var{dict}, const char *@var{new_documents})
+Sets @var{dict}'s documents to @var{new_documents}.  If
+@var{new_documents} is a null pointer or an empty string, then
+@var{dict}'s documents are cleared.  The caller retains ownership of
+@var{new_documents}.
+@end deftypefun
+
+@deftypefun void dict_clear_documents (struct dictionary *@var{dict})
+Clears the documents from @var{dict}.
+@end deftypefun
+
+The following functions work with individual lines in a dictionary's
+set of documents.
+
+@deftypefun void dict_add_document_line (struct dictionary *@var{dict}, const char *@var{content})
+Appends @var{content} to the documents in @var{dict}.  The text in
+@var{content} will be truncated or padded with spaces as necessary to
+make it exactly @code{DOC_LINE_LENGTH} bytes long.  The caller retains
+ownership of @var{content}.
+
+If @var{content} is over @code{DOC_LINE_LENGTH}, this function also
+issues a warning using @func{msg}.  To suppress the warning, enclose a
+call to one of this function in a @func{msg_disable}/@func{msg_enable}
+pair.
+@end deftypefun
+
+@deftypefun size_t dict_get_document_line_cnt (const struct dictionary *@var{dict})
+Returns the number of line of documents in @var{dict}.  If the
+dictionary contains no documents, returns 0.
+@end deftypefun
+
+@deftypefun void dict_get_document_line (const struct dictionary *@var{dict}, size_t @var{idx}, struct string *@var{content})
+Replaces the text in @var{content} (which must already have been
+initialized by the caller) by the document line in @var{dict} numbered
+@var{idx}, which must be less than the number of lines of documents in
+@var{dict}.  Any trailing white space in the document line is trimmed,
+so that @var{content} will have a length between 0 and
+@code{DOC_LINE_LENGTH}.
+@end deftypefun
+
+@node Cases
+@section Cases
+
+A
+
+
+
+  The set of variables is ordered
+
+A @struct{dictionary} binds together the following:
+
+@itemize @bullet
+@item
+An ordered set of variables.  @xref{Variables}, below.
+
+@item
+Optionally, a subset of the dictionary's variables that were named on
+the most recent SPLIT FILE command.  SPLIT FILE use is somewhat
+uncommon in practice, so this set is usually empty.  @xref{SPLIT
+FILE,,,pspp}.
+
+@item
+Optionally, a weighting variable.  @xref{WEIGHT,,,pspp}.
+
+@item
+Optionally, a filtering variable.  @xref{FILTER,,,pspp}.
+
+
+@end itemize
+
+@node Data Sets
+@section Data Sets
+
+A @dfn{data set} is
+
+Missing sections here:
+
+@example
+** Dictionaries
+** Variables
+** Data sets
+** Coding conventions
+** Pools
+@end example
+
+@node Coding Conventions
+@section Coding Conventions
+
+Every @file{.c} file should have @samp{#include <config.h>} as its
+first non-comment line.  No @file{.h} file should include
+@file{config.h}.
+
+@c  LocalWords:  bool
Index: b/doc/dev-data.texi
===================================================================
--- /dev/null
+++ b/doc/dev-data.texi
@@ -0,0 +1,47 @@
+@node Processing Data
+@chapter Processing Data
+
+Developer's Guide
+
+Proposed outline:
+
+@example
+* Introduction
+* Basic concepts
+** Data sets
+** Variables
+** Dictionaries
+** Coding conventions
+** Pools
+* Syntax parsing
+* Data processing
+** Reading data
+*** Casereaders generalities
+*** Casereaders from data files
+*** Casereaders from the active file
+*** Other casereaders
+** Writing data
+*** Casewriters generally
+*** Casewriters to data files
+*** Modifying the active file
+**** Modifying cases obtained from active file casereaders has no real effect
+**** Transformations; procedures that transform
+** Transforming data
+*** Sorting and merging
+*** Filtering
+*** Grouping
+**** Ordering and interaction of filtering and grouping
+*** Multiple passes over data
+*** Counting cases and case weights
+** Best practices
+*** Multiple passes with filters versus single pass with loops
+*** Sequential versus random access
+*** Managing memory
+*** Passing cases around
+*** Renaming casereaders
+*** Avoiding excessive buffering
+*** Propagating errors
+*** Avoid static/global data
+*** Don't worry about null filters, groups, etc.
+*** Be aware of reference counting semantics for cases
+@end example
Index: b/doc/dev-intro.texi
===================================================================
--- /dev/null
+++ b/doc/dev-intro.texi
@@ -0,0 +1,21 @@
+@node Introduction
+@chapter Introduction
+
+This manual is a guide to PSPP internals.  Its intended audience is
+developers who wish to modify or extend PSPP's capabilities.  The use
+of PSPP is documented in a separate manual.  @xref{Top,,,pspp}.
+
+This manual is both a tutorial and a reference manual for PSPP
+developers.  It is ultimately intended to cover everything that
+developers who wish to implement new PSPP statistical procedures and
+other commands should know.  It is currently incomplete, partly
+because existing developers have not yet spent enough time on writing,
+and partly because the interfaces not yet documented are not yet
+mature enough to making documenting them worthwhile.
+
+PSPP developers should have some familiarity with the basics of PSPP
+from a user's perspective.  This manual attempts to refer to the PSPP
+user manual's descriptions of concepts that PSPP users should find
+familiar at the time of their first reference.  However, it is
+probably a good idea to at least skim the PSPP manual before reading
+this one, if you are not already familiar with PSPP.
Index: b/doc/dev-output.texi
===================================================================
--- /dev/null
+++ b/doc/dev-output.texi
@@ -0,0 +1,2 @@
+@node Presenting Output
+@chapter Presenting Output
Index: b/doc/dev-syntax.texi
===================================================================
--- /dev/null
+++ b/doc/dev-syntax.texi
@@ -0,0 +1,2 @@
+@node Parsing Command Syntax
+@chapter Parsing Command Syntax
Index: b/doc/pspp-dev.texinfo
===================================================================
--- /dev/null
+++ b/doc/pspp-dev.texinfo
@@ -0,0 +1,113 @@
+\input texinfo @c -*- texinfo -*-
+@c %**start of header
+@setfilename pspp-dev.info
+@settitle PSPP
+@c For double-sided printing, uncomment:
+@c @setchapternewpage odd
+@c %**end of header
+
+@novalidate
+
+@include version-dev.texi
+
+@macro cmd{CMDNAME}
+\CMDNAME\
+@end macro
+@macro struct{TAG}
+@code{struct \TAG\}
+@end macro
+@macro union{TAG}
+@code{union \TAG\}
+@end macro
+@macro enum{TAG}
+@code{enum \TAG\}
+@end macro
+@macro func{NAME}
+@code{\NAME\}
+@end macro
+
+@iftex
+@finalout
+@end iftex
+
+@dircategory Math
+@direntry
+* PSPP Developer Guide: (pspp-dev). Tutorial and reference for PSPP developers.
+@end direntry
+
+@copying
+This manual is for GNU PSPP version @value{VERSION},
+software for statistical analysis.
+
+Copyright @copyright{} 1997, 1998, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,''
+and with the Back-Cover Texts as in (a) below.  A copy of the
+license is included in the section entitled ``GNU Free Documentation
+License.''
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software.  Copies published by the Free
+Software Foundation raise funds for GNU development.''
+@end quotation
+@end copying
+
+@titlepage
+@title GNU PSPP Developers Guide
+@subtitle Edition @value{EDITION}, for PSPP version @value{VERSION}
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+
+@ifnottex
+@node Top
+@top GNU PSPP Developers Guide
+
+@insertcopying
+@end ifnottex
+
+@menu
+* Introduction::                Introduction to PSPP development.
+* Basic Concepts::              Data structures and concepts.
+* Parsing Command Syntax::      How to parse command syntax.
+* Processing Data::             Data input, output, and processing.
+* Presenting Output::           Producing machine- and human-readable output.
+
+* Function Index::              Index of PSPP functions.
+* Concept Index::               Index of concepts.
+
+* Portable File Format::        Format of PSPP portable files.
+* Data File Format::            Format of PSPP system files.
+* q2c Input Format::            Format of syntax accepted by q2c.
+
+* GNU Free Documentation License:: License for copying this manual.
+@end menu
+
+@include dev-intro.texi
+@include dev-concepts.texi
+@include dev-syntax.texi
+@include dev-data.texi
+@include dev-output.texi
+
+@include function-index.texi
+@include concept-index.texi
+
+@include portable-file-format.texi
+@include data-file-format.texi
+@include q2c.texi
+
+@include fdl.texi
+
+@bye
+
+@c Local Variables:
+@c compile-command: "makeinfo pspp-dev.texinfo"
+@c End:
Index: b/doc/pspp.texinfo
===================================================================
--- a/doc/pspp.texinfo
+++ b/doc/pspp.texinfo
@@ -87,10 +87,6 @@ Software Foundation raise funds for GNU 
 
 * Configuration::               Configuring PSPP.
 
-* Portable File Format::        Format of PSPP portable files.
-* System File Format::          Format of PSPP system files.
-* q2c Input Format::            Format of syntax accepted by q2c.
-
 * GNU Free Documentation License:: License for copying this manual.
 @end menu
 
@@ -117,10 +113,6 @@ Software Foundation raise funds for GNU 
 
 @include configuring.texi
 
-@include portable-file-format.texi
-@include data-file-format.texi
-@include q2c.texi
-
 @include fdl.texi
 
 @bye
Index: b/doc/utilities.texi
===================================================================
--- a/doc/utilities.texi
+++ b/doc/utilities.texi
@@ -406,6 +406,7 @@ files.  The data input subcommands are
 
 @table @asis
 @item BLANKS
+@anchor{SET BLANKS}
 This is the value assigned to an item data item that is empty or
 contains only white space.  An argument of SYSMIS or '.' will cause the
 system-missing value to be assigned to null items.  This is the
Index: b/doc/variables.texi
===================================================================
--- a/doc/variables.texi
+++ b/doc/variables.texi
@@ -378,7 +378,7 @@ statistical procedures.
 To assign a variable label to a group of variables, specify a 
 list of variable names and the variable label as a string.
 To assign different labels to different variables in the same command, 
-preceed the subsequent variable list with a slash (@samp{/}).
+precede the subsequent variable list with a slash (@samp{/}).
 
 
 @node VARIABLE ALIGNMENT
Index: b/src/data/automake.mk
===================================================================
--- a/src/data/automake.mk
+++ b/src/data/automake.mk
@@ -42,6 +42,8 @@ src_data_libdata_a_SOURCES = \
 	src/data/data-out.h \
 	src/data/datasheet.c \
 	src/data/datasheet.h \
+	src/data/dict-class.c \
+	src/data/dict-class.h \
 	src/data/dictionary.c \
 	src/data/dictionary.h \
 	src/data/file-handle-def.c \
Index: b/src/data/calendar.c
===================================================================
--- a/src/data/calendar.c
+++ b/src/data/calendar.c
@@ -2,8 +2,8 @@
 #include "calendar.h"
 #include <assert.h>
 #include <stdbool.h>
-#include "settings.h"
-#include "value.h"
+#include <data/settings.h>
+#include <data/val-type.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
Index: b/src/data/case.h
===================================================================
--- a/src/data/case.h
+++ b/src/data/case.h
@@ -14,8 +14,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#ifndef HEADER_CASE
-#define HEADER_CASE
+#ifndef DATA_CASE_H
+#define DATA_CASE_H 1
 
 #include <limits.h>
 #include <stddef.h>
@@ -82,4 +82,4 @@ int case_compare_2dict (const struct cca
 const union value *case_data_all (const struct ccase *);
 union value *case_data_all_rw (struct ccase *);
 
-#endif /* case.h */
+#endif /* data/case.h */
Index: b/src/data/data-in.h
===================================================================
--- a/src/data/data-in.h
+++ b/src/data/data-in.h
@@ -14,16 +14,15 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#if !data_in_h
-#define data_in_h 1
+#ifndef DATA_DATA_IN_H
+#define DATA_DATA_IN_H 1
 
-#include <stddef.h>
 #include <stdbool.h>
+#include <data/format.h>
 #include <libpspp/legacy-encoding.h>
 #include <libpspp/float-format.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/str.h>
-#include "format.h"
 
 enum integer_format data_in_get_integer_format (void);
 void data_in_set_integer_format (enum integer_format);
@@ -31,8 +30,9 @@ void data_in_set_integer_format (enum in
 enum float_format data_in_get_float_format (void);
 void data_in_set_float_format (enum float_format);
 
+union value;
 bool data_in (struct substring input, enum legacy_encoding,
               enum fmt_type, int implied_decimals, int first_column,
               union value *output, int width);
 
-#endif /* data-in.h */
+#endif /* data/data-in.h */
Index: b/src/data/data-out.c
===================================================================
--- a/src/data/data-out.c
+++ b/src/data/data-out.c
@@ -25,17 +25,16 @@
 #include <stdlib.h>
 #include <time.h>
 
-#include "calendar.h"
-#include "format.h"
-#include "settings.h"
-#include "value.h"
+#include <data/calendar.h>
+#include <data/format.h>
+#include <data/settings.h>
+#include <data/value.h>
 
 #include <libpspp/assertion.h>
 #include <libpspp/float-format.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include <libpspp/misc.h>
 #include <libpspp/str.h>
 
 #include "minmax.h"
Index: b/src/data/dict-class.c
===================================================================
--- /dev/null
+++ b/src/data/dict-class.c
@@ -0,0 +1,60 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <data/dict-class.h>
+
+#include <libpspp/assertion.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Returns the dictionary class corresponding to a variable named
+   NAME. */
+enum dict_class
+dict_class_from_id (const char *name)
+{
+  switch (name[0])
+    {
+    default:
+      return DC_ORDINARY;
+    case '$':
+      return DC_SYSTEM;
+    case '#':
+      return DC_SCRATCH;
+    }
+}
+
+/* Returns the name of dictionary class DICT_CLASS.
+
+   This function should probably not be used in new code as it
+   can lead to difficulties for internationalization. */
+const char *
+dict_class_to_name (enum dict_class dict_class)
+{
+  switch (dict_class)
+    {
+    case DC_ORDINARY:
+      return _("ordinary");
+    case DC_SYSTEM:
+      return _("system");
+    case DC_SCRATCH:
+      return _("scratch");
+    default:
+      NOT_REACHED ();
+    }
+}
Index: b/src/data/dict-class.h
===================================================================
--- /dev/null
+++ b/src/data/dict-class.h
@@ -0,0 +1,42 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* Dictionary classes.
+
+   Occasionally it is useful to classify variables into three
+   groups: system variables (those whose names begin with $),
+   scratch variables (those whose names begin with #), and
+   ordinary variables (all others).  This header provides a
+   little bit of support for this. */
+
+#ifndef DATA_DICT_CLASS_H
+#define DATA_DICT_CLASS_H 1
+
+/* Classes of variables.
+   These values are bitwise disjoint so that they can be used in
+   masks. */
+enum dict_class
+  {
+    DC_ORDINARY = 0x0001,       /* Ordinary identifier. */
+    DC_SYSTEM = 0x0002,         /* System variable. */
+    DC_SCRATCH = 0x0004,        /* Scratch variable. */
+    DC_ALL = 0x0007             /* All of the above. */
+  };
+
+enum dict_class dict_class_from_id (const char *name);
+const char *dict_class_to_name (enum dict_class);
+
+#endif /* data/dict-class.h */
Index: b/src/data/dictionary.c
===================================================================
--- a/src/data/dictionary.c
+++ b/src/data/dictionary.c
@@ -53,7 +53,7 @@ struct dictionary
     size_t split_cnt;           /* SPLIT FILE count. */
     struct variable *weight;    /* WEIGHT variable. */
     struct variable *filter;    /* FILTER variable. */
-    size_t case_limit;          /* Current case limit (N command). */
+    casenumber case_limit;      /* Current case limit (N command). */
     char *label;		/* File label. */
     struct string documents;    /* Documents, as a string. */
     struct vector **vector;     /* Vectors of variables. */
@@ -257,21 +257,26 @@ dict_get_var (const struct dictionary *d
   return d->var[idx];
 }
 
-inline void
+/* Sets *VARS to an array of pointers to variables in D and *CNT
+   to the number of variables in *D.  All variables are returned
+   except for those, if any, in the classes indicated by EXCLUDE.
+   (There is no point in putting DC_SYSTEM in EXCLUDE as
+   dictionaries never include system variables.) */
+void
 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
-               size_t *cnt, unsigned exclude_classes)
+               size_t *cnt, enum dict_class exclude)
 {
-  dict_get_vars_mutable (d, (struct variable ***) vars, cnt, exclude_classes);
+  dict_get_vars_mutable (d, (struct variable ***) vars, cnt, exclude);
 }
 
 /* Sets *VARS to an array of pointers to variables in D and *CNT
    to the number of variables in *D.  All variables are returned
-   if EXCLUDE_CLASSES is 0, or it may contain one or more of (1u
-   << DC_ORDINARY), (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to
-   exclude the corresponding type of variable. */
+   except for those, if any, in the classes indicated by EXCLUDE.
+   (There is no point in putting DC_SYSTEM in EXCLUDE as
+   dictionaries never include system variables.) */
 void
 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
-               size_t *cnt, unsigned exclude_classes)
+                       size_t *cnt, enum dict_class exclude)
 {
   size_t count;
   size_t i;
@@ -279,15 +284,13 @@ dict_get_vars_mutable (const struct dict
   assert (d != NULL);
   assert (vars != NULL);
   assert (cnt != NULL);
-  assert ((exclude_classes & ~((1u << DC_ORDINARY)
-                               | (1u << DC_SYSTEM)
-                               | (1u << DC_SCRATCH))) == 0);
+  assert (exclude == (exclude & DC_ALL));
 
   count = 0;
   for (i = 0; i < d->var_cnt; i++)
     {
-      enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
-      if (!(exclude_classes & (1u << class)))
+      enum dict_class class = var_get_dict_class (d->var[i]);
+      if (!(class & exclude))
         count++;
     }
 
@@ -295,8 +298,8 @@ dict_get_vars_mutable (const struct dict
   *cnt = 0;
   for (i = 0; i < d->var_cnt; i++)
     {
-      enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
-      if (!(exclude_classes & (1u << class)))
+      enum dict_class class = var_get_dict_class (d->var[i]);
+      if (!(class & exclude))
         (*vars)[(*cnt)++] = d->var[i];
     }
   assert (*cnt == count);
@@ -480,7 +483,7 @@ reindex_vars (struct dictionary *d, size
    active on the dictionary's dataset, because those
    transformations might reference the deleted variable.  The
    safest time to delete a variable is just after a procedure has
-   been executed, as done by MODIFY VARS.
+   been executed, as done by DELETE VARIABLES.
 
    Pointers to V within D are not a problem, because
    dict_delete_var() knows to remove V from split variables,
@@ -567,7 +570,7 @@ dict_delete_scratch_vars (struct diction
   assert (d != NULL);
 
   for (i = 0; i < d->var_cnt; )
-    if (dict_class_from_id (var_get_name (d->var[i])) == DC_SCRATCH)
+    if (var_get_dict_class (d->var[i]) == DC_SCRATCH)
       dict_delete_var (d, d->var[i]);
     else
       i++;
@@ -734,11 +737,12 @@ dict_get_weight (const struct dictionary
   return d->weight;
 }
 
-/* Returns the value of D's weighting variable in case C, except that a
-   negative weight is returned as 0.  Returns 1 if the dictionary is
-   unweighted. Will warn about missing, negative, or zero values if
-   warn_on_invalid is true. The function will set warn_on_invalid to false
-   if an invalid weight is found. */
+/* Returns the value of D's weighting variable in case C, except
+   that a negative weight is returned as 0.  Returns 1 if the
+   dictionary is unweighted.  Will warn about missing, negative,
+   or zero values if *WARN_ON_INVALID is true.  The function will
+   set *WARN_ON_INVALID to false if an invalid weight is
+   found. */
 double
 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
 		      bool *warn_on_invalid)
@@ -798,6 +802,7 @@ dict_set_filter (struct dictionary *d, s
 {
   assert (d != NULL);
   assert (v == NULL || dict_contains_var (d, v));
+  assert (v == NULL || var_is_numeric (v));
 
   d->filter = v;
 
@@ -809,7 +814,7 @@ dict_set_filter (struct dictionary *d, s
 
 /* Returns the case limit for dictionary D, or zero if the number
    of cases is unlimited. */
-size_t
+casenumber
 dict_get_case_limit (const struct dictionary *d)
 {
   assert (d != NULL);
@@ -820,7 +825,7 @@ dict_get_case_limit (const struct dictio
 /* Sets CASE_LIMIT as the case limit for dictionary D.  Use
    0 for CASE_LIMIT to indicate no limit. */
 void
-dict_set_case_limit (struct dictionary *d, size_t case_limit)
+dict_set_case_limit (struct dictionary *d, casenumber case_limit)
 {
   assert (d != NULL);
 
@@ -913,7 +918,7 @@ dict_count_values (const struct dictiona
   cnt = 0;
   for (i = 0; i < d->var_cnt; i++)
     {
-      enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
+      enum dict_class class = var_get_dict_class (d->var[i]);
       if (!(exclude_classes & (1u << class)))
         cnt += var_get_value_cnt (d->var[i]);
     }
@@ -941,20 +946,25 @@ dict_get_split_cnt (const struct diction
   return d->split_cnt;
 }
 
-/* Removes variable V from the set of split variables in dictionary D */
+/* Removes variable V, which must be in D, from D's set of split
+   variables. */
 void
-dict_unset_split_var (struct dictionary *d,
-		      struct variable *v)
+dict_unset_split_var (struct dictionary *d, struct variable *v)
 {
-  const int count = d->split_cnt;
-  d->split_cnt = remove_equal (d->split, d->split_cnt, sizeof *d->split,
-                               &v, compare_var_ptrs, NULL);
+  int orig_count;
 
-  if ( count == d->split_cnt)
-    return;
+  assert (dict_contains_var (d, v));
 
-  if ( d->callbacks &&  d->callbacks->split_changed )
-    d->callbacks->split_changed (d, d->cb_data);
+  orig_count = d->split_cnt;
+  d->split_cnt = remove_equal (d->split, d->split_cnt, sizeof *d->split,
+                               &v, compare_var_ptrs, NULL);
+  if (orig_count != d->split_cnt)
+    {
+      /* We changed the set of split variables so invoke the
+         callback. */
+      if (d->callbacks &&  d->callbacks->split_changed)
+        d->callbacks->split_changed (d, d->cb_data);
+    }
 }
 
 /* Sets CNT split vars SPLIT in dictionary D. */
@@ -999,16 +1009,7 @@ dict_set_label (struct dictionary *d, co
   assert (d != NULL);
 
   free (d->label);
-  if (label == NULL)
-    d->label = NULL;
-  else if (strlen (label) < 60)
-    d->label = xstrdup (label);
-  else
-    {
-      d->label = xmalloc (61);
-      memcpy (d->label, label, 60);
-      d->label[60] = '\0';
-    }
+  d->label = label != NULL ? xstrndup (label, 60) : NULL;
 }
 
 /* Returns the documents for D, or a null pointer if D has no
Index: b/src/data/dictionary.h
===================================================================
--- a/src/data/dictionary.h
+++ b/src/data/dictionary.h
@@ -14,132 +14,148 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#ifndef DICTIONARY_H
-#define DICTIONARY_H
+#ifndef DATA_DICTIONARY_H
+#define DATA_DICTIONARY_H 1
 
 #include <stdbool.h>
 #include <stddef.h>
+#include <data/case.h>
+#include <data/dict-class.h>
 
-/* Dictionary. */
-
-struct variable;
-struct dictionary;
 struct string;
+struct ccase;
 
-struct dict_callbacks
- {
-  void (*var_added) (struct dictionary *, int, void *);
-  void (*var_deleted) (struct dictionary *, int, int, int, void *);
-  void (*var_changed) (struct dictionary *, int, void *);
-  void (*var_resized) (struct dictionary *, int, int, void *);
-  void (*weight_changed) (struct dictionary *, int, void *);
-  void (*filter_changed) (struct dictionary *, int, void *);
-  void (*split_changed) (struct dictionary *, void *);
- };
-
-
+/* Creating dictionaries. */
 struct dictionary *dict_create (void);
 struct dictionary *dict_clone (const struct dictionary *);
-void dict_set_callbacks (struct dictionary *, const struct dict_callbacks *,
-			 void *);
-void dict_copy_callbacks (struct dictionary *, const struct dictionary *);
 
 
+/* Clearing and destroying dictionaries. */
 void dict_clear (struct dictionary *);
 void dict_clear_aux (struct dictionary *);
 void dict_destroy (struct dictionary *);
 
+/* Common ways to access variables. */
+struct variable *dict_lookup_var (const struct dictionary *, const char *);
+struct variable *dict_lookup_var_assert (const struct dictionary *,
+                                         const char *);
+struct variable *dict_get_var (const struct dictionary *, size_t position);
 size_t dict_get_var_cnt (const struct dictionary *);
-struct variable *dict_get_var (const struct dictionary *, size_t idx);
-inline void dict_get_vars (const struct dictionary *,
+
+/* Other access to variables. */
+bool dict_contains_var (const struct dictionary *, const struct variable *);
+void dict_get_vars (const struct dictionary *,
                     const struct variable ***vars, size_t *cnt,
-                    unsigned exclude_classes);
+                    enum dict_class exclude);
 void dict_get_vars_mutable (const struct dictionary *,
-                    struct variable ***vars, size_t *cnt,
-                    unsigned exclude_classes);
+                            struct variable ***vars, size_t *cnt,
+                            enum dict_class exclude);
 
+/* Creating variables. */
 struct variable *dict_create_var (struct dictionary *, const char *,
                                   int width);
-
 struct variable *dict_create_var_assert (struct dictionary *, const char *,
-                                  int width);
+                                         int width);
 struct variable *dict_clone_var (struct dictionary *, const struct variable *,
                                  const char *);
 struct variable *dict_clone_var_assert (struct dictionary *,
                                         const struct variable *, const char *);
 
-struct variable *dict_lookup_var (const struct dictionary *, const char *);
-struct variable *dict_lookup_var_assert (const struct dictionary *,
-                                         const char *);
-bool dict_contains_var (const struct dictionary *, const struct variable *);
+/* Deleting variables. */
 void dict_delete_var (struct dictionary *, struct variable *);
 void dict_delete_vars (struct dictionary *,
                        struct variable *const *, size_t count);
-void dict_delete_consecutive_vars (struct dictionary *d,
+void dict_delete_consecutive_vars (struct dictionary *,
                                    size_t idx, size_t count);
 void dict_delete_scratch_vars (struct dictionary *);
-void dict_reorder_var (struct dictionary *d, struct variable *v,
+
+/* Changing the order of variables. */
+void dict_reorder_var (struct dictionary *, struct variable *,
                        size_t new_index);
 void dict_reorder_vars (struct dictionary *,
                         struct variable *const *, size_t count);
+
+/* Changing variable names. */
 void dict_rename_var (struct dictionary *, struct variable *, const char *);
 bool dict_rename_vars (struct dictionary *,
                        struct variable **, char **new_names,
                        size_t count, char **err_name);
 
-struct ccase;
-struct variable *dict_get_weight (const struct dictionary *);
+/* Weight variable. */
 double dict_get_case_weight (const struct dictionary *,
 			     const struct ccase *, bool *);
+struct variable *dict_get_weight (const struct dictionary *);
 void dict_set_weight (struct dictionary *, struct variable *);
 
+/* Filter variable. */
 struct variable *dict_get_filter (const struct dictionary *);
 void dict_set_filter (struct dictionary *, struct variable *);
 
-size_t dict_get_case_limit (const struct dictionary *);
-void dict_set_case_limit (struct dictionary *, size_t);
+/* Case limit (N OF CASES). */
+casenumber dict_get_case_limit (const struct dictionary *);
+void dict_set_case_limit (struct dictionary *, casenumber);
 
+/* Size of cases for this dictionary. */
 int dict_get_next_value_idx (const struct dictionary *);
 size_t dict_get_case_size (const struct dictionary *);
 
+/* Making this dictionary's cases smaller (if some variables were
+   deleted). */
 size_t dict_count_values (const struct dictionary *,
                           unsigned int exclude_classes);
 void dict_compact_values (struct dictionary *);
 
+/* SPLIT FILE variables. */
 const struct variable *const *dict_get_split_vars (const struct dictionary *);
 size_t dict_get_split_cnt (const struct dictionary *);
 void dict_set_split_vars (struct dictionary *,
                           struct variable *const *, size_t cnt);
-void dict_unset_split_var (struct dictionary *d,
-			   struct variable *v);
+void dict_unset_split_var (struct dictionary *, struct variable *);
 
+/* File label. */
 const char *dict_get_label (const struct dictionary *);
 void dict_set_label (struct dictionary *, const char *);
 
-/* Fixed length of lines in dictionary documents. */
-#define DOC_LINE_LENGTH 80
+/* Documents. */
+#define DOC_LINE_LENGTH 80 /* Fixed length of document lines. */
 
 const char *dict_get_documents (const struct dictionary *);
 void dict_set_documents (struct dictionary *, const char *);
 void dict_clear_documents (struct dictionary *);
+
 void dict_add_document_line (struct dictionary *, const char *);
 size_t dict_get_document_line_cnt (const struct dictionary *);
 void dict_get_document_line (const struct dictionary *,
                              size_t, struct string *);
 
-bool dict_create_vector (struct dictionary *,
-                         const char *name,
+/* Vectors. */
+bool dict_create_vector (struct dictionary *, const char *name,
                          struct variable **, size_t cnt);
-void dict_create_vector_assert (struct dictionary *,
-                                const char *name,
+void dict_create_vector_assert (struct dictionary *, const char *name,
                                 struct variable **, size_t cnt);
-const struct vector *dict_get_vector (const struct dictionary *,
-                                      size_t idx);
+const struct vector *dict_get_vector (const struct dictionary *, size_t idx);
 size_t dict_get_vector_cnt (const struct dictionary *);
 const struct vector *dict_lookup_vector (const struct dictionary *,
                                          const char *name);
 void dict_clear_vectors (struct dictionary *);
 
+/* Functions to be called upon dictionary changes. */
+struct dict_callbacks
+ {
+  void (*var_added) (struct dictionary *, int, void *);
+  void (*var_deleted) (struct dictionary *, int, int, int, void *);
+  void (*var_changed) (struct dictionary *, int, void *);
+  void (*var_resized) (struct dictionary *, int, int, void *);
+  void (*weight_changed) (struct dictionary *, int, void *);
+  void (*filter_changed) (struct dictionary *, int, void *);
+  void (*split_changed) (struct dictionary *, void *);
+ };
+
+void dict_set_callbacks (struct dictionary *, const struct dict_callbacks *,
+			 void *);
+void dict_copy_callbacks (struct dictionary *, const struct dictionary *);
+
+/* Debug use only. */
 void dict_dump (const struct dictionary *);
 
-#endif /* dictionary.h */
+#endif /* data/dictionary.h */
Index: b/src/data/format.c
===================================================================
--- a/src/data/format.c
+++ b/src/data/format.c
@@ -66,7 +66,7 @@ fmt_done (void)
 {
   int t;
   for (t = 0 ; t < FMT_NUMBER_OF_FORMATS ; ++t )
-	  fmt_number_style_destroy (styles[t]);
+    fmt_number_style_destroy (styles[t]);
 }
 
 /* Returns an input format specification with type TYPE, width W,
@@ -305,18 +305,18 @@ fmt_check_output (const struct fmt_spec 
 }
 
 /* Checks that FORMAT is appropriate for a variable of the given
-   TYPE and returns true if so.  Otherwise returns false and
+   VAR_TYPE and returns true if so.  Otherwise returns false and
    emits an error message. */
 bool
-fmt_check_type_compat (const struct fmt_spec *format, enum var_type var_type)
+fmt_check_type_compat (const struct fmt_spec *format, enum val_type var_type)
 {
-  assert (var_type_is_valid (var_type));
-  if ((var_type == VAR_STRING) != (fmt_is_string (format->type) != 0))
+  assert (val_type_is_valid (var_type));
+  if ((var_type == VAL_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 == VAR_STRING ? _("String") : _("Numeric"),
-           var_type == VAR_STRING ? _("numeric") : _("string"),
+           var_type == VAL_STRING ? _("String") : _("Numeric"),
+           var_type == VAL_STRING ? _("numeric") : _("string"),
            fmt_to_string (format, str));
       return false;
     }
@@ -329,7 +329,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, var_type_from_width (width)))
+  if (!fmt_check_type_compat (format, val_type_from_width (width)))
     return false;
   if (fmt_var_width (format) != width)
     {
@@ -342,14 +342,13 @@ fmt_check_width_compat (const struct fmt
   return true;
 }
 
-/* Returns the width corresponding to the format specifier.  The
-   return value is the value of the `width' member of a `struct
-   variable' for such an input format. */
+/* Returns the width corresponding to FORMAT.  The return value
+   is the width of the `union value's required by FORMAT. */
 int
-fmt_var_width (const struct fmt_spec *spec)
+fmt_var_width (const struct fmt_spec *format)
 {
-  return (spec->type == FMT_AHEX ? spec->w / 2
-          : spec->type == FMT_A ? spec->w
+  return (format->type == FMT_AHEX ? format->w / 2
+          : format->type == FMT_A ? format->w
           : 0);
 }
 
@@ -499,7 +498,8 @@ fmt_max_output_decimals (enum fmt_type t
 int
 fmt_step_width (enum fmt_type type)
 {
-  return fmt_get_category (type) == FMT_CAT_HEXADECIMAL ? 2 : 1;
+  return (fmt_get_category (type) == FMT_CAT_HEXADECIMAL || type == FMT_AHEX
+          ? 2 : 1);
 }
 
 /* Returns true if TYPE is used for string fields,
@@ -868,9 +868,9 @@ fmt_set_style (enum fmt_type type, struc
   assert (ss_length (style->suffix) <= FMT_STYLE_AFFIX_MAX);
   assert (ss_length (style->neg_suffix) <= FMT_STYLE_AFFIX_MAX);
   assert (style->decimal == '.' || style->decimal == ',');
-  assert (style->grouping != style->decimal
-          && (style->grouping == '.' || style->grouping == ','
-              || style->grouping == 0));
+  assert (style->grouping == '.' || style->grouping == ','
+          || style->grouping == 0);
+  assert (style->grouping != style->decimal);
 
   assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
   assert (styles[type] != NULL);
Index: b/src/data/format.h
===================================================================
--- a/src/data/format.h
+++ b/src/data/format.h
@@ -14,17 +14,21 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#ifndef FORMAT_H
-#define FORMAT_H 1
+#ifndef DATA_FORMAT_H
+#define DATA_FORMAT_H 1
 
 /* Display format types. */
 
 #include <stdbool.h>
-#include <stddef.h>
-#include <data/variable.h>
 #include <libpspp/str.h>
+#include <data/val-type.h>
 
-/* Format type categories. */
+/* Format type categories.
+
+   Each format is in exactly one category.  We give categories
+   bitwise disjoint values only to enable bitwise comparisons
+   against a mask of FMT_CAT_* values, not to allow multiple
+   categories per format. */
 enum fmt_category
   {
     /* Numeric formats. */
@@ -41,6 +45,7 @@ enum fmt_category
     FMT_CAT_STRING         = 0x100      /* String formats. */
   };
 
+/* Format type. */
 enum fmt_type
   {
 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) FMT_##NAME,
@@ -64,8 +69,6 @@ struct fmt_spec
     int d;			/* Number of implied decimal places. */
   };
 
-union value;
-
 /* Initialization. */
 void fmt_init (void);
 void fmt_done (void);
@@ -74,13 +77,13 @@ void fmt_done (void);
 struct fmt_spec fmt_for_input (enum fmt_type, int w, int d) PURE_FUNCTION;
 struct fmt_spec fmt_for_output (enum fmt_type, int w, int d) PURE_FUNCTION;
 struct fmt_spec fmt_for_output_from_input (const struct fmt_spec *);
-struct fmt_spec fmt_default_for_width (int var_width);
+struct fmt_spec fmt_default_for_width (int width);
 
 /* Verifying formats. */
 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 *, enum var_type);
+bool fmt_check_type_compat (const struct fmt_spec *, enum val_type);
 bool fmt_check_width_compat (const struct fmt_spec *, int var_width);
 
 /* Working with formats. */
@@ -108,11 +111,11 @@ bool fmt_is_numeric (enum fmt_type) PURE
 enum fmt_category fmt_get_category (enum fmt_type) PURE_FUNCTION;
 
 enum fmt_type fmt_input_to_output (enum fmt_type) PURE_FUNCTION;
+bool fmt_usable_for_input (enum fmt_type) PURE_FUNCTION;
 
 int fmt_to_io (enum fmt_type) PURE_FUNCTION;
 bool fmt_from_io (int io, enum fmt_type *);
 
-bool fmt_usable_for_input (enum fmt_type) PURE_FUNCTION;
 const char *fmt_date_template (enum fmt_type) PURE_FUNCTION;
 char *fmt_dollar_template (const struct fmt_spec *);
 
@@ -134,15 +137,15 @@ struct fmt_number_style
 struct fmt_number_style *fmt_number_style_create (void);
 void fmt_number_style_destroy (struct fmt_number_style *);
 
-const struct fmt_number_style *fmt_get_style (enum fmt_type);
-void fmt_set_style (enum fmt_type, struct fmt_number_style *);
-
 int fmt_affix_width (const struct fmt_number_style *);
 int fmt_neg_affix_width (const struct fmt_number_style *);
 
+const struct fmt_number_style *fmt_get_style (enum fmt_type);
+void fmt_set_style (enum fmt_type, struct fmt_number_style *);
+
 int fmt_decimal_char (enum fmt_type);
 int fmt_grouping_char (enum fmt_type);
 
 void fmt_set_decimal (char);
 
-#endif /* format.h */
+#endif /* data/format.h */
Index: b/src/data/missing-values.c
===================================================================
--- a/src/data/missing-values.c
+++ b/src/data/missing-values.c
@@ -18,6 +18,7 @@
 #include "missing-values.h"
 #include <assert.h>
 #include <stdlib.h>
+#include <libpspp/array.h>
 #include <libpspp/assertion.h>
 #include "variable.h"
 #include <libpspp/str.h>
@@ -129,27 +130,18 @@ mv_add_num (struct missing_values *mv, d
    missing values MV.  Returns true if successful, false if MV
    has no room for a range, or if LOW > HIGH. */
 bool
-mv_add_num_range (struct missing_values *mv, double low, double high)
+mv_add_range (struct missing_values *mv, double low, double high)
 {
   assert (mv->width == 0);
-  if (low > high)
-    return false;
-  switch (mv->type)
+  if (low <= high && (mv->type == MVT_NONE || mv->type == MVT_1))
     {
-    case MVT_NONE:
-    case MVT_1:
       mv->values[1].f = low;
       mv->values[2].f = high;
       mv->type |= 4;
       return true;
-
-    case MVT_2:
-    case MVT_3:
-    case MVT_RANGE:
-    case MVT_RANGE_1:
-      return false;
     }
-  NOT_REACHED ();
+  else
+    return false;
 }
 
 /* Returns true if MV contains an individual value,
@@ -157,44 +149,36 @@ mv_add_num_range (struct missing_values 
 bool
 mv_has_value (const struct missing_values *mv)
 {
-  switch (mv->type)
-    {
-    case MVT_1:
-    case MVT_2:
-    case MVT_3:
-    case MVT_RANGE_1:
-      return true;
-
-    case MVT_NONE:
-    case MVT_RANGE:
-      return false;
-    }
-  NOT_REACHED ();
+  return mv_n_values (mv) > 0;
 }
 
 /* Removes one individual value from MV and stores it in *V.
    MV must contain an individual value (as determined by
-   mv_has_value()). */
+   mv_has_value()).
+
+   We remove the first value from MV, not the last, because the
+   common use for this function is in iterating through a set of
+   missing values.  If we remove the last value then we'll output
+   the missing values in order opposite of that in which they
+   were added, so that a GET followed by a SAVE would reverse the
+   order of missing values in the system file, a weird effect. */
 void
 mv_pop_value (struct missing_values *mv, union value *v)
 {
   assert (mv_has_value (mv));
+
+  *v = mv->values[0];
+  remove_element (mv->values, mv->type & 3, sizeof *mv->values, 0);
   mv->type--;
-  *v = mv->values[mv->type & 3];
 }
 
-/* Stores  a value  in *V.
-   MV must contain an individual value (as determined by
-   mv_has_value()).
-   IDX is the zero based index of the value to get
-*/
+/* Stores MV's value with index IDX in *V.
+   IDX must be less than the number of discrete values in MV, as
+   reported by mv_n_values(MV). */
 void
-mv_peek_value (const struct missing_values *mv, union value *v, int idx)
+mv_get_value (const struct missing_values *mv, union value *v, int idx)
 {
-  assert (idx >= 0 ) ;
-  assert (idx < 3);
-
-  assert (mv_has_value (mv));
+  assert (idx >= 0 && idx < mv_n_values (mv));
   *v = mv->values[idx];
 }
 
@@ -222,19 +206,7 @@ mv_n_values (const struct missing_values
 bool
 mv_has_range (const struct missing_values *mv)
 {
-  switch (mv->type)
-    {
-    case MVT_RANGE:
-    case MVT_RANGE_1:
-      return true;
-
-    case MVT_NONE:
-    case MVT_1:
-    case MVT_2:
-    case MVT_3:
-      return false;
-    }
-  NOT_REACHED ();
+  return mv->type == MVT_RANGE || mv->type == MVT_RANGE_1;
 }
 
 /* Removes the numeric range from MV and stores it in *LOW and
@@ -249,12 +221,11 @@ mv_pop_range (struct missing_values *mv,
   mv->type &= 3;
 }
 
-
 /* Returns the numeric range from MV  into *LOW and
    *HIGH.  MV must contain a individual range (as determined by
    mv_has_range()). */
 void
-mv_peek_range (const struct missing_values *mv, double *low, double *high)
+mv_get_range (const struct missing_values *mv, double *low, double *high)
 {
   assert (mv_has_range (mv));
   *low = mv->values[1].f;
@@ -288,65 +259,39 @@ using_element (unsigned type, int idx)
   NOT_REACHED ();
 }
 
-/* Returns true if S contains only spaces between indexes
-   NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
-   false otherwise. */
-static bool
-can_resize_string (const char *s, int old_width, int new_width)
-{
-  int i;
-
-  assert (new_width < old_width);
-  for (i = new_width; i < old_width; i++)
-    if (s[i] != ' ')
-      return false;
-  return true;
-}
-
 /* Returns true if MV can be resized to the given WIDTH with
-   mv_resize(), false otherwise.  Resizing to the same width is
-   always possible.  Resizing to a long string WIDTH is only
-   possible if MV is an empty set of missing values; otherwise,
-   resizing to a larger WIDTH is always possible.  Resizing to a
-   shorter width is possible only when each missing value
-   contains only spaces in the characters that will be
-   trimmed. */
+   mv_resize(), false otherwise.  Resizing is possible only when
+   each value in MV (if any) is resizable from MV's current width
+   to WIDTH, as determined by value_is_resizable.  In addition,
+   resizing must not produce a non-empty set of long string
+   missing values. */
 bool
 mv_is_resizable (const struct missing_values *mv, int width)
 {
-  if ( var_type_from_width (width) != var_type_from_width (mv->width) )
-    return false;
+  int i;
 
   if (width > MAX_SHORT_STRING && mv->type != MVT_NONE)
     return false;
 
-  if (width >= mv->width)
-    return true;
-  else
-    {
-      int i;
+  for (i = 0; i < 3; i++)
+    if (using_element (mv->type, i)
+        && !value_is_resizable (&mv->values[i], mv->width, width))
+      return false;
 
-      for (i = 0; i < 3; i++)
-        if (using_element (mv->type, i)
-            && !can_resize_string (mv->values[i].s, mv->width, width))
-          return false;
-      return true;
-    }
+  return true;
 }
 
 /* Resizes MV to the given WIDTH.  WIDTH must fit the constraints
-   explained for mv_is_resizable(). */
+   explained for mv_is_resizable. */
 void
 mv_resize (struct missing_values *mv, int width)
 {
-  assert (mv_is_resizable (mv, width));
-  if (width > mv->width && mv->type != MVT_NONE)
-    {
-      int i;
+  int i;
 
-      for (i = 0; i < 3; i++)
-        memset (mv->values[i].s + mv->width, ' ', width - mv->width);
-    }
+  assert (mv_is_resizable (mv, width));
+  for (i = 0; i < 3; i++)
+    if (using_element (mv->type, i))
+      value_resize (&mv->values[i], mv->width, width);
   mv->width = width;
 }
 
Index: b/src/data/missing-values.h
===================================================================
--- a/src/data/missing-values.h
+++ b/src/data/missing-values.h
@@ -14,11 +14,27 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#if !missing_values_h
-#define missing_values_h 1
+/* User-missing values.
+
+   struct missing_values is an opaque type that represents a set
+   of user-missing values associated with a variable.  Valid sets
+   of missing values depend on variable width:
+
+        - Numeric variables may have up to 3 discrete numeric
+          user-missing values, or a range of numeric values, or a
+          range plus one discrete value.
+
+        - Short string variables may have up to 3 discrete string
+          user-missing values.
+
+        - Long string variables may not have user-missing
+          values. */
+
+#ifndef DATA_MISSING_VALUES_H
+#define DATA_MISSING_VALUES_H 1
 
 #include <stdbool.h>
-#include "value.h"
+#include "data/value.h"
 
 /* Missing values.
    Opaque--use access functions defined below. */
@@ -26,7 +42,7 @@ struct missing_values
   {
     int type;                   /* Types of missing values, one of MVT_*. */
     int width;                  /* 0=numeric, otherwise string width. */
-    union value values[3];      /* Missing values.  [y,z] are the range. */
+    union value values[3];      /* Missing values.  [1], [2] are the range. */
   };
 
 /* Classes of missing values. */
@@ -38,41 +54,44 @@ enum mv_class
     MV_ANY = MV_USER | MV_SYSTEM /* Missing if it is user or system-missing. */
   };
 
+/* Is a value missing? */
+bool mv_is_value_missing (const struct missing_values *, const union value *,
+                          enum mv_class);
+bool mv_is_num_missing (const struct missing_values *, double, enum mv_class);
+bool mv_is_str_missing (const struct missing_values *, const char[],
+                        enum mv_class);
+
+/* Initializing missing value sets. */
 void mv_init (struct missing_values *, int width);
+void mv_copy (struct missing_values *, const struct missing_values *);
 void mv_clear (struct missing_values *);
 
-void mv_copy (struct missing_values *, const struct missing_values *);
+/* Changing width of a missing value set. */
+bool mv_is_resizable (const struct missing_values *, int width);
+void mv_resize (struct missing_values *, int width);
+
+/* Basic property inspection. */
 bool mv_is_empty (const struct missing_values *);
 int mv_get_width (const struct missing_values *);
 
+/* Inspecting discrete values. */
+int mv_n_values (const struct missing_values *);
+bool mv_has_value (const struct missing_values *);
+void mv_get_value (const struct missing_values *, union value *, int idx);
+
+/* Inspecting ranges. */
+bool mv_has_range (const struct missing_values *);
+void mv_get_range (const struct missing_values *, double *low, double *high);
+
+/* Adding and modifying discrete values. */
 bool mv_add_value (struct missing_values *, const union value *);
 bool mv_add_str (struct missing_values *, const char[]);
 bool mv_add_num (struct missing_values *, double);
-bool mv_add_num_range (struct missing_values *, double low, double high);
-
-bool mv_has_value (const struct missing_values *);
 void mv_pop_value (struct missing_values *, union value *);
-void mv_peek_value (const struct missing_values *mv, union value *v, int idx);
-void mv_replace_value (struct missing_values *mv, const union value *v, int idx);
-
-int  mv_n_values (const struct missing_values *mv);
+void mv_replace_value (struct missing_values *, const union value *, int idx);
 
-
-bool mv_has_range (const struct missing_values *);
+/* Adding and modifying ranges. */
+bool mv_add_range (struct missing_values *, double low, double high);
 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 (const struct missing_values *, int width);
-void mv_resize (struct missing_values *, int width);
-
-typedef bool mv_is_missing_func (const struct missing_values *,
-                                 const union value *);
-
-/* Is a value missing? */
-bool mv_is_value_missing (const struct missing_values *, const union value *,
-                          enum mv_class);
-bool mv_is_num_missing (const struct missing_values *, double, enum mv_class);
-bool mv_is_str_missing (const struct missing_values *, const char[],
-                        enum mv_class);
 
-#endif /* missing-values.h */
+#endif /* data/missing-values.h */
Index: b/src/data/por-file-reader.c
===================================================================
--- a/src/data/por-file-reader.c
+++ b/src/data/por-file-reader.c
@@ -33,6 +33,7 @@
 #include <data/file-name.h>
 #include <data/format.h>
 #include <data/missing-values.h>
+#include <data/short-names.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
 #include <libpspp/compiler.h>
@@ -669,8 +670,8 @@ read_variables (struct pfm_reader *r, st
           int i;
           for (i = 1; i < 100000; i++)
             {
-              char try_name[LONG_NAME_LEN + 1];
-              sprintf (try_name, "%.*s_%d", LONG_NAME_LEN - 6, name, i);
+              char try_name[VAR_NAME_LEN + 1];
+              sprintf (try_name, "%.*s_%d", VAR_NAME_LEN - 6, name, i);
               v = dict_create_var (dict, try_name, width);
               if (v != NULL)
                 break;
@@ -692,12 +693,12 @@ read_variables (struct pfm_reader *r, st
         {
           double x = read_float (r);
           double y = read_float (r);
-          mv_add_num_range (&miss, x, y);
+          mv_add_range (&miss, x, y);
         }
       else if (match (r, 'A'))
-        mv_add_num_range (&miss, read_float (r), HIGHEST);
+        mv_add_range (&miss, read_float (r), HIGHEST);
       else if (match (r, '9'))
-        mv_add_num_range (&miss, LOWEST, read_float (r));
+        mv_add_range (&miss, LOWEST, read_float (r));
 
       /* Single missing values. */
       while (match (r, '8'))
Index: b/src/data/procedure.c
===================================================================
--- a/src/data/procedure.c
+++ b/src/data/procedure.c
@@ -664,10 +664,10 @@ static trns_free_func case_limit_trns_fr
 static void
 add_case_limit_trns (struct dataset *ds)
 {
-  size_t case_limit = dict_get_case_limit (ds->dict);
+  casenumber case_limit = dict_get_case_limit (ds->dict);
   if (case_limit != 0)
     {
-      size_t *cases_remaining = xmalloc (sizeof *cases_remaining);
+      casenumber *cases_remaining = xmalloc (sizeof *cases_remaining);
       *cases_remaining = case_limit;
       add_transformation (ds, case_limit_trns_proc, case_limit_trns_free,
                           cases_remaining);
Index: b/src/data/short-names.h
===================================================================
--- a/src/data/short-names.h
+++ b/src/data/short-names.h
@@ -33,6 +33,9 @@
 
 struct dictionary;
 
+/* Maximum length of a short name, in bytes. */
+#define SHORT_NAME_LEN 8
+
 void short_names_assign (struct dictionary *);
 
 #endif /* data/short-names.h */
Index: b/src/data/sys-file-reader.c
===================================================================
--- a/src/data/sys-file-reader.c
+++ b/src/data/sys-file-reader.c
@@ -42,6 +42,7 @@
 #include <data/file-name.h>
 #include <data/format.h>
 #include <data/missing-values.h>
+#include <data/short-names.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
 #include <data/value.h>
@@ -263,8 +264,8 @@ sfm_open_reader (struct file_handle *fh,
       for (i = 0; i < dict_get_var_cnt (*dict); i++)
 	{
 	  struct variable *var = dict_get_var (*dict, i);
-	  char short_name [SHORT_NAME_LEN + 1];
-	  char long_name [SHORT_NAME_LEN + 1];
+	  char short_name[SHORT_NAME_LEN + 1];
+	  char long_name[SHORT_NAME_LEN + 1];
 
 	  strcpy (short_name, var_get_name (var));
 
@@ -542,7 +543,7 @@ read_variable_record (struct sfm_reader 
             {
               double low = read_float (r);
               double high = read_float (r);
-              mv_add_num_range (&mv, low, high);
+              mv_add_range (&mv, low, high);
               missing_value_code = -missing_value_code - 2;
             }
           for (i = 0; i < missing_value_code; i++)
Index: b/src/data/sys-file-writer.c
===================================================================
--- a/src/data/sys-file-writer.c
+++ b/src/data/sys-file-writer.c
@@ -445,14 +445,14 @@ write_variable (struct sfm_writer *w, co
   if (mv_has_range (mv))
     {
       double x, y;
-      mv_peek_range (mv, &x, &y);
+      mv_get_range (mv, &x, &y);
       write_float (w, x);
       write_float (w, y);
     }
   for (i = 0; i < mv_n_values (mv); i++)
     {
       union value value;
-      mv_peek_value (mv, &value, i);
+      mv_get_value (mv, &value, i);
       write_value (w, &value, seg0_width);
     }
 
Index: b/src/data/val-type.h
===================================================================
--- /dev/null
+++ b/src/data/val-type.h
@@ -0,0 +1,55 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2007 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 3 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_VAL_TYPE_H
+#define DATA_VAL_TYPE_H 1
+
+#include <float.h>
+#include <stdbool.h>
+#include <libpspp/float-format.h>
+
+/* Special numeric values. */
+#define SYSMIS (-DBL_MAX)               /* System-missing value. */
+#define LOWEST (float_get_lowest ())    /* Smallest nonmissing finite value. */
+#define HIGHEST DBL_MAX                 /* Largest finite value. */
+
+/* Maximum length of a string variable. */
+#define MAX_STRING 32767
+
+/* Value type. */
+enum val_type
+  {
+    VAL_NUMERIC,              /* A numeric value. */
+    VAL_STRING                /* A string value. */
+  };
+
+/* Returns true if VAL_TYPE is a valid value type. */
+static inline bool
+val_type_is_valid (enum val_type val_type)
+{
+  return val_type == VAL_NUMERIC || val_type == VAL_STRING;
+}
+
+/* Returns the value type for the given WIDTH. */
+static inline enum val_type
+val_type_from_width (int width)
+{
+  return width != 0 ? VAL_STRING : VAL_NUMERIC;
+}
+
+#endif /* data/val-type.h */
Index: b/src/data/value-labels.c
===================================================================
--- a/src/data/value-labels.c
+++ b/src/data/value-labels.c
@@ -66,7 +66,7 @@ val_labs_create (int width)
 /* Creates and returns a new set of value labels identical to
    VLS. */
 struct val_labs *
-val_labs_copy (const struct val_labs *vls)
+val_labs_clone (const struct val_labs *vls)
 {
   struct val_labs *copy;
   struct val_labs_iterator *i;
@@ -82,46 +82,29 @@ val_labs_copy (const struct val_labs *vl
   return copy;
 }
 
-/* Determines whether VLS's width can be changed to NEW_WIDTH.
-   Numeric widths cannot be changed at all.
-   Strings can be widened.  They can be shortened only if the
-   characters that will be truncated are spaces. */
+/* Determines whether VLS's width can be changed to NEW_WIDTH,
+   using the rules checked by value_is_resizable. */
 bool
 val_labs_can_set_width (const struct val_labs *vls, int new_width)
 {
-  if ( var_type_from_width (new_width) != var_type_from_width (vls->width ))
-    return false;
-
-  if (vls->width == 0)
-    return new_width == 0;
-  else if (new_width < vls->width)
-    {
-      struct val_labs_iterator *i;
-      struct val_lab *lab;
-
-      for (lab = val_labs_first (vls, &i); lab != NULL;
-           lab = val_labs_next (vls, &i))
-        {
-          int j;
-
-          /* We can shorten the value labels only if all the
-             truncated characters are blanks. */
-          for (j = vls->width; j < new_width; j++)
-            if (lab->value.s[j] != ' ')
-              {
-                val_labs_done (&i);
-                return false;
-              }
-        }
-      return true;
-    }
-  else
-    return true;
-}
+  struct val_labs_iterator *i;
+  struct val_lab *lab;
 
-/* Changes the width of VLS to NEW_WIDTH.  If VLS is numeric,
-   NEW_WIDTH must be 0, otherwise it must be within the range
-   1...MAX_SHORT_STRING inclusive. */
+  for (lab = val_labs_first (vls, &i); lab != NULL;
+       lab = val_labs_next (vls, &i))
+    if (!value_is_resizable (&lab->value, vls->width, new_width))
+      {
+        val_labs_done (&i);
+        return false;
+      }
+
+  return true;
+}
+
+/* Changes the width of VLS to NEW_WIDTH.  The original and new
+   width must be both numeric or both string.  If the new width
+   is a long string width, then any value labels in VLS are
+   deleted. */
 void
 val_labs_set_width (struct val_labs *vls, int new_width)
 {
@@ -186,64 +169,61 @@ create_int_val_lab (struct val_labs *vls
   return ivl;
 }
 
-/* If VLS does not already contain a value label for VALUE, adds
-   LABEL for it and returns true.  Otherwise, returns false.
-   Behavior is undefined if VLS's width is greater than
-   MAX_SHORT_STRING. */
+/* If VLS does not already contain a value label for VALUE (and
+   VLS represents a numeric or short string set of value labels),
+   adds LABEL for it and returns true.  Otherwise, returns
+   false. */
 bool
 val_labs_add (struct val_labs *vls, union value value, const char *label)
 {
-  struct int_val_lab *ivl;
-  void **vlpp;
-
-  assert (vls != NULL);
-  assert (vls->width <= MAX_SHORT_STRING);
   assert (label != NULL);
-
-  if (vls->labels == NULL)
-    vls->labels = hsh_create (8, compare_int_val_lab, hash_int_val_lab,
-                              free_int_val_lab, vls);
-
-  ivl = create_int_val_lab (vls, value, label);
-  vlpp = hsh_probe (vls->labels, ivl);
-  if (*vlpp == NULL)
+  if (vls->width < MIN_LONG_STRING)
     {
-      *vlpp = ivl;
-      return true;
+      struct int_val_lab *ivl;
+      void **vlpp;
+
+      if (vls->labels == NULL)
+        vls->labels = hsh_create (8, compare_int_val_lab, hash_int_val_lab,
+                                  free_int_val_lab, vls);
+
+      ivl = create_int_val_lab (vls, value, label);
+      vlpp = hsh_probe (vls->labels, ivl);
+      if (*vlpp == NULL)
+        {
+          *vlpp = ivl;
+          return true;
+        }
+      free_int_val_lab (ivl, vls);
     }
-  free_int_val_lab (ivl, vls);
   return false;
 }
 
-/* Sets LABEL as the value label for VALUE in VLS.  Returns false
-   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. */
+/* Sets LABEL as the value label for VALUE in VLS, replacing any
+   existing label for VALUE.  Has no effect if VLS has a long
+   string width. */
 void
 val_labs_replace (struct val_labs *vls, union value value, const char *label)
 {
-  assert (vls->width <= MAX_SHORT_STRING);
-  if (vls->labels != NULL)
+  if (vls->width < MIN_LONG_STRING)
     {
-      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);
+      if (vls->labels != NULL)
+        {
+          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);
+        }
+      else
+        val_labs_add (vls, value, label);
     }
-  else
-    val_labs_add (vls, value, label);
 }
 
 /* Removes any value label for VALUE within VLS.  Returns true
-   if a value label was removed. Behavior is undefined if VLS's
-   width is greater than MAX_SHORT_STRING. */
+   if a value label was removed. */
 bool
 val_labs_remove (struct val_labs *vls, union value value)
 {
-  assert (vls != NULL);
-  assert (vls->width <= MAX_SHORT_STRING);
-
-  if (vls->labels != NULL)
+  if (vls->width < MIN_LONG_STRING && vls->labels != NULL)
     {
       struct int_val_lab *ivl = create_int_val_lab (vls, value, "");
       int deleted = hsh_delete (vls->labels, ivl);
@@ -298,7 +278,10 @@ val_labs_first (const struct val_labs *v
   assert (ip != NULL);
 
   if (vls->labels == NULL || vls->width > MAX_SHORT_STRING)
-    return NULL;
+    {
+      *ip = NULL;
+      return NULL;
+    }
 
   i = *ip = xmalloc (sizeof *i);
   i->labels = hsh_data_copy (vls->labels);
@@ -322,7 +305,10 @@ val_labs_first_sorted (const struct val_
   assert (ip != NULL);
 
   if (vls->labels == NULL || vls->width > MAX_SHORT_STRING)
-    return NULL;
+    {
+      *ip = NULL;
+      return NULL;
+    }
 
   i = *ip = xmalloc (sizeof *i);
   i->lp = i->labels = hsh_sort_copy (vls->labels);
@@ -367,15 +353,13 @@ val_labs_next (const struct val_labs *vl
 void
 val_labs_done (struct val_labs_iterator **ip)
 {
-  struct val_labs_iterator *i;
-
-  assert (ip != NULL);
-  assert (*ip != NULL);
-
-  i = *ip;
-  free (i->labels);
-  free (i);
-  *ip = NULL;
+  if (*ip != NULL)
+    {
+      struct val_labs_iterator *i = *ip;
+      free (i->labels);
+      free (i);
+      *ip = NULL;
+    }
 }
 
 /* Compares two value labels and returns a strcmp()-type result. */
Index: b/src/data/value-labels.h
===================================================================
--- a/src/data/value-labels.h
+++ b/src/data/value-labels.h
@@ -14,39 +14,49 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#ifndef VAL_LABS_H
-#define VAL_LABS_H 1
+/* Sets of value labels.
+
+   struct val_labs represents a mapping from `union value's to
+   strings.  The `union value's in the mapping all have the same
+   width.  If this width is numeric or short string, the mapping
+   may contain any number of entries; long string mappings are
+   always empty. */
+
+#ifndef DATA_VALUE_LABELS_H
+#define DATA_VALUE_LABELS_H 1
 
 #include <stdbool.h>
 #include <stddef.h>
-
 #include <data/value.h>
 
-struct val_labs;
-struct variable;
-
+/* One value label. */
 struct val_lab
   {
     union value value;
     const char *label;
   };
 
+/* Creating and destroying sets of value labels. */
 struct val_labs *val_labs_create (int width);
-struct val_labs *val_labs_copy (const struct val_labs *);
-void val_labs_destroy (struct val_labs *);
+struct val_labs *val_labs_clone (const struct val_labs *);
 void val_labs_clear (struct val_labs *);
-size_t val_labs_count (const struct val_labs *);
+void val_labs_destroy (struct val_labs *);
+
+/* Looking up value labels. */
+char *val_labs_find (const struct val_labs *, union value);
 
+/* Basic properties. */
+size_t val_labs_count (const struct val_labs *);
 bool val_labs_can_set_width (const struct val_labs *, int new_width);
 void val_labs_set_width (struct val_labs *, int new_width);
 
+/* Adding value labels. */
 bool val_labs_add (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);
 
+/* Iterating through value labels. */
 struct val_labs_iterator;
-
 struct val_lab *val_labs_first (const struct val_labs *,
                                 struct val_labs_iterator **);
 struct val_lab *val_labs_first_sorted (const struct val_labs *,
@@ -55,4 +65,4 @@ struct val_lab *val_labs_next (const str
                                struct val_labs_iterator **);
 void val_labs_done (struct val_labs_iterator **);
 
-#endif /* value-labels.h */
+#endif /* data/value-labels.h */
Index: b/src/data/value.c
===================================================================
--- a/src/data/value.c
+++ b/src/data/value.c
@@ -15,8 +15,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "value.h"
+#include <data/value.h>
 
+#include <data/val-type.h>
 #include <libpspp/hash.h>
 #include <libpspp/str.h>
 
@@ -83,3 +84,32 @@ value_set_missing (union value *v, int w
   else
     memset (v->s, ' ', width);
 }
+
+/* Tests whether VALUE may be resized from OLD_WIDTH to
+   NEW_WIDTH, using the following rules that match those for
+   resizing missing values and value labels.  First, OLD_WIDTH
+   and NEW_WIDTH must be both numeric or both string.  Second, if
+   NEW_WIDTH is less than OLD_WIDTH, then the bytes that would be
+   trimmed off the right end of VALUE must be all spaces. */
+bool
+value_is_resizable (const union value *value, int old_width, int new_width)
+{
+  int i;
+
+  if (val_type_from_width (old_width) != val_type_from_width (new_width))
+    return false;
+  for (i = new_width; i < old_width; i++)
+    if (value->s[i] != ' ')
+      return false;
+  return true;
+}
+
+/* Resizes VALUE from OLD_WIDTH to NEW_WIDTH.  The arguments must
+   satisfy the rules specified above for value_is_resizable. */
+void
+value_resize (union value *value, int old_width, int new_width)
+{
+  assert (value_is_resizable (value, old_width, new_width));
+  if (new_width > old_width)
+    memset (&value->s[old_width], ' ', new_width - old_width);
+}
Index: b/src/data/value.h
===================================================================
--- a/src/data/value.h
+++ b/src/data/value.h
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007 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
@@ -14,35 +14,18 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#if !value_h
-#define value_h 1
+#ifndef DATA_VALUE_H
+#define DATA_VALUE_H 1
 
-#include <float.h>
-#include <libpspp/float-format.h>
 #include <libpspp/misc.h>
+#include <stdbool.h>
 #include "minmax.h"
 
-/* Values. */
-
 /* "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)
-#define MAX_STRING 32767
-
-/* Special values. */
-#define SYSMIS (-DBL_MAX)
-#define LOWEST (float_get_lowest ())
-#define HIGHEST DBL_MAX
-
-/* Number of "union value"s required for a variable of the given
-   WIDTH. */
-static inline size_t
-value_cnt_from_width (int width)
-{
-  return width == 0 ? 1 : DIV_RND_UP (width, MAX_SHORT_STRING);
-}
 
 /* A numeric or short string value.
    Multiple consecutive values represent a long string. */
@@ -58,7 +41,18 @@ union value *value_create (int width);
 int compare_values (const union value *, const union value *, int width);
 unsigned hash_value (const union value  *, int width);
 
+static inline size_t value_cnt_from_width (int width);
 void value_copy (union value *, const union value *, int width);
 void value_set_missing (union value *, int width);
+bool value_is_resizable (const union value *, int old_width, int new_width);
+void value_resize (union value *, int old_width, int new_width);
+
+/* Number of "union value"s required for a variable of the given
+   WIDTH. */
+static inline size_t
+value_cnt_from_width (int width)
+{
+  return width == 0 ? 1 : DIV_RND_UP (width, MAX_SHORT_STRING);
+}
 
-#endif /* !value.h */
+#endif /* data/value.h */
Index: b/src/data/vardict.h
===================================================================
--- a/src/data/vardict.h
+++ b/src/data/vardict.h
@@ -31,13 +31,14 @@ struct vardict_info
     struct dictionary *dict;  /* The dictionary containing the variable */
   };
 
+/* Called by dictionary code, defined in variable.c. */
 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 *);
 
 
-/* Called only from variable.c, but defined in dictionary.c */
+/* Called by variable.c, defined in dictionary.c. */
 void dict_var_changed (const struct variable *v);
 void dict_var_resized (const struct variable *v, int delta);
 
Index: b/src/data/variable.c
===================================================================
--- a/src/data/variable.c
+++ b/src/data/variable.c
@@ -44,7 +44,7 @@
 struct variable
   {
     /* Dictionary information. */
-    char name[LONG_NAME_LEN + 1]; /* Variable name.  Mixed case. */
+    char name[VAR_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. */
@@ -77,20 +77,6 @@ struct variable
        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 == VAR_NUMERIC || var_type == VAR_STRING;
-}
-
-/* Returns the variable type for the given width. */
-enum var_type
-var_type_from_width (int width)
-{
-  return width != 0 ? VAR_STRING : VAR_NUMERIC;
-}
 
 /* Creates and returns a new variable with the given NAME and
    WIDTH and other fields initialized to default values.  The
@@ -271,11 +257,11 @@ var_is_plausible_name (const char *name,
         msg (SE, _("Variable name cannot be empty string."));
       return false;
     }
-  else if (length > LONG_NAME_LEN)
+  else if (length > VAR_NAME_LEN)
     {
       if (issue_error)
         msg (SE, _("Variable name %s exceeds %d-character limit."),
-             name, (int) LONG_NAME_LEN);
+             name, (int) VAR_NAME_LEN);
       return false;
     }
 
@@ -290,6 +276,13 @@ var_is_plausible_name (const char *name,
   return true;
 }
 
+/* Returns VAR's dictionary class. */
+enum dict_class
+var_get_dict_class (const struct variable *var)
+{
+  return dict_class_from_id (var->name);
+}
+
 /* A hsh_compare_func that orders variables A and B by their
    names. */
 int
@@ -333,10 +326,10 @@ hash_var_ptr_by_name (const void *v_, co
 }
 
 /* Returns the type of variable V. */
-enum var_type
+enum val_type
 var_get_type (const struct variable *v)
 {
-  return var_type_from_width (v->width);
+  return val_type_from_width (v->width);
 }
 
 /* Returns the width of variable V. */
@@ -346,7 +339,8 @@ var_get_width (const struct variable *v)
   return v->width;
 }
 
-/* Sets the width of V to WIDTH. */
+/* Changes the width of V to NEW_WIDTH.
+   This function should be used cautiously. */
 void
 var_set_width (struct variable *v, int new_width)
 {
@@ -388,7 +382,7 @@ var_set_width (struct variable *v, int n
 bool
 var_is_numeric (const struct variable *v)
 {
-  return var_get_type (v) == VAR_NUMERIC;
+  return var_get_type (v) == VAL_NUMERIC;
 }
 
 /* Returns true if variable V is a string variable, false
@@ -396,7 +390,7 @@ var_is_numeric (const struct variable *v
 bool
 var_is_alpha (const struct variable *v)
 {
-  return var_get_type (v) == VAR_STRING;
+  return var_get_type (v) == VAL_STRING;
 }
 
 /* Returns true if variable V is a short string variable, false
@@ -520,7 +514,7 @@ var_set_value_labels (struct variable *v
   if (vls != NULL)
     {
       assert (val_labs_can_set_width (vls, v->width));
-      v->val_labs = val_labs_copy (vls);
+      v->val_labs = val_labs_clone (vls);
       val_labs_set_width (v->val_labs, v->width);
       dict_var_changed (v);
     }
@@ -538,8 +532,7 @@ alloc_value_labels (struct variable *v)
 
 /* 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. */
+   existing label or if V is a long string variable. */
 bool
 var_add_value_label (struct variable *v,
                      const union value *value, const char *label)
@@ -550,7 +543,7 @@ var_add_value_label (struct variable *v,
 
 /* Adds or replaces a value label with the given VALUE and LABEL
    to V.
-   V must not be a long string variable. */
+   Has no effect if V is a long string variable. */
 void
 var_replace_value_label (struct variable *v,
                          const union value *value, const char *label)
@@ -768,7 +761,7 @@ var_set_alignment (struct variable *v, e
    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. */
+   case, instead of being reset to system-missing or blanks. */
 bool
 var_get_leave (const struct variable *v)
 {
@@ -789,7 +782,7 @@ var_set_leave (struct variable *v, bool 
 bool
 var_must_leave (const struct variable *v)
 {
-  return dict_class_from_id (v->name) == DC_SCRATCH;
+  return var_get_dict_class (v) == DC_SCRATCH;
 }
 
 /* Returns the number of short names stored in VAR.
@@ -803,7 +796,7 @@ var_must_leave (const struct variable *v
    all if it hasn't been saved to or read from a system or
    portable file. */
 size_t
-var_get_short_name_cnt (const struct variable *var) 
+var_get_short_name_cnt (const struct variable *var)
 {
   return var->short_name_cnt;
 }
@@ -829,14 +822,14 @@ var_set_short_name (struct variable *var
   assert (short_name == NULL || var_is_plausible_name (short_name, false));
 
   /* Clear old short name numbered IDX, if any. */
-  if (idx < var->short_name_cnt) 
+  if (idx < var->short_name_cnt)
     {
       free (var->short_names[idx]);
-      var->short_names[idx] = NULL; 
+      var->short_names[idx] = NULL;
     }
 
   /* Install new short name for IDX. */
-  if (short_name != NULL) 
+  if (short_name != NULL)
     {
       if (idx >= var->short_name_cnt)
         {
@@ -960,7 +953,8 @@ var_get_obs_vals (const struct variable 
   return v->obs_vals;
 }
 
-/* Sets V's observed categorical values to CAT_VALS. */
+/* Sets V's observed categorical values to CAT_VALS.
+   V becomes the owner of CAT_VALS. */
 void
 var_set_obs_vals (const struct variable *v_, struct cat_vals *cat_vals)
 {
@@ -977,39 +971,6 @@ var_has_obs_vals (const struct variable 
   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)
-{
-  switch (name[0])
-    {
-    default:
-      return DC_ORDINARY;
-    case '$':
-      return DC_SYSTEM;
-    case '#':
-      return DC_SCRATCH;
-    }
-}
-
-/* Returns the name of dictionary class DICT_CLASS. */
-const char *
-dict_class_to_name (enum dict_class dict_class)
-{
-  switch (dict_class)
-    {
-    case DC_ORDINARY:
-      return _("ordinary");
-    case DC_SYSTEM:
-      return _("system");
-    case DC_SCRATCH:
-      return _("scratch");
-    default:
-      NOT_REACHED ();
-    }
-}
-
 /* Returns V's vardict structure. */
 const struct vardict_info *
 var_get_vardict (const struct variable *v)
Index: b/src/data/variable.h
===================================================================
--- a/src/data/variable.h
+++ b/src/data/variable.h
@@ -14,40 +14,33 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#if !variable_h
-#define variable_h 1
+#ifndef DATA_VARIABLE_H
+#define DATA_VARIABLE_H 1
 
 #include <stddef.h>
 #include <stdbool.h>
+#include <data/dict-class.h>
 #include <data/missing-values.h>
+#include <data/val-type.h>
 
 union value;
 
-/* Variable type. */
-enum var_type
-  {
-    VAR_NUMERIC,                /* A numeric variable. */
-    VAR_STRING			/* A string variable. */
-  };
-
-bool var_type_is_valid (enum var_type);
-enum var_type var_type_from_width (int width);
-
-/* Variables. */
+/* Variables.
+   These functions should rarely be called directly: use
+   dict_create_var, dict_clone_var, or dict_delete_var
+   instead. */
 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
+/* Variable names. */
+#define VAR_NAME_LEN 64 /* Maximum length of variable name, in bytes. */
 
 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);
+enum dict_class var_get_dict_class (const struct variable *);
 
 int compare_vars_by_name (const void *, const void *, const void *);
 unsigned hash_var_by_name (const void *, const void *);
@@ -55,17 +48,16 @@ unsigned hash_var_by_name (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 *);
+/* Types and widths of values associated with a variable. */
+enum val_type var_get_type (const struct variable *);
 int var_get_width (const struct variable *);
 void var_set_width (struct variable *, int width);
 
-typedef bool var_predicate_func (const struct variable *);
-
 bool var_is_numeric (const struct variable *);
 bool var_is_alpha (const struct variable *);
 bool var_is_short_string (const struct variable *);
 bool var_is_long_string (const struct variable *);
+
 size_t var_get_value_cnt (const struct variable *);
 
 /* Variables' missing values. */
@@ -80,17 +72,19 @@ bool var_is_num_missing (const struct va
 bool var_is_str_missing (const struct variable *, const char[], enum mv_class);
 
 /* Value labels. */
-const struct val_labs *var_get_value_labels (const 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 *);
+
 bool var_has_value_labels (const struct variable *);
+const struct val_labs *var_get_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 *);
@@ -167,15 +161,7 @@ struct cat_vals *var_get_obs_vals (const
 void var_set_obs_vals (const struct variable *, struct cat_vals *);
 bool var_has_obs_vals (const struct variable *);
 
-/* Classes of variables. */
-enum dict_class
-  {
-    DC_ORDINARY,                /* Ordinary identifier. */
-    DC_SYSTEM,                  /* System variable. */
-    DC_SCRATCH                  /* Scratch variable. */
-  };
-
-enum dict_class dict_class_from_id (const char *name);
-const char *dict_class_to_name (enum dict_class dict_class);
+/* Function types. */
+typedef bool var_predicate_func (const struct variable *);
 
-#endif /* !variable.h */
+#endif /* data/variable.h */
Index: b/src/data/vector.c
===================================================================
--- a/src/data/vector.c
+++ b/src/data/vector.c
@@ -27,7 +27,7 @@
 /* Vector of variables. */
 struct vector
   {
-    char name[LONG_NAME_LEN + 1];       /* Name. */
+    char name[VAR_NAME_LEN + 1];       /* Name. */
     struct variable **vars;             /* Set of variables. */
     size_t var_cnt;                     /* Number of variables. */
   };
@@ -108,7 +108,7 @@ vector_get_name (const struct vector *ve
 }
 
 /* Returns the type of the variables in VECTOR. */
-enum var_type vector_get_type (const struct vector *vector)
+enum val_type vector_get_type (const struct vector *vector)
 {
   return var_get_type (vector->vars[0]);
 }
Index: b/src/data/vector.h
===================================================================
--- a/src/data/vector.h
+++ b/src/data/vector.h
@@ -30,7 +30,7 @@ struct vector *vector_clone (const struc
 void vector_destroy (struct vector *);
 
 const char *vector_get_name (const struct vector *);
-enum var_type vector_get_type (const struct vector *);
+enum val_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 *);
 
Index: b/src/language/data-io/data-list.c
===================================================================
--- a/src/language/data-io/data-list.c
+++ b/src/language/data-io/data-list.c
@@ -65,7 +65,7 @@ struct dls_var_spec
     /* All parsers. */
     struct fmt_spec input;	/* Input format of this field. */
     int fv;			/* First value in case. */
-    char name[LONG_NAME_LEN + 1]; /* Var name for error messages and tables. */
+    char name[VAR_NAME_LEN + 1]; /* Var name for error messages and tables. */
 
     /* Fixed format only. */
     int record;			/* Record number (1-based). */
Index: b/src/language/data-io/file-handle.q
===================================================================
--- a/src/language/data-io/file-handle.q
+++ b/src/language/data-io/file-handle.q
@@ -50,7 +50,7 @@
 int
 cmd_file_handle (struct lexer *lexer, struct dataset *ds)
 {
-  char handle_name[LONG_NAME_LEN + 1];
+  char handle_name[VAR_NAME_LEN + 1];
   struct cmd_file_handle cmd;
   struct file_handle *handle;
 
Index: b/src/language/data-io/get.c
===================================================================
--- a/src/language/data-io/get.c
+++ b/src/language/data-io/get.c
@@ -735,8 +735,8 @@ cmd_match_files (struct lexer *lexer, st
   bool saw_in = false;
   struct casereader *active_file = NULL;
 
-  char first_name[LONG_NAME_LEN + 1] = "";
-  char last_name[LONG_NAME_LEN + 1] = "";
+  char first_name[VAR_NAME_LEN + 1] = "";
+  char last_name[VAR_NAME_LEN + 1] = "";
 
   struct taint *taint = NULL;
 
Index: b/src/language/data-io/list.q
===================================================================
--- a/src/language/data-io/list.q
+++ b/src/language/data-io/list.q
@@ -29,6 +29,7 @@
 #include <data/data-out.h>
 #include <data/format.h>
 #include <data/procedure.h>
+#include <data/short-names.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/dictionary/split-file.h>
@@ -150,7 +151,7 @@ cmd_list (struct lexer *lexer, struct da
     cmd.last = LONG_MAX;
   if (!cmd.sbc_variables)
     dict_get_vars (dict, &cmd.v_variables, &cmd.n_variables,
-		   (1u << DC_SYSTEM) | (1u << DC_SCRATCH));
+                   DC_SYSTEM | DC_SCRATCH);
   if (cmd.n_variables == 0)
     {
       msg (SE, _("No variables specified."));
@@ -507,7 +508,7 @@ write_fallback_headers (struct outp_driv
 	  }
 
 	  {
-	    char varname[LONG_NAME_LEN + 2];
+	    char varname[VAR_NAME_LEN + 2];
 	    snprintf (varname, sizeof varname,
                       " %s", var_get_name (cmd.v_variables[index]));
 	    write_varname (d, varname, leader_width);
Index: b/src/language/dictionary/formats.c
===================================================================
--- a/src/language/dictionary/formats.c
+++ b/src/language/dictionary/formats.c
@@ -91,7 +91,7 @@ internal_cmd_formats (struct lexer *lexe
 	}
       if (!parse_format_specifier (lexer, &f)
           || !fmt_check_output (&f)
-          || !fmt_check_type_compat (&f, VAR_NUMERIC))
+          || !fmt_check_type_compat (&f, VAL_NUMERIC))
 	goto fail;
 
       if (!lex_match (lexer, ')'))
Index: b/src/language/dictionary/missing-values.c
===================================================================
--- a/src/language/dictionary/missing-values.c
+++ b/src/language/dictionary/missing-values.c
@@ -88,7 +88,7 @@ cmd_missing_values (struct lexer *lexer,
 
                   ok = (x == y
                         ? mv_add_num (&mv, x)
-                        : mv_add_num_range (&mv, x, y));
+                        : mv_add_range (&mv, x, y));
                   if (!ok)
                     deferred_errors = true;
 
Index: b/src/language/dictionary/modify-variables.c
===================================================================
--- a/src/language/dictionary/modify-variables.c
+++ b/src/language/dictionary/modify-variables.c
@@ -138,7 +138,7 @@ cmd_modify_vars (struct lexer *lexer, st
 			   "of variables."));
 		      goto done;
 		    }
-		  dict_get_vars_mutable (dataset_dict (ds), &v, &nv, 1u << DC_SYSTEM);
+		  dict_get_vars_mutable (dataset_dict (ds), &v, &nv, DC_SYSTEM);
 		}
 	      else
 		{
@@ -367,7 +367,7 @@ compare_variables_given_ordering (const 
 struct var_renaming
   {
     struct variable *var;
-    char new_name[LONG_NAME_LEN + 1];
+    char new_name[VAR_NAME_LEN + 1];
   };
 
 /* A algo_compare_func that compares new_name members in struct
Index: b/src/language/dictionary/vector.c
===================================================================
--- a/src/language/dictionary/vector.c
+++ b/src/language/dictionary/vector.c
@@ -135,7 +135,7 @@ cmd_vector (struct lexer *lexer, struct 
                   seen_format = true;
                   if (!parse_format_specifier (lexer, &format)
                       || !fmt_check_output (&format)
-                      || !fmt_check_type_compat (&format, VAR_NUMERIC))
+                      || !fmt_check_type_compat (&format, VAL_NUMERIC))
                     goto fail;
                 }
               else
@@ -152,16 +152,16 @@ cmd_vector (struct lexer *lexer, struct 
             }
 
 	  /* Check that none of the variables exist and that
-             their names are no more than LONG_NAME_LEN bytes
+             their names are no more than VAR_NAME_LEN bytes
              long. */
           for (i = 0; i < vector_cnt; i++)
 	    {
               int j;
 	      for (j = 0; j < var_cnt; j++)
 		{
-                  char name[LONG_NAME_LEN + INT_STRLEN_BOUND (int) + 1];
+                  char name[VAR_NAME_LEN + INT_STRLEN_BOUND (int) + 1];
 		  sprintf (name, "%s%d", vectors[i], j + 1);
-                  if (strlen (name) > LONG_NAME_LEN)
+                  if (strlen (name) > VAR_NAME_LEN)
                     {
                       msg (SE, _("%s is too long for a variable name."), name);
                       goto fail;
@@ -181,7 +181,7 @@ cmd_vector (struct lexer *lexer, struct 
               int j;
 	      for (j = 0; j < var_cnt; j++)
 		{
-                  char name[LONG_NAME_LEN + 1];
+                  char name[VAR_NAME_LEN + 1];
 		  sprintf (name, "%s%d", vectors[i], j + 1);
 		  vars[j] = dict_create_var_assert (dict, name, 0);
                   var_set_both_formats (vars[j], &format);
Index: b/src/language/expressions/evaluate.c
===================================================================
--- a/src/language/expressions/evaluate.c
+++ b/src/language/expressions/evaluate.c
@@ -126,7 +126,7 @@ cmd_debug_evaluate (struct lexer *lexer,
         dump_postfix = 1;
       else if (lex_match (lexer, '('))
         {
-          char name[LONG_NAME_LEN + 1];
+          char name[VAR_NAME_LEN + 1];
           struct variable *v;
           size_t old_value_cnt;
           int width;
Index: b/src/language/expressions/parse.c
===================================================================
--- a/src/language/expressions/parse.c
+++ b/src/language/expressions/parse.c
@@ -356,7 +356,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, VAR_NUMERIC))
+          && fmt_check_type_compat (&(*node)->format.f, VAL_NUMERIC))
         {
           msg_enable ();
           if (do_coercion)
@@ -370,7 +370,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, VAR_NUMERIC))
+          && fmt_check_type_compat (&(*node)->format.f, VAL_NUMERIC))
         {
           msg_enable ();
           if (do_coercion)
@@ -918,7 +918,7 @@ parse_vector_element (struct lexer *lexe
       || !lex_match (lexer, ')'))
     return NULL;
 
-  return expr_allocate_binary (e, (vector_get_type (vector) == VAR_NUMERIC
+  return expr_allocate_binary (e, (vector_get_type (vector) == VAL_NUMERIC
                                    ? OP_VEC_ELEM_NUM : OP_VEC_ELEM_STR),
                                element, expr_allocate_vector (e, vector));
 }
Index: b/src/language/lexer/lexer.c
===================================================================
--- a/src/language/lexer/lexer.c
+++ b/src/language/lexer/lexer.c
@@ -52,7 +52,7 @@ struct lexer
   int token;      /* Current token. */
   double tokval;  /* T_POS_NUM, T_NEG_NUM: the token's value. */
 
-  char tokid [LONG_NAME_LEN + 1];   /* T_ID: the identifier. */
+  char tokid [VAR_NAME_LEN + 1];   /* T_ID: the identifier. */
 
   struct string tokstr;   /* T_ID, T_STRING: token string value.
   			    For T_ID, this is not truncated as is
Index: b/src/language/lexer/variable-parser.c
===================================================================
--- a/src/language/lexer/variable-parser.c
+++ b/src/language/lexer/variable-parser.c
@@ -405,8 +405,8 @@ parse_DATA_LIST_vars (struct lexer *lexe
   int d1, d2;
   int n;
   size_t nvar, mvar;
-  char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
-  char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
+  char name1[VAR_NAME_LEN + 1], name2[VAR_NAME_LEN + 1];
+  char root1[VAR_NAME_LEN + 1], root2[VAR_NAME_LEN + 1];
   int success = 0;
 
   assert (names != NULL);
@@ -474,7 +474,7 @@ parse_DATA_LIST_vars (struct lexer *lexe
 
 	  for (n = n1; n <= n2; n++)
 	    {
-              char name[LONG_NAME_LEN + 1];
+              char name[VAR_NAME_LEN + 1];
 	      sprintf (name, "%s%0*d", root1, d1, n);
 	      (*names)[nvar] = xstrdup (name);
 	      nvar++;
@@ -664,7 +664,7 @@ var_set_lookup_var_idx (const struct var
 {
   assert (vs != NULL);
   assert (name != NULL);
-  assert (strlen (name) <= LONG_NAME_LEN);
+  assert (strlen (name) <= VAR_NAME_LEN);
 
   return vs->lookup_var_idx (vs, name, idx);
 }
Index: b/src/language/stats/aggregate.c
===================================================================
--- a/src/language/stats/aggregate.c
+++ b/src/language/stats/aggregate.c
@@ -92,7 +92,7 @@ struct agr_func
   {
     const char *name;		/* Aggregation function name. */
     size_t n_args;              /* Number of arguments. */
-    enum var_type alpha_type;   /* When given ALPHA arguments, output type. */
+    enum val_type alpha_type;   /* When given ALPHA arguments, output type. */
     struct fmt_spec format;	/* Format spec if alpha_type != ALPHA. */
   };
 
@@ -103,25 +103,25 @@ static const struct agr_func agr_func_ta
     {"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}},
+    {"MAX",     0, VAL_STRING,  {-1, -1, -1}},
+    {"MIN",     0, VAL_STRING,  {-1, -1, -1}},
+    {"PGT",     1, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"PLT",     1, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"PIN",     2, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"POUT",    2, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"FGT",     1, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FLT",     1, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FIN",     2, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FOUT",    2, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"N",       0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NU",      0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NMISS",   0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NUMISS",  0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"FIRST",   0, VAL_STRING,  {-1, -1, -1}},
+    {"LAST",    0, VAL_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}},
+    {"N",       0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NU",      0, VAL_NUMERIC, {FMT_F, 7, 0}},
   };
 
 /* Missing value types. */
@@ -478,12 +478,12 @@ parse_aggregate_functions (struct lexer 
 		if (lex_token (lexer) == T_STRING)
 		  {
 		    arg[i].c = ds_xstrdup (lex_tokstr (lexer));
-		    type = VAR_STRING;
+		    type = VAL_STRING;
 		  }
 		else if (lex_is_number (lexer))
 		  {
 		    arg[i].f = lex_tokval (lexer);
-		    type = VAR_NUMERIC;
+		    type = VAL_NUMERIC;
 		  }
                 else
                   {
@@ -573,12 +573,12 @@ parse_aggregate_functions (struct lexer 
 		    v->string = xmalloc (var_get_width (src[i]));
 		  }
 
-		if (function->alpha_type == VAR_STRING)
+		if (function->alpha_type == VAL_STRING)
 		  destvar = dict_clone_var (agr->dict, v->src, dest[i]);
 		else
                   {
                     assert (var_is_numeric (v->src)
-                            || function->alpha_type == VAR_NUMERIC);
+                            || function->alpha_type == VAL_NUMERIC);
                     destvar = dict_create_var (agr->dict, dest[i], 0);
                     if (destvar != NULL)
                       {
Index: b/src/language/stats/descriptives.c
===================================================================
--- a/src/language/stats/descriptives.c
+++ b/src/language/stats/descriptives.c
@@ -123,7 +123,7 @@ static const struct dsc_statistic_info d
 struct dsc_var
   {
     const struct variable *v;         /* Variable to calculate on. */
-    char z_name[LONG_NAME_LEN + 1]; /* Name for z-score variable. */
+    char z_name[VAR_NAME_LEN + 1]; /* Name for z-score variable. */
     double valid, missing;	/* Valid, missing counts. */
     struct moments *moments;    /* Moments. */
     double min, max;            /* Maximum and mimimum values. */
@@ -495,7 +495,7 @@ static bool
 generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc, char *z_name,
                     const char *var_name, int *z_cnt)
 {
-  char name[LONG_NAME_LEN + 1];
+  char name[VAR_NAME_LEN + 1];
 
   /* Try a name based on the original variable name. */
   name[0] = 'Z';
Index: b/src/language/stats/flip.c
===================================================================
--- a/src/language/stats/flip.c
+++ b/src/language/stats/flip.c
@@ -28,6 +28,7 @@
 #include <data/dictionary.h>
 #include <data/procedure.h>
 #include <data/settings.h>
+#include <data/short-names.h>
 #include <data/value.h>
 #include <data/variable.h>
 #include <language/command.h>
@@ -117,7 +118,7 @@ cmd_flip (struct lexer *lexer, struct da
       lex_match (lexer, '/');
     }
   else
-    dict_get_vars (dict, &flip->var, &flip->var_cnt, 1u << DC_SYSTEM);
+    dict_get_vars (dict, &flip->var, &flip->var_cnt, DC_SYSTEM);
   pool_register (flip->pool, free, flip->var);
 
   lex_match (lexer, '/');
Index: b/src/language/stats/frequencies.q
===================================================================
--- a/src/language/stats/frequencies.q
+++ b/src/language/stats/frequencies.q
@@ -636,12 +636,12 @@ postcalc (void)
 }
 
 /* Returns the comparison function that should be used for
-   sorting a frequency table by FRQ_SORT using VAR_TYPE
-   variables. */
+   sorting a frequency table by FRQ_SORT using VAL_TYPE
+   values. */
 static hsh_compare_func *
-get_freq_comparator (int frq_sort, enum var_type var_type)
+get_freq_comparator (int frq_sort, enum val_type val_type)
 {
-  bool is_numeric = var_type == VAR_NUMERIC;
+  bool is_numeric = val_type == VAL_NUMERIC;
   switch (frq_sort)
     {
     case FRQ_AVALUE:
Index: b/src/language/stats/rank.q
===================================================================
--- a/src/language/stats/rank.q
+++ b/src/language/stats/rank.q
@@ -19,23 +19,24 @@
 #include <limits.h>
 #include <math.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-ordering.h>
 #include <data/case.h>
 #include <data/casegrouper.h>
 #include <data/casereader.h>
 #include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/format.h>
+#include <data/missing-values.h>
+#include <data/procedure.h>
+#include <data/short-names.h>
+#include <data/variable.h>
 #include <language/command.h>
 #include <language/stats/sort-criteria.h>
 #include <libpspp/compiler.h>
 #include <libpspp/taint.h>
 #include <math/sort.h>
-#include <output/table.h>
 #include <output/manager.h>
+#include <output/table.h>
 
 #include <gsl/gsl_cdf.h>
 
Index: b/src/language/stats/regression.q
===================================================================
--- a/src/language/stats/regression.q
+++ b/src/language/stats/regression.q
@@ -637,16 +637,16 @@ try_name (const struct dictionary *dict,
 }
 
 static void
-reg_get_name (const struct dictionary *dict, char name[LONG_NAME_LEN],
-	      const char prefix[LONG_NAME_LEN])
+reg_get_name (const struct dictionary *dict, char name[VAR_NAME_LEN],
+	      const char prefix[VAR_NAME_LEN])
 {
   int i = 1;
 
-  snprintf (name, LONG_NAME_LEN, "%s%d", prefix, i);
+  snprintf (name, VAR_NAME_LEN, "%s%d", prefix, i);
   while (!try_name (dict, name))
     {
       i++;
-      snprintf (name, LONG_NAME_LEN, "%s%d", prefix, i);
+      snprintf (name, VAR_NAME_LEN, "%s%d", prefix, i);
     }
 }
 
@@ -656,7 +656,7 @@ reg_save_var (struct dataset *ds, const 
 {
   struct dictionary *dict = dataset_dict (ds);
   static int trns_index = 1;
-  char name[LONG_NAME_LEN];
+  char name[VAR_NAME_LEN];
   struct variable *new_var;
   struct reg_trns *t = NULL;
 
@@ -1154,8 +1154,7 @@ run_regression (struct casereader *input
 
   if (!v_variables)
     {
-      dict_get_vars (dataset_dict (ds), &v_variables, &n_variables,
-		     1u << DC_SYSTEM);
+      dict_get_vars (dataset_dict (ds), &v_variables, &n_variables, 0);
     }
 
   for (i = 0; i < cmd->n_dependent; i++)
Index: b/src/language/stats/t-test.q
===================================================================
--- a/src/language/stats/t-test.q
+++ b/src/language/stats/t-test.q
@@ -147,7 +147,7 @@ struct pair
 
 static struct pair *pairs=0;
 
-static int parse_value (struct lexer *lexer, union value * v, enum var_type);
+static int parse_value (struct lexer *lexer, union value * v, enum val_type);
 
 /* Structures and Functions for the Statistics Summary Box */
 struct ssbox;
@@ -565,9 +565,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, enum var_type type)
+parse_value (struct lexer *lexer, union value * v, enum val_type type)
 {
-  if (type == VAR_NUMERIC)
+  if (type == VAL_NUMERIC)
     {
       if (!lex_force_num (lexer))
 	return 0;
Index: b/src/language/xforms/compute.c
===================================================================
--- a/src/language/xforms/compute.c
+++ b/src/language/xforms/compute.c
@@ -258,7 +258,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) == VAR_NUMERIC;
+  bool is_numeric = lvalue_get_type (lvalue) == VAL_NUMERIC;
   bool is_vector = lvalue_is_vector (lvalue);
 
   return (is_numeric
@@ -272,7 +272,7 @@ static struct expression *
 parse_rvalue (struct lexer *lexer,
 	      const struct lvalue *lvalue, struct dataset *ds)
 {
-  bool is_numeric = lvalue_get_type (lvalue) == VAR_NUMERIC;
+  bool is_numeric = lvalue_get_type (lvalue) == VAL_NUMERIC;
 
   return expr_parse (lexer, ds, is_numeric ? EXPR_NUMBER : EXPR_STRING);
 }
Index: b/src/language/xforms/recode.c
===================================================================
--- a/src/language/xforms/recode.c
+++ b/src/language/xforms/recode.c
@@ -22,6 +22,7 @@
 
 #include <data/case.h>
 #include <data/data-in.h>
+#include <data/format.h>
 #include <data/dictionary.h>
 #include <data/procedure.h>
 #include <data/transformations.h>
@@ -90,8 +91,8 @@ struct recode_trns
     struct pool *pool;
 
     /* Variable types, for convenience. */
-    enum var_type src_type;     /* src_vars[*]->type. */
-    enum var_type dst_type;     /* dst_vars[*]->type. */
+    enum val_type src_type;     /* src_vars[*] type. */
+    enum val_type dst_type;     /* dst_vars[*] type. */
 
     /* Variables. */
     const struct variable **src_vars;	/* Source variables. */
@@ -112,7 +113,7 @@ static void add_mapping (struct recode_t
                          size_t *map_allocated, const struct map_in *);
 
 static bool parse_map_in (struct lexer *lexer, struct map_in *, struct pool *,
-                          enum var_type src_type, size_t max_src_width);
+                          enum val_type src_type, size_t max_src_width);
 static void set_map_in_generic (struct map_in *, enum map_in_type);
 static void set_map_in_num (struct map_in *, enum map_in_type, double, double);
 static void set_map_in_str (struct map_in *, struct pool *,
@@ -153,7 +154,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 == VAR_STRING)
+      if (trns->dst_type == VAL_STRING)
         enlarge_dst_widths (trns);
 
       /* Create destination variables, if needed.
@@ -215,7 +216,7 @@ parse_mappings (struct lexer *lexer, str
     return false;
   do
     {
-      enum var_type dst_type;
+      enum val_type dst_type;
 
       if (!lex_match_id (lexer, "CONVERT"))
         {
@@ -239,7 +240,7 @@ parse_mappings (struct lexer *lexer, str
 
           if (!parse_map_out (lexer, trns->pool, &out))
             return false;
-          dst_type = var_type_from_width (out.width);
+          dst_type = val_type_from_width (out.width);
           if (have_dst_type && dst_type != trns->dst_type)
             {
               msg (SE, _("Inconsistent target variable types.  "
@@ -259,9 +260,9 @@ parse_mappings (struct lexer *lexer, str
           add_mapping (trns, &map_allocated, &in);
           set_map_out_num (&trns->mappings[trns->map_cnt - 1].out, 0.0);
 
-          dst_type = VAR_NUMERIC;
-          if (trns->src_type != VAR_STRING
-              || (have_dst_type && trns->dst_type != VAR_NUMERIC))
+          dst_type = VAL_NUMERIC;
+          if (trns->src_type != VAL_STRING
+              || (have_dst_type && trns->dst_type != VAL_NUMERIC))
             {
               msg (SE, _("CONVERT requires string input values and "
                          "numeric output values."));
@@ -286,11 +287,11 @@ parse_mappings (struct lexer *lexer, str
    false on parse error. */
 static bool
 parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
-              enum var_type src_type, size_t max_src_width)
+              enum val_type src_type, size_t max_src_width)
 {
   if (lex_match_id (lexer, "ELSE"))
     set_map_in_generic (in, MAP_ELSE);
-  else if (src_type == VAR_NUMERIC)
+  else if (src_type == VAL_NUMERIC)
     {
       if (lex_match_id (lexer, "MISSING"))
         set_map_in_generic (in, MAP_MISSING);
@@ -449,7 +450,7 @@ parse_dst_vars (struct lexer *lexer, str
         {
           const struct variable *v;
           v = trns->dst_vars[i] = dict_lookup_var (dict, trns->dst_names[i]);
-          if (v == NULL && trns->dst_type == VAR_STRING)
+          if (v == NULL && trns->dst_type == VAL_STRING)
             {
               msg (SE, _("There is no variable named "
                          "%s.  (All string variables specified "
@@ -468,8 +469,8 @@ parse_dst_vars (struct lexer *lexer, str
         {
           msg (SE, _("INTO is required with %s input values "
                      "and %s output values."),
-               trns->src_type == VAR_NUMERIC ? _("numeric") : _("string"),
-               trns->dst_type == VAR_NUMERIC ? _("numeric") : _("string"));
+               trns->src_type == VAL_NUMERIC ? _("numeric") : _("string"),
+               trns->dst_type == VAL_NUMERIC ? _("numeric") : _("string"));
           return false;
         }
     }
@@ -481,7 +482,7 @@ parse_dst_vars (struct lexer *lexer, str
         {
           msg (SE, _("Type mismatch.  Cannot store %s data in "
                      "%s variable %s."),
-               trns->dst_type == VAR_STRING ? _("string") : _("numeric"),
+               trns->dst_type == VAL_STRING ? _("string") : _("numeric"),
                var_is_alpha (v) ? _("string") : _("numeric"),
                var_get_name (v));
           return false;
@@ -640,12 +641,12 @@ recode_trns_proc (void *trns_, struct cc
 
       const struct map_out *out;
 
-      if (trns->src_type == VAR_NUMERIC)
+      if (trns->src_type == VAL_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 == VAR_NUMERIC)
+      if (trns->dst_type == VAL_NUMERIC)
         {
           if (out != NULL)
             dst_data->f = !out->copy_input ? out->value.f : src_data->f;
Index: b/src/libpspp/model-checker.c
===================================================================
--- a/src/libpspp/model-checker.c
+++ b/src/libpspp/model-checker.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/time.h>
 
+#include <data/val-type.h>
 #include <libpspp/bit-vector.h>
 #include <libpspp/compiler.h>
 #include <libpspp/deque.h>
Index: b/src/math/factor-stats.c
===================================================================
--- a/src/math/factor-stats.c
+++ b/src/math/factor-stats.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include "factor-stats.h"
+#include <data/val-type.h>
 #include <data/value.h>
 #include <libpspp/hash.h>
 #include <libpspp/array.h>
Index: b/src/math/moments.c
===================================================================
--- a/src/math/moments.c
+++ b/src/math/moments.c
@@ -20,6 +20,7 @@
 #include <math.h>
 #include <stdlib.h>
 #include <libpspp/misc.h>
+#include <data/val-type.h>
 #include <data/value.h>
 
 #include "xalloc.h"
Index: b/src/math/percentiles.c
===================================================================
--- a/src/math/percentiles.c
+++ b/src/math/percentiles.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include <assert.h>
+#include <data/val-type.h>
 #include <libpspp/compiler.h>
 #include "factor-stats.h"
 #include "percentiles.h"
Index: b/src/ui/gui/missing-val-dialog.c
===================================================================
--- a/src/ui/gui/missing-val-dialog.c
+++ b/src/ui/gui/missing-val-dialog.c
@@ -148,7 +148,7 @@ missing_val_dialog_accept (GtkWidget *w,
 	g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
 
       mv_clear (&dialog->mvl);
-      mv_add_num_range (&dialog->mvl, low_val.f, high_val.f);
+      mv_add_range (&dialog->mvl, low_val.f, high_val.f);
 
       if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
 	{
@@ -307,7 +307,7 @@ missing_val_dialog_show (struct missing_
       union value low, high;
       gchar *low_text;
       gchar *high_text;
-      mv_peek_range (&dialog->mvl, &low.f, &high.f);
+      mv_get_range (&dialog->mvl, &low.f, &high.f);
 
       low_text = value_to_text (low, *write_spec);
       high_text = value_to_text (high, *write_spec);
@@ -321,7 +321,7 @@ missing_val_dialog_show (struct missing_
 	{
 	  gchar *text;
 	  union value value;
-	  mv_peek_value (&dialog->mvl, &value, 0);
+	  mv_get_value (&dialog->mvl, &value, 0);
 	  text = value_to_text (value, *write_spec);
 	  gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
 	  g_free (text);
@@ -344,7 +344,7 @@ missing_val_dialog_show (struct missing_
 	      gchar *text ;
 	      union value value;
 
-	      mv_peek_value (&dialog->mvl, &value, i);
+	      mv_get_value (&dialog->mvl, &value, i);
 	      text = value_to_text (value, *write_spec);
 	      gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
 	      g_free (text);
Index: b/src/ui/gui/val-labs-dialog.c
===================================================================
--- a/src/ui/gui/val-labs-dialog.c
+++ b/src/ui/gui/val-labs-dialog.c
@@ -519,7 +519,7 @@ val_labs_dialog_show (struct val_labs_di
   value_labels = var_get_value_labels (dialog->pv);
 
   if (value_labels)
-    dialog->labs = val_labs_copy ( value_labels );
+    dialog->labs = val_labs_clone ( value_labels );
   else
     dialog->labs = val_labs_create ( var_get_width (dialog->pv));
 
Index: b/src/ui/gui/var-display.c
===================================================================
--- a/src/ui/gui/var-display.c
+++ b/src/ui/gui/var-display.c
@@ -63,7 +63,7 @@ missing_values_to_string (const struct v
 	  for (i = 0 ; i < n; ++i )
 	    {
 	      union value v;
-	      mv_peek_value (miss, &v, i);
+	      mv_get_value (miss, &v, i);
 	      mv[i] = value_to_text (v, *fmt);
 	      if ( i > 0 )
 		g_string_append (gstr, ", ");
@@ -78,7 +78,7 @@ missing_values_to_string (const struct v
 	  GString *gstr = g_string_sized_new (10);
 	  gchar *l, *h;
 	  union value low, high;
-	  mv_peek_range (miss, &low.f, &high.f);
+	  mv_get_range (miss, &low.f, &high.f);
 
 	  l = value_to_text (low, *fmt);
 	  h = value_to_text (high, *fmt);
@@ -91,7 +91,7 @@ missing_values_to_string (const struct v
 	    {
 	      gchar *ss = 0;
 	      union value v;
-	      mv_peek_value (miss, &v, 0);
+	      mv_get_value (miss, &v, 0);
 
 	      ss = value_to_text (v, *fmt);
 
Index: b/src/ui/gui/var-type-dialog.c
===================================================================
--- a/src/ui/gui/var-type-dialog.c
+++ b/src/ui/gui/var-type-dialog.c
@@ -790,14 +790,14 @@ on_var_type_ok_clicked (GtkWidget *w, gp
     gint decimals = atoi (gtk_entry_get_text
 			 (GTK_ENTRY (dialog->entry_decimals)));
 
-    gint new_type = VAR_NUMERIC;
+    gint new_type = VAL_NUMERIC;
     gint new_width = 0;
     bool result = false;
     struct fmt_spec spec;
     switch (dialog->active_button)
       {
       case BUTTON_STRING:
-	new_type = VAR_STRING;
+	new_type = VAL_STRING;
 	new_width = width;
 	result = make_output_format_try (&spec, FMT_A, width, 0);
 	break;
