Patch #6262. New developers guide and resulting fixes and cleanups.
authorBen Pfaff <blp@gnu.org>
Sun, 11 Nov 2007 05:51:38 +0000 (05:51 +0000)
committerBen Pfaff <blp@gnu.org>
Sun, 11 Nov 2007 05:51:38 +0000 (05:51 +0000)
* automake.mk (src_data_libdata_a_SOURCES): Add new files.

* dict-class.c: New file.
(dict_class_from_id): Move here.
(dict_class_to_name): Move here.

* dict-class.h: New file.
(enum dict_class): Move here.  Change from consecutive integers to
consecutive bits, to make testing for any of multiple values
easier.  Add new DC_ALL constant.

* dictionary.c (struct dictionary): Change `case_limit' from
size_t to casenumber.
(dict_get_vars): Make final argument an enum dict_class.
(dict_get_vars_mutable): Ditto.
(dict_get_case_limit): Change return value to casenumber.
(dict_set_case_limit): Change final argument to a casenumber.
(dict_unset_split_var): Add assertion.  Rephrase slightly.
(dict_set_label): Use xstrndup to simplify.

* format.c (fmt_step_width): AHEX format also needs 2-byte
stepping.
(fmt_set_style): Simplify assertions.

* missing-values.c (mv_add_num_range): Rename mv_add_range.
Simplify implementation.
(mv_has_value): Simplify implementation.
(mv_pop_value): Remove the first value, not the last, to avoid
having GET followed by SAVE reverse the order of missing values.
(mv_peek_value): Rename mv_get_value.  Simplify assertion.
(mv_has_range): Simplify implementation.
(mv_peek_range): Rename mv_get_range.
(can_resize_string): Removed.
(mv_is_resizable): Use value_is_resizable.
(mv_resize): Use value_resize.

* short-names.h (SHORT_NAME_LEN): Move here.

* val-type.h: New file, for definitions related to type and width
of abstract values.  Before, these definitions were mixed among
those related to "union value" and those related to variables.
(macro SYSMIS): Move here.
(macro LOWEST): Move here.
(macro HIGHEST): Move here.
(macro MAX_STRING); Move here.
(enum val_type): New enum with values VAL_NUMERIC and VAL_STRING.
Replaces enum var_type that had values VAR_NUMERIC and VAR_STRING.
All references updated.
(val_type_is_valid): New function.  Replaces var_type_is_valid.
All references updated.
(val_type_from_width): New function.  Replaces
var_type_from_width.  All references updated.

* value-labels.c (val_labs_copy): Renamed val_labs_clone.  All
references updated.
(val_labs_can_set_width): Use value_is_resizable.
(val_labs_add): Simply return false if the value labels set is too
wide, instead of having undefined behavior.
(val_labs_replace): Ditto.
(val_labs_replace): Ditto.
(val_labs_first): Set iterator to null if iteration is complete.
(val_labs_first_sorted): Ditto.
(val_labs_done): Become a no-op if the iterator is null.

* value.c (value_is_resizable): New function.
(value_resize): New function.

* variable.c (var_get_dict_class): New function.

* variable.h (macro LONG_NAME_LEN): Rename VAR_NAME_LEN.  Update
all references.

* not-implemented.texi: Fix @include command so that it works
consistently, by using a file name relative to Makefile.am's
srcdir instead of relative to doc.

79 files changed:
doc/.cvsignore
doc/ChangeLog
doc/automake.mk
doc/data-file-format.texi [deleted file]
doc/dev/concepts.texi [new file with mode: 0644]
doc/dev/data.texi [new file with mode: 0644]
doc/dev/intro.texi [new file with mode: 0644]
doc/dev/output.texi [new file with mode: 0644]
doc/dev/portable-file-format.texi [new file with mode: 0644]
doc/dev/q2c.texi [new file with mode: 0644]
doc/dev/syntax.texi [new file with mode: 0644]
doc/dev/system-file-format.texi [new file with mode: 0644]
doc/not-implemented.texi
doc/portable-file-format.texi [deleted file]
doc/pspp-dev.texinfo [new file with mode: 0644]
doc/pspp.texinfo
doc/q2c.texi [deleted file]
doc/utilities.texi
doc/variables.texi
po/de.po
po/en_GB.po
src/data/ChangeLog
src/data/automake.mk
src/data/calendar.c
src/data/case.h
src/data/data-in.h
src/data/data-out.c
src/data/dict-class.c [new file with mode: 0644]
src/data/dict-class.h [new file with mode: 0644]
src/data/dictionary.c
src/data/dictionary.h
src/data/format.c
src/data/format.h
src/data/missing-values.c
src/data/missing-values.h
src/data/por-file-reader.c
src/data/procedure.c
src/data/short-names.h
src/data/sys-file-reader.c
src/data/sys-file-writer.c
src/data/val-type.h [new file with mode: 0644]
src/data/value-labels.c
src/data/value-labels.h
src/data/value.c
src/data/value.h
src/data/vardict.h
src/data/variable.c
src/data/variable.h
src/data/vector.c
src/data/vector.h
src/language/data-io/data-list.c
src/language/data-io/file-handle.q
src/language/data-io/get.c
src/language/data-io/list.q
src/language/dictionary/formats.c
src/language/dictionary/missing-values.c
src/language/dictionary/modify-variables.c
src/language/dictionary/vector.c
src/language/expressions/evaluate.c
src/language/expressions/parse.c
src/language/lexer/lexer.c
src/language/lexer/variable-parser.c
src/language/stats/aggregate.c
src/language/stats/descriptives.c
src/language/stats/flip.c
src/language/stats/frequencies.q
src/language/stats/rank.q
src/language/stats/regression.q
src/language/stats/t-test.q
src/language/xforms/compute.c
src/language/xforms/recode.c
src/libpspp/model-checker.c
src/math/factor-stats.c
src/math/moments.c
src/math/percentiles.c
src/ui/gui/missing-val-dialog.c
src/ui/gui/val-labs-dialog.c
src/ui/gui/var-display.c
src/ui/gui/var-type-dialog.c

index 6d2576feb9f8ef70064afdde2f8bae9b90d4c248..06eb3bb18a49b17bb6a488f2c2a259d95e6be159 100644 (file)
@@ -1,6 +1,9 @@
 Makefile
 Makefile.in
 ni.texi
+pspp-dev.info
 pspp.info*
+stamp-1
 stamp-vti
+version-dev.texi
 version.texi
index 8a52b3d8de1383f7c9f505f0ce77089b6ae24a49..c1fa40eb6c587b759847e7ef36a59b5dbf42a6b1 100644 (file)
@@ -1,3 +1,36 @@
+2007-11-10  Ben Pfaff  <blp@gnu.org>
+
+       * not-implemented.texi: Fix @include command so that it works
+       consistently, by using a file name relative to Makefile.am's
+       srcdir instead of relative to doc.
+
+2007-11-10  Ben Pfaff  <blp@gnu.org>
+
+       Patch #6262: New developers guide (currently incomplete).
+
+       * automake.mk: Add definitions for new manual.
+
+       * pspp.texinfo: Now this is the PSPP Users Guide instead of just
+       the PSPP manual.  Remove development chapters.
+
+       * pspp-dev.texinfo: New file.
+
+       * data-file-format.texi: Move to dev/system-file-format.texi.
+
+       * portable-file-format.texi: Move to dev/.
+
+       * q2c.texi: Move to dev/
+
+       * dev/concepts.texi: New file.
+
+       * dev/data.texi: New file.
+
+       * dev/intro.texi: New file.
+
+       * dev/output.texi: New file.
+
+       * dev/syntax.texi: New file.
+
 2007-10-19 John Darrington <john@darrington.wattle.id.au>
 
        * statistics.texi: Changed /CONTRASTS to /CONTRAST in ONEWAY which
index 301757c8b71f105e159bbea2d24c29ee4eef5c7f..9c73d344bffbeef2489fd3eb4ea166e3c6fd4ecb 100644 (file)
@@ -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/dev/system-file-format.texi \
+       doc/dev/portable-file-format.texi \
+       doc/dev/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
diff --git a/doc/data-file-format.texi b/doc/data-file-format.texi
deleted file mode 100644 (file)
index c2fdacd..0000000
+++ /dev/null
@@ -1,906 +0,0 @@
-@node System File Format
-@appendix System File Format
-
-A system file encapsulates a set of cases and dictionary information
-that describes how they may be interpreted.  This chapter describes
-the format of a system file.
-
-System files use three data types: 8-bit characters, 32-bit integers,
-and 64-bit floating points, called here @code{char}, @code{int32}, and
-@code{flt64}, respectively.  Data is not necessarily aligned on a word
-or double-word boundary: the long variable name record (@pxref{Long
-Variable Names Record}) and very long string records (@pxref{Very Long
-String Record}) have arbitrary byte length and can therefore cause all
-data coming after them in the file to be misaligned.
-
-Integer data in system files may be big-endian or little-endian.  A
-reader may detect the endianness of a system file by examining
-@code{layout_code} in the file header record
-(@pxref{layout_code,,@code{layout_code}}).
-
-Floating-point data in system files may nominally be in IEEE 754, IBM,
-or VAX formats.  A reader may detect the floating-point format in use
-by examining @code{bias} in the file header record
-(@pxref{bias,,@code{bias}}).
-
-PSPP detects big-endian and little-endian integer formats in system
-files and translates as necessary.  PSPP also detects the
-floating-point format in use, as well as the endianness of IEEE 754
-floating-point numbers, and translates as needed.  However, only IEEE
-754 numbers with the same endianness as integer data in the same file
-has actually been observed in system files, and it is likely that
-other formats are obsolete or were never used.
-
-The PSPP system-missing value is represented by the largest possible
-negative number in the floating point format (@code{-DBL_MAX}).  Two
-other values are important for use as missing values: @code{HIGHEST},
-represented by the largest possible positive number (@code{DBL_MAX}),
-and @code{LOWEST}, represented by the second-largest negative number
-(in IEEE 754 format, @code{0xffeffffffffffffe}).
-
-System files are divided into records, each of which begins with a
-4-byte record type, usually regarded as an @code{int32}.
-
-The records must appear in the following order:
-
-@itemize @bullet
-@item
-File header record.
-
-@item
-Variable records.
-
-@item
-All pairs of value labels records and value label variables records,
-if present.
-
-@item
-Document record, if present.
-
-@item
-Any of the following records, if present, in any order:
-
-@itemize @minus
-@item
-Machine integer info record.
-
-@item
-Machine floating-point info record.
-
-@item
-Variable display parameter record.
-
-@item
-Long variable names record.
-
-@item
-Miscellaneous informational records.
-@end itemize
-
-@item
-Dictionary termination record.
-
-@item
-Data record.
-@end itemize
-
-Each type of record is described separately below.
-
-@menu
-* File Header Record::
-* Variable Record::
-* Value Labels Records::
-* Document Record::
-* Machine Integer Info Record::
-* Machine Floating-Point Info Record::
-* Variable Display Parameter Record::
-* Long Variable Names Record::
-* Very Long String Record::
-* Miscellaneous Informational Records::
-* Dictionary Termination Record::
-* Data Record::
-@end menu
-
-@node File Header Record
-@section File Header Record
-
-The file header is always the first record in the file.  It has the
-following format:
-
-@example
-char                rec_type[4];
-char                prod_name[60];
-int32               layout_code;
-int32               nominal_case_size;
-int32               compressed;
-int32               weight_index;
-int32               ncases;
-flt64               bias;
-char                creation_date[9];
-char                creation_time[8];
-char                file_label[64];
-char                padding[3];
-@end example
-
-@table @code
-@item char rec_type[4];
-Record type code, set to @samp{$FL2}.
-
-@item char prod_name[60];
-Product identification string.  This always begins with the characters
-@samp{@@(#) SPSS DATA FILE}.  PSPP uses the remaining characters to
-give its version and the operating system name; for example, @samp{GNU
-pspp 0.1.4 - sparc-sun-solaris2.5.2}.  The string is truncated if it
-would be longer than 60 characters; otherwise it is padded on the right
-with spaces.
-
-@anchor{layout_code}
-@item int32 layout_code;
-Normally set to 2, although a few system files have been spotted in
-the wild with a value of 3 here.  PSPP use this value to determine the
-file's integer endianness (@pxref{System File Format}).
-
-@item int32 nominal_case_size;
-Number of data elements per case.  This is the number of variables,
-except that long string variables add extra data elements (one for every
-8 characters after the first 8).  However, string variables do not
-contribute to this value beyond the first 255 bytes.   Further, system
-files written by some systems set this value to -1.  In general, it is
-unsafe for systems reading system files to rely upon this value.
-
-@item int32 compressed;
-Set to 1 if the data in the file is compressed, 0 otherwise.
-
-@item int32 weight_index;
-If one of the variables in the data set is used as a weighting
-variable, set to the dictionary index of that variable, plus 1
-(@pxref{Dictionary Index}).  Otherwise, set to 0.
-
-@item int32 ncases;
-Set to the number of cases in the file if it is known, or -1 otherwise.
-
-In the general case it is not possible to determine the number of cases
-that will be output to a system file at the time that the header is
-written.  The way that this is dealt with is by writing the entire
-system file, including the header, then seeking back to the beginning of
-the file and writing just the @code{ncases} field.  For `files' in which
-this is not valid, the seek operation fails.  In this case,
-@code{ncases} remains -1.
-
-@anchor{bias}
-@item flt64 bias;
-Compression bias, ordinarily set to 100.  Only integers between
-@code{1 - bias} and @code{251 - bias} can be compressed.
-
-By assuming that its value is 100, PSPP uses @code{bias} to determine
-the file's floating-point format and endianness (@pxref{System File
-Format}).  If the compression bias is not 100, PSPP cannot auto-detect
-the floating-point format and assumes that it is IEEE 754 format with
-the same endianness as the system file's integers, which is correct
-for all known system files.
-
-@item char creation_date[9];
-Date of creation of the system file, in @samp{dd mmm yy}
-format, with the month as standard English abbreviations, using an
-initial capital letter and following with lowercase.  If the date is not
-available then this field is arbitrarily set to @samp{01 Jan 70}.
-
-@item char creation_time[8];
-Time of creation of the system file, in @samp{hh:mm:ss}
-format and using 24-hour time.  If the time is not available then this
-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}).
-Padded on the right with spaces.
-
-@item char padding[3];
-Ignored padding bytes to make the structure a multiple of 32 bits in
-length.  Set to zeros.
-@end table
-
-@node Variable Record
-@section Variable Record
-
-There must be one variable record for each numeric variable and each
-string variable with width 8 bytes or less.  String variables wider
-than 8 bytes have one variable record for each 8 bytes, rounding up.
-The first variable record for a long string specifies the variable's
-correct dictionary information.  Subsequent variable records for a
-long string are filled with dummy information: a type of -1, no
-variable label or missing values, print and write formats that are
-ignored, and an empty string as name.  A few system files have been
-encountered that include a variable label on dummy variable records,
-so readers should take care to parse dummy variable records in the
-same way as other variable records.
-
-@anchor{Dictionary Index}
-The @dfn{dictionary index} of a variable is its offset in the set of
-variable records, including dummy variable records for long string
-variables.  The first variable record has a dictionary index of 0, the
-second has a dictionary index of 1, and so on.
-
-The system file format does not directly support string variables
-wider than 255 bytes.  Such very long string variables are represented
-by a number of narrower string variables.  @xref{Very Long String
-Record}, for details.
-
-@example
-int32               rec_type;
-int32               type;
-int32               has_var_label;
-int32               n_missing_values;
-int32               print;
-int32               write;
-char                name[8];
-
-/* @r{Present only if @code{has_var_label} is 1.} */
-int32               label_len;
-char                label[];
-
-/* @r{Present only if @code{n_missing_values} is nonzero}. */
-flt64               missing_values[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type code.  Always set to 2.
-
-@item int32 type;
-Variable type code.  Set to 0 for a numeric variable.  For a short
-string variable or the first part of a long string variable, this is set
-to the width of the string.  For the second and subsequent parts of a
-long string variable, set to -1, and the remaining fields in the
-structure are ignored.
-
-@item int32 has_var_label;
-If this variable has a variable label, set to 1; otherwise, set to 0.
-
-@item int32 n_missing_values;
-If the variable has no missing values, set to 0.  If the variable has
-one, two, or three discrete missing values, set to 1, 2, or 3,
-respectively.  If the variable has a range for missing variables, set to
--2; if the variable has a range for missing variables plus a single
-discrete value, set to -3.
-
-@item int32 print;
-Print format for this variable.  See below.
-
-@item int32 write;
-Write format for this variable.  See below.
-
-@item char name[8];
-Variable name.  The variable name must begin with a capital letter or
-the at-sign (@samp{@@}).  Subsequent characters may also be digits, octothorpes
-(@samp{#}), dollar signs (@samp{$}), underscores (@samp{_}), or full
-stops (@samp{.}).  The variable name is padded on the right with spaces.
-
-@item int32 label_len;
-This field is present only if @code{has_var_label} is set to 1.  It is
-set to the length, in characters, of the variable label, which must be a
-number between 0 and 120.
-
-@item char label[];
-This field is present only if @code{has_var_label} is set to 1.  It has
-length @code{label_len}, rounded up to the nearest multiple of 32 bits.
-The first @code{label_len} characters are the variable's variable label.
-
-@item flt64 missing_values[];
-This field is present only if @code{n_missing_values} is not 0.  It has
-the same number of elements as the absolute value of
-@code{n_missing_values}.  For discrete missing values, each element
-represents one missing value.  When a range is present, the first
-element denotes the minimum value in the range, and the second element
-denotes the maximum value in the range.  When a range plus a value are
-present, the third element denotes the additional discrete missing
-value.  HIGHEST and LOWEST are indicated as described in the chapter
-introduction.
-@end table
-
-The @code{print} and @code{write} members of sysfile_variable are output
-formats coded into @code{int32} types.  The least-significant byte
-of the @code{int32} represents the number of decimal places, and the
-next two bytes in order of increasing significance represent field width
-and format type, respectively.  The most-significant byte is not
-used and should be set to zero.
-
-Format types are defined as follows:
-
-@quotation
-@multitable {Value} {@code{DATETIME}}
-@headitem Value
-@tab Meaning
-@item 0
-@tab Not used.
-@item 1
-@tab @code{A}
-@item 2
-@tab @code{AHEX}
-@item 3
-@tab @code{COMMA}
-@item 4
-@tab @code{DOLLAR}
-@item 5
-@tab @code{F}
-@item 6
-@tab @code{IB}
-@item 7
-@tab @code{PIBHEX}
-@item 8
-@tab @code{P}
-@item 9
-@tab @code{PIB}
-@item 10
-@tab @code{PK}
-@item 11
-@tab @code{RB}
-@item 12
-@tab @code{RBHEX}
-@item 13
-@tab Not used.
-@item 14
-@tab Not used.
-@item 15
-@tab @code{Z}
-@item 16
-@tab @code{N}
-@item 17
-@tab @code{E}
-@item 18
-@tab Not used.
-@item 19
-@tab Not used.
-@item 20
-@tab @code{DATE}
-@item 21
-@tab @code{TIME}
-@item 22
-@tab @code{DATETIME}
-@item 23
-@tab @code{ADATE}
-@item 24
-@tab @code{JDATE}
-@item 25
-@tab @code{DTIME}
-@item 26
-@tab @code{WKDAY}
-@item 27
-@tab @code{MONTH}
-@item 28
-@tab @code{MOYR}
-@item 29
-@tab @code{QYR}
-@item 30
-@tab @code{WKYR}
-@item 31
-@tab @code{PCT}
-@item 32
-@tab @code{DOT}
-@item 33
-@tab @code{CCA}
-@item 34
-@tab @code{CCB}
-@item 35
-@tab @code{CCC}
-@item 36
-@tab @code{CCD}
-@item 37
-@tab @code{CCE}
-@item 38
-@tab @code{EDATE}
-@item 39
-@tab @code{SDATE}
-@end multitable
-@end quotation
-
-@node Value Labels Records
-@section Value Labels Records
-
-The value label record has the following format:
-
-@example
-int32               rec_type;
-int32               label_count;
-
-/* @r{Repeated @code{label_cnt} times}. */
-char                value[8];
-char                label_len;
-char                label[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 3.
-
-@item int32 label_count;
-Number of value labels present in this record.
-@end table
-
-The remaining fields are repeated @code{count} times.  Each
-repetition specifies one value label.
-
-@table @code
-@item char value[8];
-A numeric value or a short string value padded as necessary to 8 bytes
-in length.  Its type and width cannot be determined until the
-following value label variables record (see below) is read.
-
-@item char label_len;
-The label's length, in bytes.
-
-@item char label[];
-@code{label_len} bytes of the actual label, followed by up to 7 bytes
-of padding to bring @code{label} and @code{label_len} together to a
-multiple of 8 bytes in length.
-@end table
-
-The value label record is always immediately followed by a value label
-variables record with the following format:
-
-@example
-int32               rec_type;
-int32               var_count;
-int32               vars[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 4.
-
-@item int32 var_count;
-Number of variables that the associated value labels from the value
-label record are to be applied.
-
-@item int32 vars[];
-A list of dictionary indexes of variables to which to apply the value
-labels (@pxref{Dictionary Index}).  There are @code{var_count}
-elements.
-
-String variables wider than 8 bytes may not have value labels.
-@end table
-
-@node Document Record
-@section Document Record
-
-The document record, if present, has the following format:
-
-@example
-int32               rec_type;
-int32               n_lines;
-char                lines[][80];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 6.
-
-@item int32 n_lines;
-Number of lines of documents present.
-
-@item char lines[][80];
-Document lines.  The number of elements is defined by @code{n_lines}.
-Lines shorter than 80 characters are padded on the right with spaces.
-@end table
-
-@node Machine Integer Info Record
-@section Machine Integer Info Record
-
-The integer info record, if present, has the following format:
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Data.} */
-int32               version_major;
-int32               version_minor;
-int32               version_revision;
-int32               machine_code;
-int32               floating_point_rep;
-int32               compression_code;
-int32               endianness;
-int32               character_code;
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  Always set to 3.
-
-@item int32 size;
-Size of each piece of data in the data part, in bytes.  Always set to 4.
-
-@item int32 count;
-Number of pieces of data in the data part.  Always set to 8.
-
-@item int32 version_major;
-PSPP major version number.  In version @var{x}.@var{y}.@var{z}, this
-is @var{x}.
-
-@item int32 version_minor;
-PSPP minor version number.  In version @var{x}.@var{y}.@var{z}, this
-is @var{y}.
-
-@item int32 version_revision;
-PSPP version revision number.  In version @var{x}.@var{y}.@var{z},
-this is @var{z}.
-
-@item int32 machine_code;
-Machine code.  PSPP always set this field to value to -1, but other
-values may appear.
-
-@item int32 floating_point_rep;
-Floating point representation code.  For IEEE 754 systems this is 1.
-IBM 370 sets this to 2, and DEC VAX E to 3.
-
-@item int32 compression_code;
-Compression code.  Always set to 1.
-
-@item int32 endianness;
-Machine endianness.  1 indicates big-endian, 2 indicates little-endian.
-
-@item int32 character_code;
-Character code.  1 indicates EBCDIC, 2 indicates 7-bit ASCII, 3
-indicates 8-bit ASCII, 4 indicates DEC Kanji.
-Windows code page numbers are also valid.
-@end table
-
-@node Machine Floating-Point Info Record
-@section Machine Floating-Point Info Record
-
-The floating-point info record, if present, has the following format:
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Data.} */
-flt64               sysmis;
-flt64               highest;
-flt64               lowest;
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  Always set to 4.
-
-@item int32 size;
-Size of each piece of data in the data part, in bytes.  Always set to 8.
-
-@item int32 count;
-Number of pieces of data in the data part.  Always set to 3.
-
-@item flt64 sysmis;
-The system missing value.
-
-@item flt64 highest;
-The value used for HIGHEST in missing values.
-
-@item flt64 lowest;
-The value used for LOWEST in missing values.
-@end table
-
-@node Variable Display Parameter Record
-@section Variable Display Parameter Record
-
-The variable display parameter record, if present, has the following
-format:
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Repeated @code{count} times}. */
-int32               measure;
-int32               width;
-int32               alignment;
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  Always set to 11.
-
-@item int32 size;
-The size of @code{int32}.  Always set to 4.
-
-@item int32 count;
-The number of sets of variable display parameters (ordinarily the
-number of variables in the dictionary), times 3.
-@end table
-
-The remaining members are repeated @code{count} times, in the same
-order as the variable records.  No element corresponds to variable
-records that continue long string variables.  The meanings of these
-members are as follows:
-
-@table @code
-@item int32 measure;
-The measurement type of the variable:
-@table @asis
-@item 1
-Nominal Scale
-@item 2
-Ordinal Scale
-@item 3
-Continuous Scale
-@end table
-
-SPSS 14 sometimes writes a @code{measure} of 0.  PSPP interprets this
-as nominal scale.
-
-@item int32 width;
-The width of the display column for the variable in characters.
-
-@item int32 alignment;
-The alignment of the variable for display purposes:
-
-@table @asis
-@item 0
-Left aligned
-@item 1
-Right aligned
-@item 2
-Centre aligned
-@end table
-@end table
-
-@node Long Variable Names Record
-@section Long Variable Names Record
-
-If present, the long variable names record has the following format:
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Exactly @code{count} bytes of data.} */
-char                var_name_pairs[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  Always set to 13.
-
-@item int32 size;
-The size of each element in the @code{var_name_pairs} member. Always set to 1.
-
-@item int32 count;
-The total number of bytes in @code{var_name_pairs}.
-
-@item char var_name_pairs[];
-A list of @var{key}--@var{value} tuples, where @var{key} is the name
-of a variable, and @var{value} is its long variable name.
-The @var{key} field is at most 8 bytes long and must match the
-name of a variable which appears in the variable record (@pxref{Variable
-Record}).
-The @var{value} field is at most 64 bytes long.
-The @var{key} and @var{value} fields are separated by a @samp{=} byte.
-Each tuple is separated by a byte whose value is 09.  There is no
-trailing separator following the last tuple.
-The total length is @code{count} bytes.
-@end table
-
-@node Very Long String Record
-@section Very Long String Record
-
-Old versions of SPSS limited string variables to a width of 255 bytes.
-For backward compatibility with these older versions, the system file
-format represents a string longer than 255 bytes, called a @dfn{very
-long string}, as a collection of strings no longer than 255 bytes
-each.  The strings concatenated to make a very long string are called
-its @dfn{segments}; for consistency, variables other than very long
-strings are considered to have a single segment.
-
-A very long string with a width of @var{w} has @var{n} =
-(@var{w} + 251) / 252 segments, that is, one segment for every
-252 bytes of width, rounding up.  It would be logical, then, for each
-of the segments except the last to have a width of 252 and the last
-segment to have the remainder, but this is not the case.  In fact,
-each segment except the last has a width of 255 bytes.  The last
-segment has width @var{w} - (@var{n} - 1) * 252; some versions
-of SPSS make it slightly wider, but not wide enough to make the last
-segment require another 8 bytes of data.
-
-Data is packed tightly into segments of a very long string, 255 bytes
-per segment.  Because 255 bytes of segment data are allocated for
-every 252 bytes of the very long string's width (approximately), some
-unused space is left over at the end of the allocated segments.  Data
-in unused space is ignored.
-
-Example: Consider a very long string of width 20,000.  Such a very
-long string has 20,000 / 252 = 80 (rounding up) segments.  The first
-79 segments have width 255; the last segment has width 20,000 - 79 *
-252 = 92 or slightly wider (up to 96 bytes, the next multiple of 8).
-The very long string's data is actually stored in the 19,890 bytes in
-the first 78 segments, plus the first 110 bytes of the 79th segment
-(19,890 + 110 = 20,000).  The remaining 145 bytes of the 79th segment
-and all 92 bytes of the 80th segment are unused.
-
-The very long string record explains how to stitch together segments
-to obtain very long string data.  For each of the very long string
-variables in the dictionary, it specifies the name of its first
-segment's variable and the very long string variable's actual width.
-The remaining segments immediately follow the named variable in the
-system file's dictionary.
-
-The very long string record, which is present only if the system file
-contains very long string variables, has the following format:
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Exactly @code{count} bytes of data.} */
-char                string_lengths[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  Always set to 14.
-
-@item int32 size;
-The size of each element in the @code{string_lengths} member. Always set to 1.
-
-@item int32 count;
-The total number of bytes in @code{string_lengths}.
-
-@item char string_lengths[];
-A list of @var{key}--@var{value} tuples, where @var{key} is the name
-of a variable, and @var{value} is its length.
-The @var{key} field is at most 8 bytes long and must match the
-name of a variable which appears in the variable record (@pxref{Variable
-Record}).
-The @var{value} field is exactly 5 bytes long. It is a zero-padded,
-ASCII-encoded string that is the length of the variable.
-The @var{key} and @var{value} fields are separated by a @samp{=} byte.
-Tuples are delimited by a two-byte sequence @{00, 09@}.
-After the last tuple, there may be a single byte 00, or @{00, 09@}.
-The total length is @code{count} bytes.
-@end table
-
-@node Miscellaneous Informational Records
-@section Miscellaneous Informational Records
-
-Some specific types of miscellaneous informational records are
-documented here, but others are known to exist.  PSPP ignores unknown
-miscellaneous informational records when reading system files.
-
-@example
-/* @r{Header.} */
-int32               rec_type;
-int32               subtype;
-int32               size;
-int32               count;
-
-/* @r{Exactly @code{size * count} bytes of data.} */
-char                data[];
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 7.
-
-@item int32 subtype;
-Record subtype.  May take any value.  According to Aapi
-H@"am@"al@"ainen, value 5 indicates a set of grouped variables and 6
-indicates date info (probably related to USE).
-
-@item int32 size;
-Size of each piece of data in the data part.  Should have the value 1,
-4, or 8, for @code{char}, @code{int32}, and @code{flt64} format data,
-respectively.
-
-@item int32 count;
-Number of pieces of data in the data part.
-
-@item char data[];
-Arbitrary data.  There must be @code{size} times @code{count} bytes of
-data.
-@end table
-
-@node Dictionary Termination Record
-@section Dictionary Termination Record
-
-The dictionary termination record separates all other records from the
-data records.
-
-@example
-int32               rec_type;
-int32               filler;
-@end example
-
-@table @code
-@item int32 rec_type;
-Record type.  Always set to 999.
-
-@item int32 filler;
-Ignored padding.  Should be set to 0.
-@end table
-
-@node Data Record
-@section Data Record
-
-Data records must follow all other records in the system file.  There must
-be at least one data record in every system file.
-
-The format of data records varies depending on whether the data is
-compressed.  Regardless, the data is arranged in a series of 8-byte
-elements.
-
-When data is not compressed,
-each element corresponds to
-the variable declared in the respective variable record (@pxref{Variable
-Record}).  Numeric values are given in @code{flt64} format; string
-values are literal characters string, padded on the right when
-necessary to fill out 8-byte units.
-
-Compressed data is arranged in the following manner: the first 8 bytes
-in the data section is divided into a series of 1-byte command
-codes.  These codes have meanings as described below:
-
-@table @asis
-@item 0
-Ignored.  If the program writing the system file accumulates compressed
-data in blocks of fixed length, 0 bytes can be used to pad out extra
-bytes remaining at the end of a fixed-size block.
-
-@item 1 through 251
-A number with
-value @var{code} - @var{bias}, where
-@var{code} is the value of the compression code and @var{bias} is the
-variable @code{bias} from the file header.  For example,
-code 105 with bias 100.0 (the normal value) indicates a numeric variable
-of value 5.
-
-@item 252
-End of file.  This code may or may not appear at the end of the data
-stream.  PSPP always outputs this code but its use is not required.
-
-@item 253
-A numeric or string value that is not
-compressible.  The value is stored in the 8 bytes following the
-current block of command bytes.  If this value appears twice in a block
-of command bytes, then it indicates the second group of 8 bytes following the
-command bytes, and so on.
-
-@item 254
-An 8-byte string value that is all spaces.
-
-@item 255
-The system-missing value.
-@end table
-
-When the end of the an 8-byte group of command bytes is reached, any
-blocks of non-compressible values indicated by code 253 are skipped,
-and the next element of command bytes is read and interpreted, until
-the end of the file or a code with value 252 is reached.
-@setfilename ignored
diff --git a/doc/dev/concepts.texi b/doc/dev/concepts.texi
new file mode 100644 (file)
index 0000000..b1d8583
--- /dev/null
@@ -0,0 +1,2451 @@
+@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::
+* Coding Conventions::
+* Cases::
+* Data Sets::
+* Pools::
+@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, PSPP Users Guide}, 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, PSPP Users Guide}).
+@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 Users Guide}).
+
+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 Users
+Guide}).  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, PSPP
+Users Guide}, 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
+
+@anchor{fmt_min_input_width}
+@anchor{fmt_max_input_width}
+@anchor{fmt_min_output_width}
+@anchor{fmt_max_output_width}
+@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
+
+@anchor{fmt_max_input_decimals}
+@anchor{fmt_max_output_decimals}
+@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, PSPP Users Guide}).
+
+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, PSPP
+Users Guide}) 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, PSPP Users Guide}).  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}.
+@c (@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},
+@c (@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, PSPP Users Guide}).  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,
+PSPP Users Guide}), 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, PSPP Users Guide}, 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, PSPP Users Guide}).
+
+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, PSPP Users Guide}).  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, PSPP Users Guide}).  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, PSPP Users Guide}), 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, PSPP Users Guide}), 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{Input and Output 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, PSPP Users Guide}, 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, PSPP Users Guide}).  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, PSPP Users Guide}, 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, PSPP Users
+Guide}).  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, PSPP
+Users Guide}) 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, PSPP Users Guide}.
+
+@item DC_SCRATCH
+A scratch variable, one whose name begins with @samp{#}.
+@xref{Scratch Variables,,,pspp, PSPP Users Guide}.
+@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,
+PSPP Users Guide}).  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. @c (@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, PSPP Users Guide}, 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, PSPP Users Guide}).
+
+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 Variables::
+* 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 Variables
+@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. @c (@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.
+
+@anchor{dict_reorder_var}
+@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, PSPP Users Guide}, 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, PSPP Users Guide}, 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, PSPP Users Guide}), 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, PSPP Users Guide}) 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, PSPP
+Users Guide}).
+
+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,,,pspp, PSPP
+Users Guide}), @cmd{ADD DOCUMENT} (@pxref{ADD DOCUMENT,,,pspp, PSPP
+Users Guide}), and @cmd{DROP DOCUMENTS} (@pxref{DROP DOCUMENTS,,,pspp,
+PSPP Users Guide}) 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 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}.
+
+This section needs to be finished.
+
+@node Cases
+@section Cases
+
+This section needs to be written.
+
+@node Data Sets
+@section Data Sets
+
+This section needs to be written.
+
+@node Pools
+@section Pools
+
+This section needs to be written.
+
+@c  LocalWords:  bool
diff --git a/doc/dev/data.texi b/doc/dev/data.texi
new file mode 100644 (file)
index 0000000..356b5e0
--- /dev/null
@@ -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
diff --git a/doc/dev/intro.texi b/doc/dev/intro.texi
new file mode 100644 (file)
index 0000000..1558745
--- /dev/null
@@ -0,0 +1,22 @@
+@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, ,
+Introduction, pspp, PSPP Users Guide}.
+
+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.
diff --git a/doc/dev/output.texi b/doc/dev/output.texi
new file mode 100644 (file)
index 0000000..6fb8b60
--- /dev/null
@@ -0,0 +1,2 @@
+@node Presenting Output
+@chapter Presenting Output
diff --git a/doc/dev/portable-file-format.texi b/doc/dev/portable-file-format.texi
new file mode 100644 (file)
index 0000000..31c1ac3
--- /dev/null
@@ -0,0 +1,479 @@
+@node Portable File Format
+@appendix Portable File Format
+
+These days, most computers use the same internal data formats for
+integer and floating-point data, if one ignores little differences like
+big- versus little-endian byte ordering.  However, occasionally it is
+necessary to exchange data between systems with incompatible data
+formats.  This is what portable files are designed to do.
+
+@strong{Please note:} This information is gleaned from examination of
+ASCII-formatted portable files only, so some of it may be incorrect
+for portable files formatted in EBCDIC or other character sets.
+
+@menu
+* Portable File Characters::
+* Portable File Structure::
+* Portable File Header::
+* Version and Date Info Record::
+* Identification Records::
+* Variable Count Record::
+* Case Weight Variable Record::
+* Variable Records::
+* Value Label Records::
+* Portable File Document Record::
+* Portable File Data::
+@end menu
+
+@node Portable File Characters
+@section Portable File Characters
+
+Portable files are arranged as a series of lines of 80
+characters each.  Each line is terminated by a carriage-return,
+line-feed sequence (``new-lines'').  New-lines are only used to avoid
+line length limits imposed by some OSes; they are not meaningful.
+
+Most lines in portable files are exactly 80 characters long.  The only
+exception is a line that ends in one or more spaces, in which the
+spaces may optionally be omitted.  Thus, a portable file reader must
+act as though a line shorter than 80 characters is padded to that
+length with spaces.
+
+The file must be terminated with a @samp{Z} character.  In addition, if
+the final line in the file does not have exactly 80 characters, then it
+is padded on the right with @samp{Z} characters.  (The file contents may
+be in any character set; the file contains a description of its own
+character set, as explained in the next section.  Therefore, the
+@samp{Z} character is not necessarily an ASCII @samp{Z}.)
+
+For the rest of the description of the portable file format, new-lines
+and the trailing @samp{Z}s will be ignored, as if they did not exist,
+because they are not an important part of understanding the file
+contents.
+
+@node Portable File Structure
+@section Portable File Structure
+
+Every portable file consists of the following records, in sequence:
+
+@itemize @bullet
+
+@item
+File header.
+
+@item
+Version and date info.
+
+@item
+Product identification.
+
+@item
+Author identification (optional).
+
+@item
+Subproduct identification (optional).
+
+@item
+Variable count.
+
+@item
+Case weight variable (optional).
+
+@item
+Variables.  Each variable record may optionally be followed by a
+missing value record and a variable label record.
+
+@item
+Value labels (optional).
+
+@item
+Documents (optional).
+
+@item
+Data.
+@end itemize
+
+Most records are identified by a single-character tag code.  The file
+header and version info record do not have a tag.
+
+Other than these single-character codes, there are three types of fields
+in a portable file: floating-point, integer, and string.  Floating-point
+fields have the following format:
+
+@itemize @bullet
+
+@item
+Zero or more leading spaces.
+
+@item
+Optional asterisk (@samp{*}), which indicates a missing value.  The
+asterisk must be followed by a single character, generally a period
+(@samp{.}), but it appears that other characters may also be possible.
+This completes the specification of a missing value.
+
+@item
+Optional minus sign (@samp{-}) to indicate a negative number.
+
+@item
+A whole number, consisting of one or more base-30 digits: @samp{0}
+through @samp{9} plus capital letters @samp{A} through @samp{T}.
+
+@item
+Optional fraction, consisting of a radix point (@samp{.}) followed by
+one or more base-30 digits.
+
+@item
+Optional exponent, consisting of a plus or minus sign (@samp{+} or
+@samp{-}) followed by one or more base-30 digits.
+
+@item
+A forward slash (@samp{/}).
+@end itemize
+
+Integer fields take a form identical to floating-point fields, but they
+may not contain a fraction.
+
+String fields take the form of a integer field having value @var{n},
+followed by exactly @var{n} characters, which are the string content.
+
+@node Portable File Header
+@section Portable File Header
+
+Every portable file begins with a 464-byte header, consisting of a
+200-byte collection of vanity splash strings, followed by a 256-byte
+character set translation table, followed by an 8-byte tag string.
+
+The 200-byte segment is divided into five 40-byte sections, each of
+which represents the string @code{@var{charset} SPSS PORT FILE} in a
+different character set encoding, where @var{charset} is the name of
+the character set used in the file, e.g.@: @code{ASCII} or
+@code{EBCDIC}.  Each string is padded on the right with spaces in its
+respective character set.
+
+It appears that these strings exist only to inform those who might view
+the file on a screen, and that they are not parsed by SPSS products.
+Thus, they can be safely ignored.  For those interested, the strings are
+supposed to be in the following character sets, in the specified order:
+EBCDIC, 7-bit ASCII, CDC 6-bit ASCII, 6-bit ASCII, Honeywell 6-bit
+ASCII.
+
+The 256-byte segment describes a mapping from the character set used in
+the portable file to an arbitrary character set having characters at the
+following positions:
+
+@table @asis
+@item 0--60
+
+Control characters.  Not important enough to describe in full here.
+
+@item 61--63
+
+Reserved.
+
+@item 64--73
+
+Digits @samp{0} through @samp{9}.
+
+@item 74--99
+
+Capital letters @samp{A} through @samp{Z}.
+
+@item 100--125
+
+Lowercase letters @samp{a} through @samp{z}.
+
+@item 126
+
+Space.
+
+@item 127--130
+
+Symbols @code{.<(+}
+
+@item 131
+
+Solid vertical pipe.
+
+@item 132--142
+
+Symbols @code{&[]!$*);^-/}
+
+@item 143
+
+Broken vertical pipe.
+
+@item 144--150
+
+Symbols @code{,%_>}?@code{`:}   @c @code{?} is an inverted question mark
+
+@item 151
+
+British pound symbol.
+
+@item 152--155
+
+Symbols @code{@@'="}.
+
+@item 156
+
+Less than or equal symbol.
+
+@item 157
+
+Empty box.
+
+@item 158
+
+Plus or minus.
+
+@item 159
+
+Filled box.
+
+@item 160
+
+Degree symbol.
+
+@item 161
+
+Dagger.
+
+@item 162
+
+Symbol @samp{~}.
+
+@item 163
+
+En dash.
+
+@item 164
+
+Lower left corner box draw.
+
+@item 165
+
+Upper left corner box draw.
+
+@item 166
+
+Greater than or equal symbol.
+
+@item 167--176
+
+Superscript @samp{0} through @samp{9}.
+
+@item 177
+
+Lower right corner box draw.
+
+@item 178
+
+Upper right corner box draw.
+
+@item 179
+
+Not equal symbol.
+
+@item 180
+
+Em dash.
+
+@item 181
+
+Superscript @samp{(}.
+
+@item 182
+
+Superscript @samp{)}.
+
+@item 183
+
+Horizontal dagger (?).
+
+@item 184--186
+
+Symbols @samp{@{@}\}.
+@item 187
+
+Cents symbol.
+
+@item 188
+
+Centered dot, or bullet.
+
+@item 189--255
+
+Reserved.
+@end table
+
+Symbols that are not defined in a particular character set are set to
+the same value as symbol 64; i.e., to @samp{0}.
+
+The 8-byte tag string consists of the exact characters @code{SPSSPORT}
+in the portable file's character set, which can be used to verify that
+the file is indeed a portable file.
+
+@node Version and Date Info Record
+@section Version and Date Info Record
+
+This record does not have a tag code.  It has the following structure:
+
+@itemize @bullet
+@item
+A single character identifying the file format version.  The letter A
+represents version 0, and so on.
+
+@item
+An 8-character string field giving the file creation date in the format
+YYYYMMDD.
+
+@item
+A 6-character string field giving the file creation time in the format
+HHMMSS.
+@end itemize
+
+@node Identification Records
+@section Identification Records
+
+The product identification record has tag code @samp{1}.  It consists of
+a single string field giving the name of the product that wrote the
+portable file.
+
+The author identification record has tag code @samp{2}.  It is
+optional.  If present, it consists of a single string field giving the
+name of the person who caused the portable file to be written.
+
+The subproduct identification record has tag code @samp{3}.  It is
+optional.  If present, it consists of a single string field giving
+additional information on the product that wrote the portable file.
+
+@node Variable Count Record
+@section Variable Count Record
+
+The variable count record has tag code @samp{4}.  It consists of two
+integer fields.  The first contains the number of variables in the file
+dictionary.  The purpose of the second is unknown; it contains the value
+161 in all portable files examined so far.
+
+@node Case Weight Variable Record
+@section Case Weight Variable Record
+
+The case weight variable record is optional.  If it is present, it
+indicates the variable used for weighting cases; if it is absent,
+cases are unweighted.  It has tag code @samp{6}.  It consists of a
+single string field that names the weighting variable.
+
+@node Variable Records
+@section Variable Records
+
+Each variable record represents a single variable.  Variable records
+have tag code @samp{7}.  They have the following structure:
+
+@itemize @bullet
+
+@item
+Width (integer).  This is 0 for a numeric variable, and a number between 1
+and 255 for a string variable.
+
+@item
+Name (string).  1--8 characters long.  Must be in all capitals.
+
+A few portable files that contain duplicate variable names have been
+spotted in the wild.  PSPP handles these by renaming the duplicates
+with numeric extensions: @code{@var{var}_1}, @code{@var{var}_2}, and
+so on.
+
+@item
+Print format.  This is a set of three integer fields:
+
+@itemize @minus
+
+@item
+Format type (@pxref{Variable Record}).
+
+@item
+Format width.  1--40.
+
+@item
+Number of decimal places.  1--40.
+@end itemize
+
+A few portable files with invalid format types or formats that are not
+of the appropriate width for their variables have been spotted in the
+wild.  PSPP assigns a default F or A format to a variable with an
+invalid format.
+
+@item
+Write format.  Same structure as the print format described above.
+@end itemize
+
+Each variable record can optionally be followed by a missing value
+record, which has tag code @samp{8}.  A missing value record has one
+field, the missing value itself (a floating-point or string, as
+appropriate).  Up to three of these missing value records can be used.
+
+There is also a record for missing value ranges, which has tag code
+@samp{B}.  It is followed by two fields representing the range, which
+are floating-point or string as appropriate.  If a missing value range
+is present, it may be followed by a single missing value record.
+
+Tag codes @samp{9} and @samp{A} represent @code{LO THRU @var{x}} and
+@code{@var{x} THRU HI} ranges, respectively.  Each is followed by a
+single field representing @var{x}.  If one of the ranges is present, it
+may be followed by a single missing value record.
+
+In addition, each variable record can optionally be followed by a
+variable label record, which has tag code @samp{C}.  A variable label
+record has one field, the variable label itself (string).
+
+@node Value Label Records
+@section Value Label Records
+
+Value label records have tag code @samp{D}.  They have the following
+format:
+
+@itemize @bullet
+@item
+Variable count (integer).
+
+@item
+List of variables (strings).  The variable count specifies the number in
+the list.  Variables are specified by their names.  All variables must
+be of the same type (numeric or string), but string variables do not
+necessarily have the same width.
+
+@item
+Label count (integer).
+
+@item
+List of (value, label) tuples.  The label count specifies the number of
+tuples.  Each tuple consists of a value, which is numeric or string as
+appropriate to the variables, followed by a label (string).
+@end itemize
+
+A few portable files that specify duplicate value labels, that is, two
+different labels for a single value of a single variable, have been
+spotted in the wild.  PSPP uses the last value label specified in
+these cases.
+
+@node Portable File Document Record
+@section Document Record
+
+One document record may optionally follow the value label record.  The
+document record consists of tag code @samp{E}, following by the number
+of document lines as an integer, followed by that number of strings,
+each of which represents one document line.  Document lines must be 80
+bytes long or shorter.
+
+@node Portable File Data
+@section Portable File Data
+
+The data record has tag code @samp{F}.  There is only one tag for all
+the data; thus, all the data must follow the dictionary.  The data is
+terminated by the end-of-file marker @samp{Z}, which is not valid as the
+beginning of a data element.
+
+Data elements are output in the same order as the variable records
+describing them.  String variables are output as string fields, and
+numeric variables are output as floating-point fields.
+@setfilename ignored
diff --git a/doc/dev/q2c.texi b/doc/dev/q2c.texi
new file mode 100644 (file)
index 0000000..af6b1da
--- /dev/null
@@ -0,0 +1,300 @@
+@node q2c Input Format
+@appendix @code{q2c} Input Format
+
+PSPP statistical procedures have a bizarre and somewhat irregular
+syntax.  Despite this, a parser generator has been written that
+adequately addresses many of the possibilities and tries to provide
+hooks for the exceptional cases.  This parser generator is named
+@code{q2c}.
+
+@menu
+* Invoking q2c::                q2c command-line syntax.
+* q2c Input Structure::         High-level layout of the input file.
+* Grammar Rules::               Syntax of the grammar rules.
+@end menu
+
+@node Invoking q2c
+@section Invoking q2c
+
+@example
+q2c @var{input.q} @var{output.c}
+@end example
+
+@code{q2c} translates a @samp{.q} file into a @samp{.c} file.  It takes
+exactly two command-line arguments, which are the input file name and
+output file name, respectively.  @code{q2c} does not accept any
+command-line options.
+
+@node q2c Input Structure
+@section @code{q2c} Input Structure
+
+@code{q2c} input files are divided into two sections: the grammar rules
+and the supporting code.  The @dfn{grammar rules}, which make up the
+first part of the input, are used to define the syntax of the
+statistical procedure to be parsed.  The @dfn{supporting code},
+following the grammar rules, are copied largely unchanged to the output
+file, except for certain escapes.
+
+The most important lines in the grammar rules are used for defining
+procedure syntax.  These lines can be prefixed with a dollar sign
+(@samp{$}), which prevents Emacs' CC-mode from munging them.  Besides
+this, a bang (@samp{!}) at the beginning of a line causes the line,
+minus the bang, to be written verbatim to the output file (useful for
+comments).  As a third special case, any line that begins with the exact
+characters @code{/* *INDENT} is ignored and not written to the output.
+This allows @code{.q} files to be processed through @code{indent}
+without being munged.
+
+The syntax of the grammar rules themselves is given in the following
+sections.
+
+The supporting code is passed into the output file largely unchanged.
+However, the following escapes are supported.  Each escape must appear
+on a line by itself.
+
+@table @code
+@item /* (header) */
+
+Expands to a series of C @code{#include} directives which include the
+headers that are required for the parser generated by @code{q2c}.
+
+@item /* (decls @var{scope}) */
+
+Expands to C variable and data type declarations for the variables and
+@code{enum}s input and output by the @code{q2c} parser.  @var{scope}
+must be either @code{local} or @code{global}.  @code{local} causes the
+declarations to be output as function locals.  @code{global} causes them
+to be declared as @code{static} module variables; thus, @code{global} is
+a bit of a misnomer.
+
+@item /* (parser) */
+
+Expands to the entire parser.  Must be enclosed within a C function.
+
+@item /* (free) */
+
+Expands to a set of calls to the @code{free} function for variables
+declared by the parser.  Only needs to be invoked if subcommands of type
+@code{string} are used in the grammar rules.
+@end table
+
+@node Grammar Rules
+@section Grammar Rules
+
+The grammar rules describe the format of the syntax that the parser
+generated by @code{q2c} will understand.  The way that the grammar rules
+are included in @code{q2c} input file are described above.
+
+The grammar rules are divided into tokens of the following types:
+
+@table @asis
+@item Identifier (@code{ID})
+
+An identifier token is a sequence of letters, digits, and underscores
+(@samp{_}).  Identifiers are @emph{not} case-sensitive.
+
+@item String (@code{STRING})
+
+String tokens are initiated by a double-quote character (@samp{"}) and
+consist of all the characters between that double quote and the next
+double quote, which must be on the same line as the first.  Within a
+string, a backslash can be used as a ``literal escape''.  The only
+reasons to use a literal escape are to include a double quote or a
+backslash within a string.
+
+@item Special character
+
+Other characters, other than white space, constitute tokens in
+themselves.
+
+@end table
+
+The syntax of the grammar rules is as follows:
+
+@example
+grammar-rules ::= command-name opt-prefix : subcommands .
+command-name ::= ID
+             ::= STRING
+opt-prefix ::=
+           ::= ( ID )
+subcommands ::= subcommand
+            ::= subcommands ; subcommand
+@end example
+
+The syntax begins with an ID token that gives the name of the
+procedure to be parsed.  For command names that contain multiple
+words, a STRING token may be used instead, e.g.@: @samp{"FILE
+HANDLE"}.  Optionally, an ID in parentheses specifies a prefix used
+for all file-scope identifiers declared by the emitted code.
+
+The rest of the syntax consists of subcommands separated by semicolons
+(@samp{;}) and terminated with a full stop (@samp{.}).
+
+@example
+subcommand ::= default-opt arity-opt ID sbc-defn
+default-opt ::=
+            ::= *
+arity-opt ::=
+          ::= +
+          ::= ^
+sbc-defn ::= opt-prefix = specifiers
+         ::= [ ID ] = array-sbc
+         ::= opt-prefix = sbc-special-form
+@end example
+
+A subcommand that begins with an asterisk (@samp{*}) is the default
+subcommand.  The keyword used for the default subcommand can be omitted
+in the PSPP syntax file.
+
+A plus sign (@samp{+}) indicates that a subcommand can appear more than
+once.  A caret (@samp{^}) indicate that a subcommand must appear exactly
+once.  A subcommand marked with neither character may appear once or not
+at all, but not more than once.
+
+The subcommand name appears after the leading option characters.
+
+There are three forms of subcommands.  The first and most common form
+simply gives an equals sign (@samp{=}) and a list of specifiers, which
+can each be set to a single setting.  The second form declares an array,
+which is a set of flags that can be individually turned on by the user.
+There are also several special forms that do not take a list of
+specifiers.
+
+Arrays require an additional @code{ID} argument.  This is used as a
+prefix, prepended to the variable names constructed from the
+specifiers.  The other forms also allow an optional prefix to be
+specified.
+
+@example
+array-sbc ::= alternatives
+          ::= array-sbc , alternatives
+alternatives ::= ID
+             ::= alternatives | ID
+@end example
+
+An array subcommand is a set of Boolean values that can independently be
+turned on by the user, listed separated by commas (@samp{,}).  If an value has more
+than one name then these names are separated by pipes (@samp{|}).
+
+@example
+specifiers ::= specifier
+           ::= specifiers , specifier
+specifier ::= opt-id : settings
+opt-id ::=
+       ::= ID
+@end example
+
+Ordinary subcommands (other than arrays and special forms) require a
+list of specifiers.  Each specifier has an optional name and a list of
+settings.  If the name is given then a correspondingly named variable
+will be used to store the user's choice of setting.  If no name is given
+then there is no way to tell which setting the user picked; in this case
+the settings should probably have values attached.
+
+@example
+settings ::= setting
+         ::= settings / setting
+setting ::= setting-options ID setting-value
+setting-options ::=
+                ::= *
+                ::= !
+                ::= * !
+@end example
+
+Individual settings are separated by forward slashes (@samp{/}).  Each
+setting can be as little as an @code{ID} token, but options and values
+can optionally be included.  The @samp{*} option means that, for this
+setting, the @code{ID} can be omitted.  The @samp{!} option means that
+this option is the default for its specifier.
+
+@example
+setting-value ::=
+              ::= ( setting-value-2 )
+              ::= setting-value-2
+setting-value-2 ::= setting-value-options setting-value-type : ID
+                    setting-value-restriction
+setting-value-options ::=
+                      ::= *
+setting-value-type ::= N
+                   ::= D
+                   ::= S
+setting-value-restriction ::=
+                          ::= , STRING
+@end example
+
+Settings may have values.  If the value must be enclosed in parentheses,
+then enclose the value declaration in parentheses.  Declare the setting
+type as @samp{n}, @samp{d}, or @samp{s} for integer, floating-point,
+or string type, respectively.  The given @code{ID} is used to
+construct a variable name.
+If option @samp{*} is given, then the value is optional; otherwise it
+must be specified whenever the corresponding setting is specified.  A
+``restriction'' can also be specified which is a string giving a C
+expression limiting the valid range of the value.  The special escape
+@code{%s} should be used within the restriction to refer to the
+setting's value variable.
+
+@example
+sbc-special-form ::= VAR
+                 ::= VARLIST varlist-options
+                 ::= INTEGER opt-list
+                 ::= DOUBLE opt-list
+                 ::= PINT
+                 ::= STRING @r{(the literal word STRING)} string-options
+                 ::= CUSTOM
+varlist-options ::=
+                ::= ( STRING )
+opt-list ::=
+         ::= LIST
+string-options ::=
+               ::= ( STRING STRING )
+@end example
+
+The special forms are of the following types:
+
+@table @code
+@item VAR
+
+A single variable name.
+
+@item VARLIST
+
+A list of variables.  If given, the string can be used to provide
+@code{PV_@var{*}} options to the call to @code{parse_variables}.
+
+@item INTEGER
+
+A single integer value.
+
+@item INTEGER LIST
+
+A list of integers separated by spaces or commas.
+
+@item DOUBLE
+
+A single floating-point value.
+
+@item DOUBLE LIST
+
+A list of floating-point values.
+
+@item PINT
+
+A single positive integer value.
+
+@item STRING
+
+A string value.  If the options are given then the first string is an
+expression giving a restriction on the value of the string; the second
+string is an error message to display when the restriction is violated.
+
+@item CUSTOM
+
+A custom function is used to parse this subcommand.  The function must
+have prototype @code{int custom_@var{name} (void)}.  It should return 0
+on failure (when it has already issued an appropriate diagnostic), 1 on
+success, or 2 if it fails and the calling function should issue a syntax
+error on behalf of the custom handler.
+
+@end table
+@setfilename ignored
diff --git a/doc/dev/syntax.texi b/doc/dev/syntax.texi
new file mode 100644 (file)
index 0000000..81d34c0
--- /dev/null
@@ -0,0 +1,2 @@
+@node Parsing Command Syntax
+@chapter Parsing Command Syntax
diff --git a/doc/dev/system-file-format.texi b/doc/dev/system-file-format.texi
new file mode 100644 (file)
index 0000000..193c660
--- /dev/null
@@ -0,0 +1,906 @@
+@node System File Format
+@appendix System File Format
+
+A system file encapsulates a set of cases and dictionary information
+that describes how they may be interpreted.  This chapter describes
+the format of a system file.
+
+System files use three data types: 8-bit characters, 32-bit integers,
+and 64-bit floating points, called here @code{char}, @code{int32}, and
+@code{flt64}, respectively.  Data is not necessarily aligned on a word
+or double-word boundary: the long variable name record (@pxref{Long
+Variable Names Record}) and very long string records (@pxref{Very Long
+String Record}) have arbitrary byte length and can therefore cause all
+data coming after them in the file to be misaligned.
+
+Integer data in system files may be big-endian or little-endian.  A
+reader may detect the endianness of a system file by examining
+@code{layout_code} in the file header record
+(@pxref{layout_code,,@code{layout_code}}).
+
+Floating-point data in system files may nominally be in IEEE 754, IBM,
+or VAX formats.  A reader may detect the floating-point format in use
+by examining @code{bias} in the file header record
+(@pxref{bias,,@code{bias}}).
+
+PSPP detects big-endian and little-endian integer formats in system
+files and translates as necessary.  PSPP also detects the
+floating-point format in use, as well as the endianness of IEEE 754
+floating-point numbers, and translates as needed.  However, only IEEE
+754 numbers with the same endianness as integer data in the same file
+has actually been observed in system files, and it is likely that
+other formats are obsolete or were never used.
+
+The PSPP system-missing value is represented by the largest possible
+negative number in the floating point format (@code{-DBL_MAX}).  Two
+other values are important for use as missing values: @code{HIGHEST},
+represented by the largest possible positive number (@code{DBL_MAX}),
+and @code{LOWEST}, represented by the second-largest negative number
+(in IEEE 754 format, @code{0xffeffffffffffffe}).
+
+System files are divided into records, each of which begins with a
+4-byte record type, usually regarded as an @code{int32}.
+
+The records must appear in the following order:
+
+@itemize @bullet
+@item
+File header record.
+
+@item
+Variable records.
+
+@item
+All pairs of value labels records and value label variables records,
+if present.
+
+@item
+Document record, if present.
+
+@item
+Any of the following records, if present, in any order:
+
+@itemize @minus
+@item
+Machine integer info record.
+
+@item
+Machine floating-point info record.
+
+@item
+Variable display parameter record.
+
+@item
+Long variable names record.
+
+@item
+Miscellaneous informational records.
+@end itemize
+
+@item
+Dictionary termination record.
+
+@item
+Data record.
+@end itemize
+
+Each type of record is described separately below.
+
+@menu
+* File Header Record::
+* Variable Record::
+* Value Labels Records::
+* Document Record::
+* Machine Integer Info Record::
+* Machine Floating-Point Info Record::
+* Variable Display Parameter Record::
+* Long Variable Names Record::
+* Very Long String Record::
+* Miscellaneous Informational Records::
+* Dictionary Termination Record::
+* Data Record::
+@end menu
+
+@node File Header Record
+@section File Header Record
+
+The file header is always the first record in the file.  It has the
+following format:
+
+@example
+char                rec_type[4];
+char                prod_name[60];
+int32               layout_code;
+int32               nominal_case_size;
+int32               compressed;
+int32               weight_index;
+int32               ncases;
+flt64               bias;
+char                creation_date[9];
+char                creation_time[8];
+char                file_label[64];
+char                padding[3];
+@end example
+
+@table @code
+@item char rec_type[4];
+Record type code, set to @samp{$FL2}.
+
+@item char prod_name[60];
+Product identification string.  This always begins with the characters
+@samp{@@(#) SPSS DATA FILE}.  PSPP uses the remaining characters to
+give its version and the operating system name; for example, @samp{GNU
+pspp 0.1.4 - sparc-sun-solaris2.5.2}.  The string is truncated if it
+would be longer than 60 characters; otherwise it is padded on the right
+with spaces.
+
+@anchor{layout_code}
+@item int32 layout_code;
+Normally set to 2, although a few system files have been spotted in
+the wild with a value of 3 here.  PSPP use this value to determine the
+file's integer endianness (@pxref{System File Format}).
+
+@item int32 nominal_case_size;
+Number of data elements per case.  This is the number of variables,
+except that long string variables add extra data elements (one for every
+8 characters after the first 8).  However, string variables do not
+contribute to this value beyond the first 255 bytes.   Further, system
+files written by some systems set this value to -1.  In general, it is
+unsafe for systems reading system files to rely upon this value.
+
+@item int32 compressed;
+Set to 1 if the data in the file is compressed, 0 otherwise.
+
+@item int32 weight_index;
+If one of the variables in the data set is used as a weighting
+variable, set to the dictionary index of that variable, plus 1
+(@pxref{Dictionary Index}).  Otherwise, set to 0.
+
+@item int32 ncases;
+Set to the number of cases in the file if it is known, or -1 otherwise.
+
+In the general case it is not possible to determine the number of cases
+that will be output to a system file at the time that the header is
+written.  The way that this is dealt with is by writing the entire
+system file, including the header, then seeking back to the beginning of
+the file and writing just the @code{ncases} field.  For `files' in which
+this is not valid, the seek operation fails.  In this case,
+@code{ncases} remains -1.
+
+@anchor{bias}
+@item flt64 bias;
+Compression bias, ordinarily set to 100.  Only integers between
+@code{1 - bias} and @code{251 - bias} can be compressed.
+
+By assuming that its value is 100, PSPP uses @code{bias} to determine
+the file's floating-point format and endianness (@pxref{System File
+Format}).  If the compression bias is not 100, PSPP cannot auto-detect
+the floating-point format and assumes that it is IEEE 754 format with
+the same endianness as the system file's integers, which is correct
+for all known system files.
+
+@item char creation_date[9];
+Date of creation of the system file, in @samp{dd mmm yy}
+format, with the month as standard English abbreviations, using an
+initial capital letter and following with lowercase.  If the date is not
+available then this field is arbitrarily set to @samp{01 Jan 70}.
+
+@item char creation_time[8];
+Time of creation of the system file, in @samp{hh:mm:ss}
+format and using 24-hour time.  If the time is not available then this
+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,,,pspp,
+PSPP Users Guide}).  Padded on the right with spaces.
+
+@item char padding[3];
+Ignored padding bytes to make the structure a multiple of 32 bits in
+length.  Set to zeros.
+@end table
+
+@node Variable Record
+@section Variable Record
+
+There must be one variable record for each numeric variable and each
+string variable with width 8 bytes or less.  String variables wider
+than 8 bytes have one variable record for each 8 bytes, rounding up.
+The first variable record for a long string specifies the variable's
+correct dictionary information.  Subsequent variable records for a
+long string are filled with dummy information: a type of -1, no
+variable label or missing values, print and write formats that are
+ignored, and an empty string as name.  A few system files have been
+encountered that include a variable label on dummy variable records,
+so readers should take care to parse dummy variable records in the
+same way as other variable records.
+
+@anchor{Dictionary Index}
+The @dfn{dictionary index} of a variable is its offset in the set of
+variable records, including dummy variable records for long string
+variables.  The first variable record has a dictionary index of 0, the
+second has a dictionary index of 1, and so on.
+
+The system file format does not directly support string variables
+wider than 255 bytes.  Such very long string variables are represented
+by a number of narrower string variables.  @xref{Very Long String
+Record}, for details.
+
+@example
+int32               rec_type;
+int32               type;
+int32               has_var_label;
+int32               n_missing_values;
+int32               print;
+int32               write;
+char                name[8];
+
+/* @r{Present only if @code{has_var_label} is 1.} */
+int32               label_len;
+char                label[];
+
+/* @r{Present only if @code{n_missing_values} is nonzero}. */
+flt64               missing_values[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type code.  Always set to 2.
+
+@item int32 type;
+Variable type code.  Set to 0 for a numeric variable.  For a short
+string variable or the first part of a long string variable, this is set
+to the width of the string.  For the second and subsequent parts of a
+long string variable, set to -1, and the remaining fields in the
+structure are ignored.
+
+@item int32 has_var_label;
+If this variable has a variable label, set to 1; otherwise, set to 0.
+
+@item int32 n_missing_values;
+If the variable has no missing values, set to 0.  If the variable has
+one, two, or three discrete missing values, set to 1, 2, or 3,
+respectively.  If the variable has a range for missing variables, set to
+-2; if the variable has a range for missing variables plus a single
+discrete value, set to -3.
+
+@item int32 print;
+Print format for this variable.  See below.
+
+@item int32 write;
+Write format for this variable.  See below.
+
+@item char name[8];
+Variable name.  The variable name must begin with a capital letter or
+the at-sign (@samp{@@}).  Subsequent characters may also be digits, octothorpes
+(@samp{#}), dollar signs (@samp{$}), underscores (@samp{_}), or full
+stops (@samp{.}).  The variable name is padded on the right with spaces.
+
+@item int32 label_len;
+This field is present only if @code{has_var_label} is set to 1.  It is
+set to the length, in characters, of the variable label, which must be a
+number between 0 and 120.
+
+@item char label[];
+This field is present only if @code{has_var_label} is set to 1.  It has
+length @code{label_len}, rounded up to the nearest multiple of 32 bits.
+The first @code{label_len} characters are the variable's variable label.
+
+@item flt64 missing_values[];
+This field is present only if @code{n_missing_values} is not 0.  It has
+the same number of elements as the absolute value of
+@code{n_missing_values}.  For discrete missing values, each element
+represents one missing value.  When a range is present, the first
+element denotes the minimum value in the range, and the second element
+denotes the maximum value in the range.  When a range plus a value are
+present, the third element denotes the additional discrete missing
+value.  HIGHEST and LOWEST are indicated as described in the chapter
+introduction.
+@end table
+
+The @code{print} and @code{write} members of sysfile_variable are output
+formats coded into @code{int32} types.  The least-significant byte
+of the @code{int32} represents the number of decimal places, and the
+next two bytes in order of increasing significance represent field width
+and format type, respectively.  The most-significant byte is not
+used and should be set to zero.
+
+Format types are defined as follows:
+
+@quotation
+@multitable {Value} {@code{DATETIME}}
+@headitem Value
+@tab Meaning
+@item 0
+@tab Not used.
+@item 1
+@tab @code{A}
+@item 2
+@tab @code{AHEX}
+@item 3
+@tab @code{COMMA}
+@item 4
+@tab @code{DOLLAR}
+@item 5
+@tab @code{F}
+@item 6
+@tab @code{IB}
+@item 7
+@tab @code{PIBHEX}
+@item 8
+@tab @code{P}
+@item 9
+@tab @code{PIB}
+@item 10
+@tab @code{PK}
+@item 11
+@tab @code{RB}
+@item 12
+@tab @code{RBHEX}
+@item 13
+@tab Not used.
+@item 14
+@tab Not used.
+@item 15
+@tab @code{Z}
+@item 16
+@tab @code{N}
+@item 17
+@tab @code{E}
+@item 18
+@tab Not used.
+@item 19
+@tab Not used.
+@item 20
+@tab @code{DATE}
+@item 21
+@tab @code{TIME}
+@item 22
+@tab @code{DATETIME}
+@item 23
+@tab @code{ADATE}
+@item 24
+@tab @code{JDATE}
+@item 25
+@tab @code{DTIME}
+@item 26
+@tab @code{WKDAY}
+@item 27
+@tab @code{MONTH}
+@item 28
+@tab @code{MOYR}
+@item 29
+@tab @code{QYR}
+@item 30
+@tab @code{WKYR}
+@item 31
+@tab @code{PCT}
+@item 32
+@tab @code{DOT}
+@item 33
+@tab @code{CCA}
+@item 34
+@tab @code{CCB}
+@item 35
+@tab @code{CCC}
+@item 36
+@tab @code{CCD}
+@item 37
+@tab @code{CCE}
+@item 38
+@tab @code{EDATE}
+@item 39
+@tab @code{SDATE}
+@end multitable
+@end quotation
+
+@node Value Labels Records
+@section Value Labels Records
+
+The value label record has the following format:
+
+@example
+int32               rec_type;
+int32               label_count;
+
+/* @r{Repeated @code{label_cnt} times}. */
+char                value[8];
+char                label_len;
+char                label[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 3.
+
+@item int32 label_count;
+Number of value labels present in this record.
+@end table
+
+The remaining fields are repeated @code{count} times.  Each
+repetition specifies one value label.
+
+@table @code
+@item char value[8];
+A numeric value or a short string value padded as necessary to 8 bytes
+in length.  Its type and width cannot be determined until the
+following value label variables record (see below) is read.
+
+@item char label_len;
+The label's length, in bytes.
+
+@item char label[];
+@code{label_len} bytes of the actual label, followed by up to 7 bytes
+of padding to bring @code{label} and @code{label_len} together to a
+multiple of 8 bytes in length.
+@end table
+
+The value label record is always immediately followed by a value label
+variables record with the following format:
+
+@example
+int32               rec_type;
+int32               var_count;
+int32               vars[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 4.
+
+@item int32 var_count;
+Number of variables that the associated value labels from the value
+label record are to be applied.
+
+@item int32 vars[];
+A list of dictionary indexes of variables to which to apply the value
+labels (@pxref{Dictionary Index}).  There are @code{var_count}
+elements.
+
+String variables wider than 8 bytes may not have value labels.
+@end table
+
+@node Document Record
+@section Document Record
+
+The document record, if present, has the following format:
+
+@example
+int32               rec_type;
+int32               n_lines;
+char                lines[][80];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 6.
+
+@item int32 n_lines;
+Number of lines of documents present.
+
+@item char lines[][80];
+Document lines.  The number of elements is defined by @code{n_lines}.
+Lines shorter than 80 characters are padded on the right with spaces.
+@end table
+
+@node Machine Integer Info Record
+@section Machine Integer Info Record
+
+The integer info record, if present, has the following format:
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Data.} */
+int32               version_major;
+int32               version_minor;
+int32               version_revision;
+int32               machine_code;
+int32               floating_point_rep;
+int32               compression_code;
+int32               endianness;
+int32               character_code;
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 3.
+
+@item int32 size;
+Size of each piece of data in the data part, in bytes.  Always set to 4.
+
+@item int32 count;
+Number of pieces of data in the data part.  Always set to 8.
+
+@item int32 version_major;
+PSPP major version number.  In version @var{x}.@var{y}.@var{z}, this
+is @var{x}.
+
+@item int32 version_minor;
+PSPP minor version number.  In version @var{x}.@var{y}.@var{z}, this
+is @var{y}.
+
+@item int32 version_revision;
+PSPP version revision number.  In version @var{x}.@var{y}.@var{z},
+this is @var{z}.
+
+@item int32 machine_code;
+Machine code.  PSPP always set this field to value to -1, but other
+values may appear.
+
+@item int32 floating_point_rep;
+Floating point representation code.  For IEEE 754 systems this is 1.
+IBM 370 sets this to 2, and DEC VAX E to 3.
+
+@item int32 compression_code;
+Compression code.  Always set to 1.
+
+@item int32 endianness;
+Machine endianness.  1 indicates big-endian, 2 indicates little-endian.
+
+@item int32 character_code;
+Character code.  1 indicates EBCDIC, 2 indicates 7-bit ASCII, 3
+indicates 8-bit ASCII, 4 indicates DEC Kanji.
+Windows code page numbers are also valid.
+@end table
+
+@node Machine Floating-Point Info Record
+@section Machine Floating-Point Info Record
+
+The floating-point info record, if present, has the following format:
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Data.} */
+flt64               sysmis;
+flt64               highest;
+flt64               lowest;
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 4.
+
+@item int32 size;
+Size of each piece of data in the data part, in bytes.  Always set to 8.
+
+@item int32 count;
+Number of pieces of data in the data part.  Always set to 3.
+
+@item flt64 sysmis;
+The system missing value.
+
+@item flt64 highest;
+The value used for HIGHEST in missing values.
+
+@item flt64 lowest;
+The value used for LOWEST in missing values.
+@end table
+
+@node Variable Display Parameter Record
+@section Variable Display Parameter Record
+
+The variable display parameter record, if present, has the following
+format:
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Repeated @code{count} times}. */
+int32               measure;
+int32               width;
+int32               alignment;
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 11.
+
+@item int32 size;
+The size of @code{int32}.  Always set to 4.
+
+@item int32 count;
+The number of sets of variable display parameters (ordinarily the
+number of variables in the dictionary), times 3.
+@end table
+
+The remaining members are repeated @code{count} times, in the same
+order as the variable records.  No element corresponds to variable
+records that continue long string variables.  The meanings of these
+members are as follows:
+
+@table @code
+@item int32 measure;
+The measurement type of the variable:
+@table @asis
+@item 1
+Nominal Scale
+@item 2
+Ordinal Scale
+@item 3
+Continuous Scale
+@end table
+
+SPSS 14 sometimes writes a @code{measure} of 0.  PSPP interprets this
+as nominal scale.
+
+@item int32 width;
+The width of the display column for the variable in characters.
+
+@item int32 alignment;
+The alignment of the variable for display purposes:
+
+@table @asis
+@item 0
+Left aligned
+@item 1
+Right aligned
+@item 2
+Centre aligned
+@end table
+@end table
+
+@node Long Variable Names Record
+@section Long Variable Names Record
+
+If present, the long variable names record has the following format:
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Exactly @code{count} bytes of data.} */
+char                var_name_pairs[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 13.
+
+@item int32 size;
+The size of each element in the @code{var_name_pairs} member. Always set to 1.
+
+@item int32 count;
+The total number of bytes in @code{var_name_pairs}.
+
+@item char var_name_pairs[];
+A list of @var{key}--@var{value} tuples, where @var{key} is the name
+of a variable, and @var{value} is its long variable name.
+The @var{key} field is at most 8 bytes long and must match the
+name of a variable which appears in the variable record (@pxref{Variable
+Record}).
+The @var{value} field is at most 64 bytes long.
+The @var{key} and @var{value} fields are separated by a @samp{=} byte.
+Each tuple is separated by a byte whose value is 09.  There is no
+trailing separator following the last tuple.
+The total length is @code{count} bytes.
+@end table
+
+@node Very Long String Record
+@section Very Long String Record
+
+Old versions of SPSS limited string variables to a width of 255 bytes.
+For backward compatibility with these older versions, the system file
+format represents a string longer than 255 bytes, called a @dfn{very
+long string}, as a collection of strings no longer than 255 bytes
+each.  The strings concatenated to make a very long string are called
+its @dfn{segments}; for consistency, variables other than very long
+strings are considered to have a single segment.
+
+A very long string with a width of @var{w} has @var{n} =
+(@var{w} + 251) / 252 segments, that is, one segment for every
+252 bytes of width, rounding up.  It would be logical, then, for each
+of the segments except the last to have a width of 252 and the last
+segment to have the remainder, but this is not the case.  In fact,
+each segment except the last has a width of 255 bytes.  The last
+segment has width @var{w} - (@var{n} - 1) * 252; some versions
+of SPSS make it slightly wider, but not wide enough to make the last
+segment require another 8 bytes of data.
+
+Data is packed tightly into segments of a very long string, 255 bytes
+per segment.  Because 255 bytes of segment data are allocated for
+every 252 bytes of the very long string's width (approximately), some
+unused space is left over at the end of the allocated segments.  Data
+in unused space is ignored.
+
+Example: Consider a very long string of width 20,000.  Such a very
+long string has 20,000 / 252 = 80 (rounding up) segments.  The first
+79 segments have width 255; the last segment has width 20,000 - 79 *
+252 = 92 or slightly wider (up to 96 bytes, the next multiple of 8).
+The very long string's data is actually stored in the 19,890 bytes in
+the first 78 segments, plus the first 110 bytes of the 79th segment
+(19,890 + 110 = 20,000).  The remaining 145 bytes of the 79th segment
+and all 92 bytes of the 80th segment are unused.
+
+The very long string record explains how to stitch together segments
+to obtain very long string data.  For each of the very long string
+variables in the dictionary, it specifies the name of its first
+segment's variable and the very long string variable's actual width.
+The remaining segments immediately follow the named variable in the
+system file's dictionary.
+
+The very long string record, which is present only if the system file
+contains very long string variables, has the following format:
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Exactly @code{count} bytes of data.} */
+char                string_lengths[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 14.
+
+@item int32 size;
+The size of each element in the @code{string_lengths} member. Always set to 1.
+
+@item int32 count;
+The total number of bytes in @code{string_lengths}.
+
+@item char string_lengths[];
+A list of @var{key}--@var{value} tuples, where @var{key} is the name
+of a variable, and @var{value} is its length.
+The @var{key} field is at most 8 bytes long and must match the
+name of a variable which appears in the variable record (@pxref{Variable
+Record}).
+The @var{value} field is exactly 5 bytes long. It is a zero-padded,
+ASCII-encoded string that is the length of the variable.
+The @var{key} and @var{value} fields are separated by a @samp{=} byte.
+Tuples are delimited by a two-byte sequence @{00, 09@}.
+After the last tuple, there may be a single byte 00, or @{00, 09@}.
+The total length is @code{count} bytes.
+@end table
+
+@node Miscellaneous Informational Records
+@section Miscellaneous Informational Records
+
+Some specific types of miscellaneous informational records are
+documented here, but others are known to exist.  PSPP ignores unknown
+miscellaneous informational records when reading system files.
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Exactly @code{size * count} bytes of data.} */
+char                data[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  May take any value.  According to Aapi
+H@"am@"al@"ainen, value 5 indicates a set of grouped variables and 6
+indicates date info (probably related to USE).
+
+@item int32 size;
+Size of each piece of data in the data part.  Should have the value 1,
+4, or 8, for @code{char}, @code{int32}, and @code{flt64} format data,
+respectively.
+
+@item int32 count;
+Number of pieces of data in the data part.
+
+@item char data[];
+Arbitrary data.  There must be @code{size} times @code{count} bytes of
+data.
+@end table
+
+@node Dictionary Termination Record
+@section Dictionary Termination Record
+
+The dictionary termination record separates all other records from the
+data records.
+
+@example
+int32               rec_type;
+int32               filler;
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 999.
+
+@item int32 filler;
+Ignored padding.  Should be set to 0.
+@end table
+
+@node Data Record
+@section Data Record
+
+Data records must follow all other records in the system file.  There must
+be at least one data record in every system file.
+
+The format of data records varies depending on whether the data is
+compressed.  Regardless, the data is arranged in a series of 8-byte
+elements.
+
+When data is not compressed,
+each element corresponds to
+the variable declared in the respective variable record (@pxref{Variable
+Record}).  Numeric values are given in @code{flt64} format; string
+values are literal characters string, padded on the right when
+necessary to fill out 8-byte units.
+
+Compressed data is arranged in the following manner: the first 8 bytes
+in the data section is divided into a series of 1-byte command
+codes.  These codes have meanings as described below:
+
+@table @asis
+@item 0
+Ignored.  If the program writing the system file accumulates compressed
+data in blocks of fixed length, 0 bytes can be used to pad out extra
+bytes remaining at the end of a fixed-size block.
+
+@item 1 through 251
+A number with
+value @var{code} - @var{bias}, where
+@var{code} is the value of the compression code and @var{bias} is the
+variable @code{bias} from the file header.  For example,
+code 105 with bias 100.0 (the normal value) indicates a numeric variable
+of value 5.
+
+@item 252
+End of file.  This code may or may not appear at the end of the data
+stream.  PSPP always outputs this code but its use is not required.
+
+@item 253
+A numeric or string value that is not
+compressible.  The value is stored in the 8 bytes following the
+current block of command bytes.  If this value appears twice in a block
+of command bytes, then it indicates the second group of 8 bytes following the
+command bytes, and so on.
+
+@item 254
+An 8-byte string value that is all spaces.
+
+@item 255
+The system-missing value.
+@end table
+
+When the end of the an 8-byte group of command bytes is reached, any
+blocks of non-compressible values indicated by code 253 are skipped,
+and the next element of command bytes is read and interpreted, until
+the end of the file or a code with value 252 is reached.
+@setfilename ignored
index 5706068764f485b3645e78b24cb4a3ddcb4dcd2f..0dd77d499803e456e82093145d825dfe804e0ad0 100644 (file)
@@ -7,6 +7,6 @@ implemented.
 @cindex unimplemented commands
 @cindex commands, unimplemented
 
-@include ni.texi
+@include doc/ni.texi
 
 @setfilename ignored
diff --git a/doc/portable-file-format.texi b/doc/portable-file-format.texi
deleted file mode 100644 (file)
index d58a987..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-@node Portable File Format
-@appendix Portable File Format
-
-These days, most computers use the same internal data formats for
-integer and floating-point data, if one ignores little differences like
-big- versus little-endian byte ordering.  However, occasionally it is
-necessary to exchange data between systems with incompatible data
-formats.  This is what portable files are designed to do.
-
-@strong{Please note:} Although all of the following information is
-correct, as far as the author has been able to ascertain, it is gleaned
-from examination of ASCII-formatted portable files only, so some of it
-may be incorrect in the general case.
-
-@menu
-* Portable File Characters::    
-* Portable File Structure::     
-* Portable File Header::        
-* Version and Date Info Record::  
-* Identification Records::      
-* Variable Count Record::       
-* Case Weight Variable Record::  
-* Variable Records::            
-* Value Label Records::         
-* Portable File Document Record::
-* Portable File Data::          
-@end menu
-
-@node Portable File Characters
-@section Portable File Characters
-
-Portable files are arranged as a series of lines of 80
-characters each.  Each line is terminated by a carriage-return,
-line-feed sequence (``new-lines'').  New-lines are only used to avoid
-line length limits imposed by some OSes; they are not meaningful.
-
-Most lines in portable files are exactly 80 characters long.  The only
-exception is a line that ends in one or more spaces, in which the
-spaces may optionally be omitted.  Thus, a portable file reader must
-act as though a line shorter than 80 characters is padded to that
-length with spaces.
-
-The file must be terminated with a @samp{Z} character.  In addition, if
-the final line in the file does not have exactly 80 characters, then it
-is padded on the right with @samp{Z} characters.  (The file contents may
-be in any character set; the file contains a description of its own
-character set, as explained in the next section.  Therefore, the
-@samp{Z} character is not necessarily an ASCII @samp{Z}.)
-
-For the rest of the description of the portable file format, new-lines
-and the trailing @samp{Z}s will be ignored, as if they did not exist,
-because they are not an important part of understanding the file
-contents.
-
-@node Portable File Structure
-@section Portable File Structure
-
-Every portable file consists of the following records, in sequence:
-
-@itemize @bullet
-
-@item
-File header.
-
-@item
-Version and date info.
-
-@item
-Product identification.
-
-@item
-Author identification (optional).
-
-@item
-Subproduct identification (optional).
-
-@item
-Variable count.
-
-@item
-Case weight variable (optional).
-
-@item
-Variables.  Each variable record may optionally be followed by a
-missing value record and a variable label record.
-
-@item
-Value labels (optional).
-
-@item
-Documents (optional).
-
-@item
-Data.
-@end itemize
-
-Most records are identified by a single-character tag code.  The file
-header and version info record do not have a tag.
-
-Other than these single-character codes, there are three types of fields
-in a portable file: floating-point, integer, and string.  Floating-point
-fields have the following format:
-
-@itemize @bullet
-
-@item
-Zero or more leading spaces.
-
-@item
-Optional asterisk (@samp{*}), which indicates a missing value.  The
-asterisk must be followed by a single character, generally a period
-(@samp{.}), but it appears that other characters may also be possible.
-This completes the specification of a missing value.
-
-@item
-Optional minus sign (@samp{-}) to indicate a negative number.
-
-@item
-A whole number, consisting of one or more base-30 digits: @samp{0}
-through @samp{9} plus capital letters @samp{A} through @samp{T}.
-
-@item
-Optional fraction, consisting of a radix point (@samp{.}) followed by
-one or more base-30 digits.
-
-@item
-Optional exponent, consisting of a plus or minus sign (@samp{+} or
-@samp{-}) followed by one or more base-30 digits.
-
-@item
-A forward slash (@samp{/}).
-@end itemize
-
-Integer fields take a form identical to floating-point fields, but they
-may not contain a fraction.
-
-String fields take the form of a integer field having value @var{n},
-followed by exactly @var{n} characters, which are the string content.
-
-@node Portable File Header
-@section Portable File Header
-
-Every portable file begins with a 464-byte header, consisting of a
-200-byte collection of vanity splash strings, followed by a 256-byte
-character set translation table, followed by an 8-byte tag string.
-
-The 200-byte segment is divided into five 40-byte sections, each of
-which represents the string @code{@var{charset} SPSS PORT FILE} in a
-different character set encoding, where @var{charset} is the name of
-the character set used in the file, e.g.@: @code{ASCII} or
-@code{EBCDIC}.  Each string is padded on the right with spaces in its
-respective character set.
-
-It appears that these strings exist only to inform those who might view
-the file on a screen, and that they are not parsed by SPSS products.
-Thus, they can be safely ignored.  For those interested, the strings are
-supposed to be in the following character sets, in the specified order:
-EBCDIC, 7-bit ASCII, CDC 6-bit ASCII, 6-bit ASCII, Honeywell 6-bit
-ASCII.
-
-The 256-byte segment describes a mapping from the character set used in
-the portable file to an arbitrary character set having characters at the
-following positions:
-
-@table @asis
-@item 0--60
-
-Control characters.  Not important enough to describe in full here.
-
-@item 61--63
-
-Reserved.
-
-@item 64--73
-
-Digits @samp{0} through @samp{9}.
-
-@item 74--99
-
-Capital letters @samp{A} through @samp{Z}. 
-
-@item 100--125
-
-Lowercase letters @samp{a} through @samp{z}.
-
-@item 126
-
-Space.
-
-@item 127--130
-
-Symbols @code{.<(+}
-
-@item 131
-
-Solid vertical pipe.
-
-@item 132--142
-
-Symbols @code{&[]!$*);^-/}
-
-@item 143
-
-Broken vertical pipe.
-
-@item 144--150
-
-Symbols @code{,%_>}?@code{`:}   @c @code{?} is an inverted question mark
-
-@item 151
-
-British pound symbol.
-
-@item 152--155
-
-Symbols @code{@@'="}.
-
-@item 156
-
-Less than or equal symbol.
-
-@item 157
-
-Empty box.
-
-@item 158
-
-Plus or minus.
-
-@item 159
-
-Filled box.
-
-@item 160
-
-Degree symbol.
-
-@item 161
-
-Dagger.
-
-@item 162
-
-Symbol @samp{~}.
-
-@item 163
-
-En dash.
-
-@item 164
-
-Lower left corner box draw.
-
-@item 165
-
-Upper left corner box draw.
-
-@item 166
-
-Greater than or equal symbol.
-
-@item 167--176
-
-Superscript @samp{0} through @samp{9}.
-
-@item 177
-
-Lower right corner box draw.
-
-@item 178
-
-Upper right corner box draw.
-
-@item 179
-
-Not equal symbol.
-
-@item 180
-
-Em dash.
-
-@item 181
-
-Superscript @samp{(}.
-
-@item 182
-
-Superscript @samp{)}.
-
-@item 183
-
-Horizontal dagger (?).
-
-@item 184--186
-
-Symbols @samp{@{@}\}.
-@item 187
-
-Cents symbol.
-
-@item 188
-
-Centered dot, or bullet.
-
-@item 189--255
-
-Reserved.
-@end table
-
-Symbols that are not defined in a particular character set are set to
-the same value as symbol 64; i.e., to @samp{0}.
-
-The 8-byte tag string consists of the exact characters @code{SPSSPORT}
-in the portable file's character set, which can be used to verify that
-the file is indeed a portable file.
-
-@node Version and Date Info Record
-@section Version and Date Info Record
-
-This record does not have a tag code.  It has the following structure:
-
-@itemize @bullet
-@item
-A single character identifying the file format version.  The letter A
-represents version 0, and so on.
-
-@item
-An 8-character string field giving the file creation date in the format
-YYYYMMDD.
-
-@item
-A 6-character string field giving the file creation time in the format
-HHMMSS.
-@end itemize
-
-@node Identification Records
-@section Identification Records
-
-The product identification record has tag code @samp{1}.  It consists of
-a single string field giving the name of the product that wrote the
-portable file.
-
-The author identification record has tag code @samp{2}.  It is
-optional.  If present, it consists of a single string field giving the
-name of the person who caused the portable file to be written.
-
-The subproduct identification record has tag code @samp{3}.  It is
-optional.  If present, it consists of a single string field giving
-additional information on the product that wrote the portable file.
-
-@node Variable Count Record
-@section Variable Count Record
-
-The variable count record has tag code @samp{4}.  It consists of two
-integer fields.  The first contains the number of variables in the file
-dictionary.  The purpose of the second is unknown; it contains the value
-161 in all portable files examined so far.
-
-@node Case Weight Variable Record
-@section Case Weight Variable Record
-
-The case weight variable record is optional.  If it is present, it
-indicates the variable used for weighting cases; if it is absent,
-cases are unweighted.  It has tag code @samp{6}.  It consists of a
-single string field that names the weighting variable.
-
-@node Variable Records
-@section Variable Records
-
-Each variable record represents a single variable.  Variable records
-have tag code @samp{7}.  They have the following structure:
-
-@itemize @bullet
-
-@item
-Width (integer).  This is 0 for a numeric variable, and a number between 1
-and 255 for a string variable.
-
-@item
-Name (string).  1--8 characters long.  Must be in all capitals.
-
-A few portable files that contain duplicate variable names have been
-spotted in the wild.  PSPP handles these by renaming the duplicates
-with numeric extensions: @code{@var{var}_1}, @code{@var{var}_2}, and
-so on.
-
-@item
-Print format.  This is a set of three integer fields:
-
-@itemize @minus
-
-@item
-Format type (@pxref{Variable Record}).
-
-@item
-Format width.  1--40.
-
-@item
-Number of decimal places.  1--40.
-@end itemize
-
-A few portable files with invalid format types or formats that are not
-of the appropriate width for their variables have been spotted in the
-wild.  PSPP assigns a default F or A format to a variable with an
-invalid format.
-
-@item
-Write format.  Same structure as the print format described above.
-@end itemize
-
-Each variable record can optionally be followed by a missing value
-record, which has tag code @samp{8}.  A missing value record has one
-field, the missing value itself (a floating-point or string, as
-appropriate).  Up to three of these missing value records can be used.
-
-There is also a record for missing value ranges, which has tag code
-@samp{B}.  It is followed by two fields representing the range, which
-are floating-point or string as appropriate.  If a missing value range
-is present, it may be followed by a single missing value record.
-
-Tag codes @samp{9} and @samp{A} represent @code{LO THRU @var{x}} and
-@code{@var{x} THRU HI} ranges, respectively.  Each is followed by a
-single field representing @var{x}.  If one of the ranges is present, it
-may be followed by a single missing value record.
-
-In addition, each variable record can optionally be followed by a
-variable label record, which has tag code @samp{C}.  A variable label
-record has one field, the variable label itself (string).
-
-@node Value Label Records
-@section Value Label Records
-
-Value label records have tag code @samp{D}.  They have the following
-format:
-
-@itemize @bullet
-@item
-Variable count (integer).
-
-@item
-List of variables (strings).  The variable count specifies the number in
-the list.  Variables are specified by their names.  All variables must
-be of the same type (numeric or string), but string variables do not
-necessarily have the same width.
-
-@item
-Label count (integer).
-
-@item
-List of (value, label) tuples.  The label count specifies the number of
-tuples.  Each tuple consists of a value, which is numeric or string as
-appropriate to the variables, followed by a label (string).
-@end itemize
-
-A few portable files that specify duplicate value labels, that is, two
-different labels for a single value of a single variable, have been
-spotted in the wild.  PSPP uses the last value label specified in
-these cases.
-
-@node Portable File Document Record
-@section Document Record
-
-One document record may optionally follow the value label record.  The
-document record consists of tag code @samp{E}, following by the number
-of document lines as an integer, followed by that number of strings,
-each of which represents one document line.  Document lines must be 80
-bytes long or shorter.
-
-@node Portable File Data
-@section Portable File Data
-
-The data record has tag code @samp{F}.  There is only one tag for all
-the data; thus, all the data must follow the dictionary.  The data is
-terminated by the end-of-file marker @samp{Z}, which is not valid as the
-beginning of a data element.
-
-Data elements are output in the same order as the variable records
-describing them.  String variables are output as string fields, and
-numeric variables are output as floating-point fields.
-@setfilename ignored
diff --git a/doc/pspp-dev.texinfo b/doc/pspp-dev.texinfo
new file mode 100644 (file)
index 0000000..991b04b
--- /dev/null
@@ -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
+
+@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 Developers 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 PSPP Developers Guide
+@subtitle GNU PSPP Statistical Analysis Software
+@subtitle Release @value{VERSION}
+@author
+@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.
+* 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
+
+@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 dev/portable-file-format.texi
+@include dev/system-file-format.texi
+@include dev/q2c.texi
+
+@include fdl.texi
+
+@bye
+
+@c Local Variables:
+@c compile-command: "makeinfo pspp-dev.texinfo"
+@c End:
index 9698cc588bc7b342fee2868ed0f5203251a3d306..b0759dd4c1ef095f43395c3145eb7976b20baa56 100644 (file)
@@ -43,9 +43,10 @@ Software Foundation raise funds for GNU development.''
 @end copying
 
 @titlepage
-@title GNU PSPP
-@subtitle A System for Statistical Analysis
-@subtitle Edition @value{EDITION}, for PSPP version @value{VERSION}
+@title PSPP Users Guide
+@subtitle GNU PSPP Statistical Analysis Software
+@subtitle Release @value{VERSION}
+@author
 @page
 @vskip 0pt plus 1filll
 @insertcopying
@@ -87,10 +88,6 @@ Software Foundation raise funds for GNU development.''
 
 * 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 +114,6 @@ Software Foundation raise funds for GNU development.''
 
 @include configuring.texi
 
-@include portable-file-format.texi
-@include data-file-format.texi
-@include q2c.texi
-
 @include fdl.texi
 
 @bye
diff --git a/doc/q2c.texi b/doc/q2c.texi
deleted file mode 100644 (file)
index fb61173..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-@node q2c Input Format
-@appendix @code{q2c} Input Format
-
-PSPP statistical procedures have a bizarre and somewhat irregular
-syntax.  Despite this, a parser generator has been written that
-adequately addresses many of the possibilities and tries to provide
-hooks for the exceptional cases.  This parser generator is named
-@code{q2c}.
-
-@menu
-* Invoking q2c::                q2c command-line syntax.
-* q2c Input Structure::         High-level layout of the input file.
-* Grammar Rules::               Syntax of the grammar rules.
-@end menu
-
-@node Invoking q2c
-@section Invoking q2c
-
-@example
-q2c @var{input.q} @var{output.c}
-@end example
-
-@code{q2c} translates a @samp{.q} file into a @samp{.c} file.  It takes
-exactly two command-line arguments, which are the input file name and
-output file name, respectively.  @code{q2c} does not accept any
-command-line options.
-
-@node q2c Input Structure
-@section @code{q2c} Input Structure
-
-@code{q2c} input files are divided into two sections: the grammar rules
-and the supporting code.  The @dfn{grammar rules}, which make up the
-first part of the input, are used to define the syntax of the
-statistical procedure to be parsed.  The @dfn{supporting code},
-following the grammar rules, are copied largely unchanged to the output
-file, except for certain escapes.
-
-The most important lines in the grammar rules are used for defining
-procedure syntax.  These lines can be prefixed with a dollar sign
-(@samp{$}), which prevents Emacs' CC-mode from munging them.  Besides
-this, a bang (@samp{!}) at the beginning of a line causes the line,
-minus the bang, to be written verbatim to the output file (useful for
-comments).  As a third special case, any line that begins with the exact
-characters @code{/* *INDENT} is ignored and not written to the output.
-This allows @code{.q} files to be processed through @code{indent}
-without being munged.
-
-The syntax of the grammar rules themselves is given in the following
-sections.
-
-The supporting code is passed into the output file largely unchanged.
-However, the following escapes are supported.  Each escape must appear
-on a line by itself.
-
-@table @code
-@item /* (header) */
-
-Expands to a series of C @code{#include} directives which include the
-headers that are required for the parser generated by @code{q2c}.
-
-@item /* (decls @var{scope}) */
-
-Expands to C variable and data type declarations for the variables and
-@code{enum}s input and output by the @code{q2c} parser.  @var{scope}
-must be either @code{local} or @code{global}.  @code{local} causes the
-declarations to be output as function locals.  @code{global} causes them
-to be declared as @code{static} module variables; thus, @code{global} is
-a bit of a misnomer.
-
-@item /* (parser) */
-
-Expands to the entire parser.  Must be enclosed within a C function.
-
-@item /* (free) */
-
-Expands to a set of calls to the @code{free} function for variables
-declared by the parser.  Only needs to be invoked if subcommands of type
-@code{string} are used in the grammar rules.
-@end table
-
-@node Grammar Rules
-@section Grammar Rules
-
-The grammar rules describe the format of the syntax that the parser
-generated by @code{q2c} will understand.  The way that the grammar rules
-are included in @code{q2c} input file are described above.
-
-The grammar rules are divided into tokens of the following types:
-
-@table @asis
-@item Identifier (@code{ID})
-
-An identifier token is a sequence of letters, digits, and underscores
-(@samp{_}).  Identifiers are @emph{not} case-sensitive.
-
-@item String (@code{STRING})
-
-String tokens are initiated by a double-quote character (@samp{"}) and
-consist of all the characters between that double quote and the next
-double quote, which must be on the same line as the first.  Within a
-string, a backslash can be used as a ``literal escape''.  The only
-reasons to use a literal escape are to include a double quote or a
-backslash within a string.
-
-@item Special character
-
-Other characters, other than white space, constitute tokens in
-themselves.
-
-@end table
-
-The syntax of the grammar rules is as follows:
-
-@example
-grammar-rules ::= command-name opt-prefix : subcommands .
-command-name ::= ID
-             ::= STRING
-opt-prefix ::=
-           ::= ( ID )
-subcommands ::= subcommand
-            ::= subcommands ; subcommand
-@end example
-
-The syntax begins with an ID token that gives the name of the
-procedure to be parsed.  For command names that contain multiple
-words, a STRING token may be used instead, e.g.@: @samp{"FILE
-HANDLE"}.  Optionally, an ID in parentheses specifies a prefix used
-for all file-scope identifiers declared by the emitted code.
-
-The rest of the syntax consists of subcommands separated by semicolons
-(@samp{;}) and terminated with a full stop (@samp{.}).
-
-@example
-subcommand ::= default-opt arity-opt ID sbc-defn
-default-opt ::=
-            ::= *
-arity-opt ::=
-          ::= +
-          ::= ^
-sbc-defn ::= opt-prefix = specifiers
-         ::= [ ID ] = array-sbc
-         ::= opt-prefix = sbc-special-form
-@end example
-
-A subcommand that begins with an asterisk (@samp{*}) is the default
-subcommand.  The keyword used for the default subcommand can be omitted
-in the PSPP syntax file.
-
-A plus sign (@samp{+}) indicates that a subcommand can appear more than
-once.  A caret (@samp{^}) indicate that a subcommand must appear exactly
-once.  A subcommand marked with neither character may appear once or not
-at all, but not more than once.
-
-The subcommand name appears after the leading option characters.
-
-There are three forms of subcommands.  The first and most common form
-simply gives an equals sign (@samp{=}) and a list of specifiers, which
-can each be set to a single setting.  The second form declares an array,
-which is a set of flags that can be individually turned on by the user.
-There are also several special forms that do not take a list of
-specifiers.
-
-Arrays require an additional @code{ID} argument.  This is used as a
-prefix, prepended to the variable names constructed from the
-specifiers.  The other forms also allow an optional prefix to be
-specified.
-
-@example
-array-sbc ::= alternatives
-          ::= array-sbc , alternatives
-alternatives ::= ID
-             ::= alternatives | ID
-@end example
-
-An array subcommand is a set of Boolean values that can independently be
-turned on by the user, listed separated by commas (@samp{,}).  If an value has more
-than one name then these names are separated by pipes (@samp{|}).
-
-@example
-specifiers ::= specifier
-           ::= specifiers , specifier
-specifier ::= opt-id : settings
-opt-id ::=
-       ::= ID
-@end example
-
-Ordinary subcommands (other than arrays and special forms) require a
-list of specifiers.  Each specifier has an optional name and a list of
-settings.  If the name is given then a correspondingly named variable
-will be used to store the user's choice of setting.  If no name is given
-then there is no way to tell which setting the user picked; in this case
-the settings should probably have values attached.
-
-@example
-settings ::= setting
-         ::= settings / setting
-setting ::= setting-options ID setting-value
-setting-options ::=
-                ::= *
-                ::= !
-                ::= * !
-@end example
-
-Individual settings are separated by forward slashes (@samp{/}).  Each
-setting can be as little as an @code{ID} token, but options and values
-can optionally be included.  The @samp{*} option means that, for this
-setting, the @code{ID} can be omitted.  The @samp{!} option means that
-this option is the default for its specifier.
-
-@example
-setting-value ::=
-              ::= ( setting-value-2 )
-              ::= setting-value-2
-setting-value-2 ::= setting-value-options setting-value-type : ID 
-                    setting-value-restriction
-setting-value-options ::=
-                      ::= *
-setting-value-type ::= N
-                   ::= D
-                   ::= S
-setting-value-restriction ::= 
-                          ::= , STRING
-@end example
-
-Settings may have values.  If the value must be enclosed in parentheses,
-then enclose the value declaration in parentheses.  Declare the setting
-type as @samp{n}, @samp{d}, or @samp{s} for integer, floating-point,
-or string type, respectively.  The given @code{ID} is used to
-construct a variable name.
-If option @samp{*} is given, then the value is optional; otherwise it
-must be specified whenever the corresponding setting is specified.  A
-``restriction'' can also be specified which is a string giving a C
-expression limiting the valid range of the value.  The special escape
-@code{%s} should be used within the restriction to refer to the
-setting's value variable.
-
-@example
-sbc-special-form ::= VAR
-                 ::= VARLIST varlist-options
-                 ::= INTEGER opt-list
-                 ::= DOUBLE opt-list
-                 ::= PINT
-                 ::= STRING @r{(the literal word STRING)} string-options
-                 ::= CUSTOM
-varlist-options ::= 
-                ::= ( STRING )
-opt-list ::=
-         ::= LIST
-string-options ::= 
-               ::= ( STRING STRING )
-@end example
-
-The special forms are of the following types:
-
-@table @code
-@item VAR
-
-A single variable name.
-
-@item VARLIST
-
-A list of variables.  If given, the string can be used to provide
-@code{PV_@var{*}} options to the call to @code{parse_variables}. 
-
-@item INTEGER
-
-A single integer value.
-
-@item INTEGER LIST
-
-A list of integers separated by spaces or commas.
-
-@item DOUBLE
-
-A single floating-point value.
-
-@item DOUBLE LIST
-
-A list of floating-point values.
-
-@item PINT
-
-A single positive integer value.
-
-@item STRING
-
-A string value.  If the options are given then the first string is an
-expression giving a restriction on the value of the string; the second
-string is an error message to display when the restriction is violated.
-
-@item CUSTOM
-
-A custom function is used to parse this subcommand.  The function must
-have prototype @code{int custom_@var{name} (void)}.  It should return 0
-on failure (when it has already issued an appropriate diagnostic), 1 on
-success, or 2 if it fails and the calling function should issue a syntax
-error on behalf of the custom handler.
-
-@end table
-@setfilename ignored
index 94fa50744d6a4c70d48befce93b2b57438c1d658..314c435e37d1a1985202f4738ea5bf007815ad24 100644 (file)
@@ -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 46c6df8f6cac9037fdfe42aef55b0c2f83501bdb..a66e423292054adf60892eb059449e8db7dff2a1 100644 (file)
@@ -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 0e91bb1a81a845e6f76d014b063548e1ff80fa87..3c374e700ffdd2de9b09b46fcad9b6fdbf8e331c 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.4.3\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-11-08 09:15+0900\n"
+"POT-Creation-Date: 2007-11-10 20:49-0800\n"
 "PO-Revision-Date: 2006-07-28 19:32+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: German <pspp-dev@gnu.org>\n"
@@ -47,12 +47,6 @@ msgstr "Tag %d muß zwischen 0 bit 31 sein."
 msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
 msgstr ""
 
-#: src/data/casereader-filter.c:221
-msgid ""
-"At least one case in the data read had a weight value that was user-missing, "
-"system-missing, zero, or negative.  These case(s) were ignored."
-msgstr ""
-
 #: src/data/case-tmpfile.c:57
 msgid "failed to create temporary file"
 msgstr ""
@@ -73,157 +67,163 @@ msgstr "plotzlich ist der Datei beendet"
 msgid "writing to temporary file"
 msgstr ""
 
-#: src/data/data-in.c:267 src/data/data-in.c:457
+#: src/data/casereader-filter.c:221
+msgid ""
+"At least one case in the data read had a weight value that was user-missing, "
+"system-missing, zero, or negative.  These case(s) were ignored."
+msgstr ""
+
+#: src/data/data-in.c:287 src/data/data-in.c:477
 msgid "Field contents are not numeric."
 msgstr ""
 
-#: src/data/data-in.c:269 src/data/data-in.c:459
+#: src/data/data-in.c:289 src/data/data-in.c:479
 msgid "Number followed by garbage."
 msgstr ""
 
-#: src/data/data-in.c:280
+#: src/data/data-in.c:300
 msgid "Invalid numeric syntax."
 msgstr ""
 
-#: src/data/data-in.c:289 src/data/data-in.c:472
+#: src/data/data-in.c:309 src/data/data-in.c:492
 msgid "Too-large number set to system-missing."
 msgstr ""
 
-#: src/data/data-in.c:294 src/data/data-in.c:477
+#: src/data/data-in.c:314 src/data/data-in.c:497
 msgid "Too-small number set to zero."
 msgstr ""
 
-#: src/data/data-in.c:320
+#: src/data/data-in.c:340
 msgid "All characters in field must be digits."
 msgstr ""
 
-#: src/data/data-in.c:343
+#: src/data/data-in.c:363
 msgid "Unrecognized character in field."
 msgstr ""
 
-#: src/data/data-in.c:367 src/data/data-in.c:631
+#: src/data/data-in.c:387 src/data/data-in.c:660
 msgid "Field must have even length."
 msgstr ""
 
-#: src/data/data-in.c:372 src/data/data-in.c:637
+#: src/data/data-in.c:392 src/data/data-in.c:671
 msgid "Field must contain only hex digits."
 msgstr ""
 
-#: src/data/data-in.c:676 src/data/data-in.c:723
+#: src/data/data-in.c:710 src/data/data-in.c:757
 msgid "Syntax error in date field."
 msgstr ""
 
-#: src/data/data-in.c:692
+#: src/data/data-in.c:726
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr ""
 
-#: src/data/data-in.c:739
+#: src/data/data-in.c:773
 msgid "Delimiter expected between fields in date."
 msgstr ""
 
-#: src/data/data-in.c:813
+#: src/data/data-in.c:847
 msgid ""
 "Unrecognized month format.  Months may be specified as Arabic or Roman "
 "numerals or as at least 3 letters of their English names."
 msgstr ""
 
-#: src/data/data-in.c:840
+#: src/data/data-in.c:874
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr ""
 
-#: src/data/data-in.c:852
+#: src/data/data-in.c:886
 #, c-format
 msgid "Trailing garbage \"%.*s\" following date."
 msgstr ""
 
-#: src/data/data-in.c:868
+#: src/data/data-in.c:902
 msgid "Julian day must have exactly three digits."
 msgstr ""
 
-#: src/data/data-in.c:873
+#: src/data/data-in.c:907
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr ""
 
-#: src/data/data-in.c:897
+#: src/data/data-in.c:931
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr ""
 
-#: src/data/data-in.c:917
+#: src/data/data-in.c:951
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr ""
 
-#: src/data/data-in.c:930
+#: src/data/data-in.c:964
 msgid "Delimiter expected between fields in time."
 msgstr ""
 
-#: src/data/data-in.c:950
+#: src/data/data-in.c:984
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr ""
 
-#: src/data/data-in.c:990
+#: src/data/data-in.c:1024
 msgid ""
 "Unrecognized weekday name.  At least the first two letters of an English "
 "weekday name must be specified."
 msgstr ""
 
-#: src/data/data-in.c:1128
+#: src/data/data-in.c:1162
 #, c-format
 msgid "`%c' expected in date field."
 msgstr ""
 
-#: src/data/data-in.c:1169
+#: src/data/data-in.c:1203
 #, c-format
 msgid "column %d"
 msgstr "Spalten %d"
 
-#: src/data/data-in.c:1171
+#: src/data/data-in.c:1205
 #, fuzzy, c-format
 msgid "columns %d-%d"
 msgstr "Spalten"
 
-#: src/data/data-in.c:1175
+#: src/data/data-in.c:1209
 #, c-format
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:465
+#: src/data/data-out.c:476
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:486
+#: src/data/data-out.c:497
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
 
-#: src/data/dictionary.c:758
+#: src/data/dictionary.c:762
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1059
+#: src/data/dictionary.c:1060
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
 
-#: src/data/file-handle-def.c:452
+#: src/data/file-handle-def.c:462
 #, c-format
 msgid "Can't read from %s as a %s because it is already being read as a %s."
 msgstr ""
 
-#: src/data/file-handle-def.c:456
+#: src/data/file-handle-def.c:466
 #, c-format
 msgid "Can't write to %s as a %s because it is already being written as a %s."
 msgstr ""
 
-#: src/data/file-handle-def.c:463
+#: src/data/file-handle-def.c:473
 #, c-format
 msgid "Can't re-open %s as a %s."
 msgstr ""
@@ -305,33 +305,33 @@ msgstr[1] ""
 msgid "%s variables are not compatible with %s format %s."
 msgstr ""
 
-#: src/data/format.c:318 src/data/sys-file-reader.c:638
-#: src/ui/gui/data-editor.glade:1285 src/ui/gui/psppire.glade:2176
-#: src/ui/gui/psppire-var-store.c:493
+#: src/data/format.c:318 src/data/sys-file-reader.c:639
+#: src/ui/gui/data-editor.glade:1285 src/ui/gui/psppire-var-store.c:493
+#: src/ui/gui/psppire.glade:2176
 msgid "String"
 msgstr "Zeichenkette"
 
-#: src/data/format.c:318 src/data/sys-file-reader.c:638
-#: src/ui/gui/data-editor.glade:1174 src/ui/gui/psppire.glade:2131
-#: src/ui/gui/psppire-var-store.c:486
+#: src/data/format.c:318 src/data/sys-file-reader.c:639
+#: src/ui/gui/data-editor.glade:1174 src/ui/gui/psppire-var-store.c:486
+#: src/ui/gui/psppire.glade:2131
 msgid "Numeric"
 msgstr "Nummer"
 
-#: src/data/format.c:319 src/data/sys-file-reader.c:1113
-#: src/data/sys-file-reader.c:1115
+#: src/data/format.c:319 src/data/sys-file-reader.c:1114
+#: src/data/sys-file-reader.c:1116
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:471 src/language/xforms/recode.c:472
-#: src/language/xforms/recode.c:484 src/language/xforms/recode.c:485
+#: src/language/xforms/recode.c:472 src/language/xforms/recode.c:473
+#: src/language/xforms/recode.c:485 src/language/xforms/recode.c:486
 msgid "numeric"
 msgstr "numerisch"
 
-#: src/data/format.c:319 src/data/sys-file-reader.c:1113
-#: src/data/sys-file-reader.c:1115
+#: src/data/format.c:319 src/data/sys-file-reader.c:1114
+#: src/data/sys-file-reader.c:1116
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:471 src/language/xforms/recode.c:472
-#: src/language/xforms/recode.c:484 src/language/xforms/recode.c:485
+#: src/language/xforms/recode.c:472 src/language/xforms/recode.c:473
+#: src/language/xforms/recode.c:485 src/language/xforms/recode.c:486
 msgid "string"
 msgstr "kette"
 
@@ -405,150 +405,150 @@ msgstr ""
 msgid "Removing %s: %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:98
+#: src/data/por-file-reader.c:99
 #, c-format
 msgid "portable file %s corrupt at offset 0x%lx: "
 msgstr ""
 
-#: src/data/por-file-reader.c:127
+#: src/data/por-file-reader.c:128
 #, c-format
 msgid "reading portable file %s at offset 0x%lx: "
 msgstr ""
 
-#: src/data/por-file-reader.c:155
+#: src/data/por-file-reader.c:156
 #, c-format
 msgid "Error closing portable file \"%s\": %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:207
+#: src/data/por-file-reader.c:208
 msgid "unexpected end of file"
 msgstr "plotzlich ist der Datei beendet"
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:148
+#: src/data/por-file-reader.c:268 src/data/por-file-writer.c:148
 #, fuzzy
 msgid "portable file"
 msgstr "Tragbardatein (*.por)"
 
-#: src/data/por-file-reader.c:275
+#: src/data/por-file-reader.c:276
 #, c-format
 msgid ""
 "An error occurred while opening \"%s\" for reading as a portable file: %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:296
+#: src/data/por-file-reader.c:297
 msgid "Data record expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:378
+#: src/data/por-file-reader.c:379
 msgid "Number expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:406
+#: src/data/por-file-reader.c:407
 msgid "Missing numeric terminator."
 msgstr ""
 
-#: src/data/por-file-reader.c:429
+#: src/data/por-file-reader.c:430
 msgid "Invalid integer."
 msgstr ""
 
-#: src/data/por-file-reader.c:440
+#: src/data/por-file-reader.c:441
 #, c-format
 msgid "Bad string length %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:501
+#: src/data/por-file-reader.c:502
 #, c-format
 msgid "%s: Not a portable file."
 msgstr ""
 
-#: src/data/por-file-reader.c:517
+#: src/data/por-file-reader.c:518
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr ""
 
-#: src/data/por-file-reader.c:526
+#: src/data/por-file-reader.c:527
 #, c-format
 msgid "Bad date string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:528
+#: src/data/por-file-reader.c:529
 #, c-format
 msgid "Bad time string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:570
+#: src/data/por-file-reader.c:571
 #, c-format
 msgid ""
 "%s: Bad format specifier byte (%d).  Variable will be assigned a default "
 "format."
 msgstr ""
 
-#: src/data/por-file-reader.c:591
+#: src/data/por-file-reader.c:592
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:595
+#: src/data/por-file-reader.c:596
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:619
+#: src/data/por-file-reader.c:620
 msgid "Expected variable count record."
 msgstr ""
 
-#: src/data/por-file-reader.c:623
+#: src/data/por-file-reader.c:624
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:633
+#: src/data/por-file-reader.c:634
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr ""
 
-#: src/data/por-file-reader.c:648
+#: src/data/por-file-reader.c:649
 msgid "Expected variable record."
 msgstr ""
 
-#: src/data/por-file-reader.c:652
+#: src/data/por-file-reader.c:653
 #, c-format
 msgid "Invalid variable width %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:660
+#: src/data/por-file-reader.c:661
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:664
+#: src/data/por-file-reader.c:665
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:679
+#: src/data/por-file-reader.c:680
 #, c-format
 msgid "Duplicate variable name %s in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:680
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:723
+#: src/data/por-file-reader.c:724
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr ""
 
-#: src/data/por-file-reader.c:770
+#: src/data/por-file-reader.c:771
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr ""
 
-#: src/data/por-file-reader.c:773
+#: src/data/por-file-reader.c:774
 #, c-format
 msgid ""
 "Cannot assign value labels to %s and %s, which have different variable types."
@@ -578,7 +578,7 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:151
+#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:180
 msgid "scratch file"
 msgstr ""
 
@@ -588,299 +588,299 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:197 src/data/sys-file-writer.c:190
+#: src/data/sys-file-reader.c:198 src/data/sys-file-writer.c:190
 #, fuzzy
 msgid "system file"
 msgstr "Systemedatein (*.sav)"
 
-#: src/data/sys-file-reader.c:204
+#: src/data/sys-file-reader.c:205
 #, c-format
 msgid "Error opening \"%s\" for reading as a system file: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:243
+#: src/data/sys-file-reader.c:244
 msgid "Misplaced type 4 record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:254
+#: src/data/sys-file-reader.c:255
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:293
+#: src/data/sys-file-reader.c:294
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:333
+#: src/data/sys-file-reader.c:334
 #, c-format
 msgid "Error closing system file \"%s\": %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:398 src/data/sys-file-reader.c:408
+#: src/data/sys-file-reader.c:399 src/data/sys-file-reader.c:409
 #, fuzzy
 msgid "This is not an SPSS system file."
 msgstr "\"%s\" ist kein Systemdatei und kein Tragbardatei."
 
-#: src/data/sys-file-reader.c:427
+#: src/data/sys-file-reader.c:428
 #, c-format
 msgid ""
 "Compression bias (%g) is not the usual value of 100, or system file uses "
 "unrecognized floating-point format."
 msgstr ""
 
-#: src/data/sys-file-reader.c:496
+#: src/data/sys-file-reader.c:497
 #, c-format
 msgid "Invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:500
+#: src/data/sys-file-reader.c:501
 #, c-format
 msgid "Bad variable width %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:504
+#: src/data/sys-file-reader.c:505
 #, c-format
 msgid "Duplicate variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:512
+#: src/data/sys-file-reader.c:513
 msgid "Variable label indicator field is not 0 or 1."
 msgstr ""
 
-#: src/data/sys-file-reader.c:520
+#: src/data/sys-file-reader.c:521
 #, c-format
 msgid "Variable %s has label of invalid length %zu."
 msgstr ""
 
-#: src/data/sys-file-reader.c:539
+#: src/data/sys-file-reader.c:540
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:554
+#: src/data/sys-file-reader.c:555
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:564
+#: src/data/sys-file-reader.c:565
 #, c-format
 msgid "Long string variable %s may not have missing values."
 msgstr ""
 
-#: src/data/sys-file-reader.c:585
+#: src/data/sys-file-reader.c:586
 msgid "Missing string continuation record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:619
+#: src/data/sys-file-reader.c:620
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr ""
 
-#: src/data/sys-file-reader.c:637
+#: src/data/sys-file-reader.c:638
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:640
+#: src/data/sys-file-reader.c:641
 msgid "print"
 msgstr "drucken"
 
-#: src/data/sys-file-reader.c:640
+#: src/data/sys-file-reader.c:641
 msgid "write"
 msgstr "schreiben"
 
-#: src/data/sys-file-reader.c:644
+#: src/data/sys-file-reader.c:645
 msgid "Suppressing further invalid format warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:662
+#: src/data/sys-file-reader.c:663
 msgid "Weighting variable must be numeric."
 msgstr ""
 
-#: src/data/sys-file-reader.c:676
+#: src/data/sys-file-reader.c:677
 msgid "Multiple type 6 (document) records."
 msgstr ""
 
-#: src/data/sys-file-reader.c:680
+#: src/data/sys-file-reader.c:681
 #, c-format
 msgid "Number of document lines (%d) must be greater than 0."
 msgstr ""
 
-#: src/data/sys-file-reader.c:688
+#: src/data/sys-file-reader.c:689
 msgid "Document line contains null byte."
 msgstr ""
 
-#: src/data/sys-file-reader.c:755
+#: src/data/sys-file-reader.c:756
 #, c-format
 msgid "Unrecognized record type 7, subtype %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:780
+#: src/data/sys-file-reader.c:781
 #, c-format
 msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:800
+#: src/data/sys-file-reader.c:801
 #, c-format
 msgid ""
 "Floating-point representation indicated by system file (%d) differs from "
 "expected (%d)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:813
+#: src/data/sys-file-reader.c:814
 msgid "little-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:813
+#: src/data/sys-file-reader.c:814
 msgid "big-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:814
+#: src/data/sys-file-reader.c:815
 #, c-format
 msgid ""
 "Integer format indicated by system file (%s) differs from expected (%s)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:830
+#: src/data/sys-file-reader.c:831
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 4."
 msgstr ""
 
-#: src/data/sys-file-reader.c:834
+#: src/data/sys-file-reader.c:835
 #, c-format
 msgid "File specifies unexpected value %g as SYSMIS."
 msgstr ""
 
-#: src/data/sys-file-reader.c:836
+#: src/data/sys-file-reader.c:837
 #, c-format
 msgid "File specifies unexpected value %g as HIGHEST."
 msgstr ""
 
-#: src/data/sys-file-reader.c:838
+#: src/data/sys-file-reader.c:839
 #, c-format
 msgid "File specifies unexpected value %g as LOWEST."
 msgstr ""
 
-#: src/data/sys-file-reader.c:852
+#: src/data/sys-file-reader.c:853
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 11."
 msgstr ""
 
-#: src/data/sys-file-reader.c:875
+#: src/data/sys-file-reader.c:876
 msgid "Invalid variable display parameters.  Default parameters substituted."
 msgstr ""
 
-#: src/data/sys-file-reader.c:914
+#: src/data/sys-file-reader.c:915
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:924
+#: src/data/sys-file-reader.c:925
 #, c-format
 msgid "Duplicate long variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:979
+#: src/data/sys-file-reader.c:980
 #, c-format
 msgid "%s listed as string of invalid length %s in very length string record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:989
+#: src/data/sys-file-reader.c:990
 #, c-format
 msgid ""
 "%s listed in very long string record with width %s, which requires only one "
 "segment."
 msgstr ""
 
-#: src/data/sys-file-reader.c:995
+#: src/data/sys-file-reader.c:996
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1009
+#: src/data/sys-file-reader.c:1010
 #, c-format
 msgid ""
 "Very long string with width %ld has segment %d of width %d (expected %d)"
 msgstr ""
 
-#: src/data/sys-file-reader.c:1054
+#: src/data/sys-file-reader.c:1055
 #, c-format
 msgid "Invalid number of labels: %d.  Ignoring labels."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1085
+#: src/data/sys-file-reader.c:1086
 msgid ""
 "Variable index record (type 4) does not immediately follow value label "
 "record (type 3) as it should."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1092
+#: src/data/sys-file-reader.c:1093
 #, c-format
 msgid ""
 "Number of variables associated with a value label (%d) is not between 1 and "
 "the number of variables (%zu)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1102
+#: src/data/sys-file-reader.c:1103
 #, c-format
 msgid "Value labels are not allowed on long string variables (%s)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1109
+#: src/data/sys-file-reader.c:1110
 #, c-format
 msgid ""
 "Variables associated with value label are not all of identical type.  "
 "Variable %s is %s, but variable %s is %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1142
+#: src/data/sys-file-reader.c:1143
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1145
+#: src/data/sys-file-reader.c:1146
 #, c-format
 msgid "Duplicate value label for \"%.*s\" on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1223
+#: src/data/sys-file-reader.c:1224
 msgid "File ends in partial case."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1231
+#: src/data/sys-file-reader.c:1232
 #, c-format
 msgid "Error reading case from file %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1328 src/data/sys-file-reader.c:1364
+#: src/data/sys-file-reader.c:1329 src/data/sys-file-reader.c:1365
 msgid "Compressed data is corrupt."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1451
+#: src/data/sys-file-reader.c:1452
 #, c-format
 msgid "Variable index %d not in valid range 1...%d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1456
+#: src/data/sys-file-reader.c:1457
 #, c-format
 msgid "Variable index %d refers to long string continuation."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1542
+#: src/data/sys-file-reader.c:1543
 #, c-format
 msgid "Suppressed %d additional variable map warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1555
+#: src/data/sys-file-reader.c:1556
 #, c-format
 msgid "Variable map refers to unknown variable %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1631
+#: src/data/sys-file-reader.c:1632
 #, c-format
 msgid "System error: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1633
+#: src/data/sys-file-reader.c:1634
 msgid "Unexpected end of file."
 msgstr "plotzlich ist der Datei beendet"
 
@@ -899,44 +899,32 @@ msgstr ""
 msgid "An I/O error occurred writing system file \"%s\"."
 msgstr ""
 
-#: src/data/variable.c:231
+#: src/data/variable.c:217
 #, c-format
 msgid ""
 "Character `%c' (in %s) may not appear as the first character in a variable "
 "name."
 msgstr ""
 
-#: src/data/variable.c:243
+#: src/data/variable.c:229
 #, c-format
 msgid "Character `%c' (in %s) may not appear in a variable name."
 msgstr ""
 
-#: src/data/variable.c:271
+#: src/data/variable.c:257
 msgid "Variable name cannot be empty string."
 msgstr "Ein Variablename darf nicht eines leeres Kette sein."
 
-#: src/data/variable.c:277
+#: src/data/variable.c:263
 #, c-format
 msgid "Variable name %s exceeds %d-character limit."
 msgstr "Der Variabelname %s ist große als %d Buchstaben."
 
-#: src/data/variable.c:285
+#: src/data/variable.c:271
 #, c-format
 msgid "`%s' may not be used as a variable name because it is a reserved word."
 msgstr ""
 
-#: src/data/variable.c:1003
-msgid "ordinary"
-msgstr ""
-
-#: src/data/variable.c:1005
-msgid "system"
-msgstr ""
-
-#: src/data/variable.c:1007
-msgid "scratch"
-msgstr ""
-
 #: src/language/command.c:208
 #, c-format
 msgid "%s is unimplemented."
@@ -1175,7 +1163,7 @@ msgid ""
 msgstr ""
 
 #: src/language/data-io/data-list.c:434 src/language/data-io/data-list.c:543
-#: src/language/data-io/print.c:397 src/language/dictionary/split-file.c:84
+#: src/language/data-io/print.c:401 src/language/dictionary/split-file.c:84
 #: src/language/dictionary/sys-file-info.c:161
 #: src/language/dictionary/sys-file-info.c:390
 #: src/language/dictionary/sys-file-info.c:634
@@ -1183,17 +1171,17 @@ msgstr ""
 msgid "Variable"
 msgstr ""
 
-#: src/language/data-io/data-list.c:435 src/language/data-io/print.c:398
+#: src/language/data-io/data-list.c:435 src/language/data-io/print.c:402
 msgid "Record"
 msgstr ""
 
-#: src/language/data-io/data-list.c:436 src/language/data-io/print.c:399
+#: src/language/data-io/data-list.c:436 src/language/data-io/print.c:403
 #: src/ui/gui/var-sheet.c:72
 msgid "Columns"
 msgstr "Spalten"
 
 #: src/language/data-io/data-list.c:437 src/language/data-io/data-list.c:544
-#: src/language/data-io/print.c:400
+#: src/language/data-io/print.c:404
 msgid "Format"
 msgstr ""
 
@@ -1213,17 +1201,17 @@ msgstr ""
 msgid "Quoted string extends beyond end of line."
 msgstr ""
 
-#: src/language/data-io/data-list.c:689
+#: src/language/data-io/data-list.c:690
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr ""
 
-#: src/language/data-io/data-list.c:733
+#: src/language/data-io/data-list.c:736
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr ""
 
-#: src/language/data-io/data-list.c:764
+#: src/language/data-io/data-list.c:768
 #, c-format
 msgid ""
 "Missing value(s) for all variables from %s onward.  These will be filled "
@@ -1232,98 +1220,128 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/language/data-io/data-reader.c:116
-#: src/language/data-io/data-writer.c:56
+#: src/language/data-io/data-reader.c:120
+#: src/language/data-io/data-writer.c:58
 #, fuzzy
 msgid "data file"
 msgstr "Speichern unter"
 
-#: src/language/data-io/data-reader.c:140
+#: src/language/data-io/data-reader.c:146
 #, c-format
 msgid "Could not open \"%s\" for reading as a data file: %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:178
+#: src/language/data-io/data-reader.c:184
 msgid ""
 "Unexpected end-of-file while reading data in BEGIN DATA.  This probably "
 "indicates a missing or misformatted END DATA command.  END DATA must appear "
 "by itself on a single line with exactly one space between words."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:210
-#: src/language/data-io/data-reader.c:223
+#: src/language/data-io/data-reader.c:209
 #, c-format
 msgid "Error reading file %s: %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:226
+#: src/language/data-io/data-reader.c:212
+#, fuzzy, c-format
+msgid "Unexpected end of file reading %s."
+msgstr "plotzlich ist der Datei beendet"
+
+#: src/language/data-io/data-reader.c:221
+#, fuzzy, c-format
+msgid "Unexpected end of file in partial record reading %s."
+msgstr "plotzlich ist der Datei beendet"
+
+#: src/language/data-io/data-reader.c:281
+#, c-format
+msgid "Corrupt block descriptor word at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:282
 #, c-format
-msgid "%s: Partial record at end of file."
+msgid "Corrupt record descriptor word at offset 0x%lx in %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:277
+#: src/language/data-io/data-reader.c:295
+#, c-format
+msgid "Corrupt record size at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:437
+msgid "Record exceeds remaining block length."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:511
 #, c-format
 msgid "Attempt to read beyond end-of-file on file %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:280
+#: src/language/data-io/data-reader.c:514
 msgid "Attempt to read beyond END DATA."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:438
+#: src/language/data-io/data-reader.c:679
 msgid ""
 "This command is not valid here since the current input program does not "
 "access the inline file."
 msgstr ""
 
-#: src/language/data-io/data-writer.c:72
+#: src/language/data-io/data-writer.c:74
 #, c-format
 msgid "An error occurred while opening \"%s\" for writing as a data file: %s."
 msgstr ""
 
-#: src/language/data-io/data-writer.c:150
+#: src/language/data-io/data-writer.c:191
 #, c-format
 msgid "I/O error occurred writing data file \"%s\"."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:65
+#: src/language/data-io/file-handle.q:64
 #, c-format
 msgid ""
 "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining "
 "a file handle."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:97
+#: src/language/data-io/file-handle.q:119
+msgid "RECFORM must be specified with MODE=360."
+msgstr ""
+
+#: src/language/data-io/file-handle.q:130
 #, c-format
-msgid ""
-"Fixed-length records were specified on /RECFORM, but record length was not "
-"specified on /LRECL.  Assuming %zu-character records."
+msgid "The specified file mode requires LRECL.  Assuming %d-character records."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:102
+#: src/language/data-io/file-handle.q:134
 #, c-format
 msgid ""
-"Record length (%ld) must be at least one byte.  Assuming %zu-character "
+"Record length (%ld) must be between 1 and %lu bytes.  Assuming %d-character "
 "records."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:147
+#: src/language/data-io/file-handle.q:176
 msgid "file"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:149
+#: src/language/data-io/file-handle.q:178
 msgid "inline file"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:175
+#: src/language/data-io/file-handle.q:204
 msgid "expecting a file name or handle name"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:195
+#: src/language/data-io/file-handle.q:224
 #, c-format
 msgid "Handle for %s not allowed here."
 msgstr ""
 
+#: src/language/data-io/get-data.c:48
+#, c-format
+msgid "Unsupported TYPE %s"
+msgstr ""
+
 #: src/language/data-io/get.c:106
 msgid "expecting COMM or TAPE"
 msgstr ""
@@ -1334,7 +1352,7 @@ msgstr ""
 msgid "expecting %s or %s"
 msgstr ""
 
-#: src/language/data-io/get.c:513 src/language/data-io/print.c:176
+#: src/language/data-io/get.c:513 src/language/data-io/print.c:177
 msgid "expecting a valid subcommand"
 msgstr ""
 
@@ -1413,11 +1431,6 @@ msgid ""
 "variable in earlier file (%s)."
 msgstr ""
 
-#: src/language/data-io/get-data.c:48
-#, c-format
-msgid "Unsupported TYPE %s"
-msgstr ""
-
 #: src/language/data-io/inpt-pgm.c:129
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr ""
@@ -1435,39 +1448,39 @@ msgid ""
 "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:156 src/language/stats/descriptives.c:362
+#: src/language/data-io/list.q:157 src/language/stats/descriptives.c:362
 msgid "No variables specified."
 msgstr ""
 
-#: src/language/data-io/list.q:164
+#: src/language/data-io/list.q:165
 #, c-format
 msgid ""
 "The first case (%ld) specified precedes the last case (%ld) specified.  The "
 "values will be swapped."
 msgstr ""
 
-#: src/language/data-io/list.q:172
+#: src/language/data-io/list.q:173
 #, c-format
 msgid ""
 "The first case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:178
+#: src/language/data-io/list.q:179
 #, c-format
 msgid ""
 "The last case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:184
+#: src/language/data-io/list.q:185
 #, c-format
 msgid "The step value %ld is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:210
+#: src/language/data-io/list.q:211
 msgid "`/FORMAT WEIGHT' specified, but weighting is not on."
 msgstr ""
 
-#: src/language/data-io/list.q:466
+#: src/language/data-io/list.q:467
 msgid "Line"
 msgstr ""
 
@@ -1511,39 +1524,39 @@ msgid ""
 "Data fields must be listed in order of increasing record number."
 msgstr ""
 
-#: src/language/data-io/print.c:261
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:476
+#: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
+msgid "expecting end of command"
+msgstr ""
+
+#: src/language/data-io/print-space.c:116
+msgid "The expression on PRINT SPACE evaluated to the system-missing value."
+msgstr ""
+
+#: src/language/data-io/print-space.c:119
+#, c-format
+msgid "The expression on PRINT SPACE evaluated to %g."
+msgstr ""
+
+#: src/language/data-io/print.c:265
 #, c-format
 msgid "Output calls for %d records but %zu specified on RECORDS subcommand."
 msgstr ""
 
-#: src/language/data-io/print.c:430
+#: src/language/data-io/print.c:434
 #, c-format
 msgid "Writing %d record to %s."
 msgid_plural "Writing %d records to %s."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print.c:434
+#: src/language/data-io/print.c:438
 #, c-format
 msgid "Writing %d record."
 msgid_plural "Writing %d records."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:476
-#: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
-msgid "expecting end of command"
-msgstr ""
-
-#: src/language/data-io/print-space.c:116
-msgid "The expression on PRINT SPACE evaluated to the system-missing value."
-msgstr ""
-
-#: src/language/data-io/print-space.c:119
-#, c-format
-msgid "The expression on PRINT SPACE evaluated to %g."
-msgstr ""
-
 #: src/language/dictionary/apply-dictionary.c:75
 #, c-format
 msgid "Variable %s is %s in target file, but %s in source file."
@@ -2302,11 +2315,11 @@ msgstr ""
 msgid "LO or LOWEST must be part of a range."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:106
+#: src/language/lexer/range-parser.c:107
 msgid "System-missing value is not valid here."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:114
+#: src/language/lexer/range-parser.c:115
 msgid "expecting number or data string"
 msgstr ""
 
@@ -3045,73 +3058,73 @@ msgstr ""
 msgid "Tukey's Hinges"
 msgstr ""
 
-#: src/language/stats/flip.c:95
+#: src/language/stats/flip.c:96
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/stats/flip.c:150
+#: src/language/stats/flip.c:151
 msgid "Could not create temporary file for FLIP."
 msgstr ""
 
-#: src/language/stats/flip.c:161
+#: src/language/stats/flip.c:162
 #, c-format
 msgid "Error writing FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:261
+#: src/language/stats/flip.c:262
 #, c-format
 msgid "Could not create acceptable variant for variable %s."
 msgstr ""
 
-#: src/language/stats/flip.c:277
+#: src/language/stats/flip.c:278
 msgid "Cannot create more than 99999 variable names."
 msgstr ""
 
-#: src/language/stats/flip.c:393
+#: src/language/stats/flip.c:394
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:400
+#: src/language/stats/flip.c:401
 msgid "Error creating FLIP source file."
 msgstr ""
 
-#: src/language/stats/flip.c:413
+#: src/language/stats/flip.c:414
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:415
+#: src/language/stats/flip.c:416
 msgid "Unexpected end of file reading FLIP file."
 msgstr "plotzlich ist der Datei beendet"
 
-#: src/language/stats/flip.c:431
+#: src/language/stats/flip.c:432
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:439
+#: src/language/stats/flip.c:440
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:450
+#: src/language/stats/flip.c:451
 #, c-format
 msgid "Error closing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:458
+#: src/language/stats/flip.c:459
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:487
+#: src/language/stats/flip.c:488
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:490
+#: src/language/stats/flip.c:491
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr ""
 
@@ -3198,11 +3211,11 @@ msgstr ""
 msgid "Multivariate GLM not yet supported"
 msgstr ""
 
-#: src/language/stats/glm.q:271 src/language/stats/regression.q:1165
+#: src/language/stats/glm.q:271 src/language/stats/regression.q:1164
 msgid "Dependent variable must be numeric."
 msgstr ""
 
-#: src/language/stats/glm.q:346 src/language/stats/regression.q:1262
+#: src/language/stats/glm.q:346 src/language/stats/regression.q:1261
 msgid "No valid data found. This command was skipped."
 msgstr ""
 
@@ -3214,6 +3227,22 @@ msgstr ""
 msgid "TABLES subcommand may not appear more than once."
 msgstr ""
 
+#: src/language/stats/npar-summary.c:108
+msgid "Descriptive Statistics"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:145
+msgid "25th"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:148
+msgid "50th (Median)"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:151
+msgid "75th"
+msgstr ""
+
 #: src/language/stats/npar.q:98
 msgid "NPAR subcommand not currently implemented."
 msgstr ""
@@ -3238,22 +3267,6 @@ msgid ""
 "not match the number following (%zu)."
 msgstr ""
 
-#: src/language/stats/npar-summary.c:108
-msgid "Descriptive Statistics"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:145
-msgid "25th"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:148
-msgid "50th (Median)"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:151
-msgid "75th"
-msgstr ""
-
 #: src/language/stats/oneway.q:169
 msgid "Number of contrast coefficients must equal the number of groups"
 msgstr ""
@@ -3349,56 +3362,56 @@ msgstr ""
 msgid "Does not assume equal"
 msgstr ""
 
-#: src/language/stats/rank.q:220
+#: src/language/stats/rank.q:221
 #, c-format
 msgid "%s of %s by %s"
 msgstr ""
 
-#: src/language/stats/rank.q:225
+#: src/language/stats/rank.q:226
 #, c-format
 msgid "%s of %s"
 msgstr ""
 
-#: src/language/stats/rank.q:601
+#: src/language/stats/rank.q:602
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr ""
 
-#: src/language/stats/rank.q:694
+#: src/language/stats/rank.q:695
 msgid "Variables Created By RANK"
 msgstr ""
 
-#: src/language/stats/rank.q:718
+#: src/language/stats/rank.q:719
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:729
+#: src/language/stats/rank.q:730
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:743
+#: src/language/stats/rank.q:744
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:753
+#: src/language/stats/rank.q:754
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:766
+#: src/language/stats/rank.q:767
 msgid ""
 "FRACTION has been specified, but NORMAL and PROPORTION rank functions have "
 "not been requested.  The FRACTION subcommand will be ignored."
 msgstr ""
 
-#: src/language/stats/rank.q:859
+#: src/language/stats/rank.q:860
 #, c-format
 msgid "Variable %s already exists."
 msgstr ""
 
-#: src/language/stats/rank.q:864
+#: src/language/stats/rank.q:865
 msgid "Too many variables in INTO clause."
 msgstr ""
 
@@ -3880,44 +3893,44 @@ msgstr ""
 msgid "Destination cannot be a string variable."
 msgstr ""
 
-#: src/language/xforms/recode.c:245
+#: src/language/xforms/recode.c:246
 msgid ""
 "Inconsistent target variable types.  Target variables must be all numeric or "
 "all string."
 msgstr ""
 
-#: src/language/xforms/recode.c:266
+#: src/language/xforms/recode.c:267
 msgid "CONVERT requires string input values and numeric output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:316
+#: src/language/xforms/recode.c:317
 msgid "THRU is not allowed with string variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:390
+#: src/language/xforms/recode.c:391
 msgid "expecting output value"
 msgstr ""
 
-#: src/language/xforms/recode.c:439
+#: src/language/xforms/recode.c:440
 #, c-format
 msgid ""
 "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same "
 "number of variables as source and target variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:454
+#: src/language/xforms/recode.c:455
 #, c-format
 msgid ""
 "There is no variable named %s.  (All string variables specified on INTO must "
 "already exist.  Use the STRING command to create a string variable.)"
 msgstr ""
 
-#: src/language/xforms/recode.c:469
+#: src/language/xforms/recode.c:470
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:482
+#: src/language/xforms/recode.c:483
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr ""
@@ -3948,23 +3961,23 @@ msgstr ""
 msgid "hash table:"
 msgstr ""
 
-#: src/math/percentiles.c:40
+#: src/math/percentiles.c:41
 msgid "HAverage"
 msgstr ""
 
-#: src/math/percentiles.c:41
+#: src/math/percentiles.c:42
 msgid "Weighted Average"
 msgstr ""
 
-#: src/math/percentiles.c:42
+#: src/math/percentiles.c:43
 msgid "Rounded"
 msgstr ""
 
-#: src/math/percentiles.c:43
+#: src/math/percentiles.c:44
 msgid "Empirical"
 msgstr ""
 
-#: src/math/percentiles.c:44
+#: src/math/percentiles.c:45
 msgid "Empirical with averaging"
 msgstr ""
 
@@ -5014,7 +5027,7 @@ msgstr ""
 msgid "Options:"
 msgstr ""
 
-#: src/ui/gui/find-dialog.c:657
+#: src/ui/gui/find-dialog.c:658
 #, c-format
 msgid "Bad regular expression: %s"
 msgstr ""
@@ -5189,10 +5202,6 @@ msgstr "xyzzy"
 msgid "Paste"
 msgstr "Datum"
 
-#: src/ui/gui/psppire.c:197
-msgid "_Reset"
-msgstr "_Zurücksetzen"
-
 #: src/ui/gui/psppire-data-store.c:816
 msgid "var"
 msgstr ""
@@ -5202,6 +5211,28 @@ msgstr ""
 msgid "%ld"
 msgstr ""
 
+#: src/ui/gui/psppire-var-store.c:479 src/ui/gui/var-display.c:14
+msgid "None"
+msgstr "Keine"
+
+#: src/ui/gui/psppire-var-store.c:489
+msgid "Scientific"
+msgstr "Wissenschäflich"
+
+#: src/ui/gui/psppire-var-store.c:492
+msgid "Custom"
+msgstr "Spezial"
+
+#: src/ui/gui/psppire-var-store.c:563 src/ui/gui/psppire-var-store.c:573
+#: src/ui/gui/psppire-var-store.c:583
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/ui/gui/psppire.c:198
+msgid "_Reset"
+msgstr "_Zurücksetzen"
+
 #: src/ui/gui/psppire.glade:11
 #, fuzzy
 msgid "This is pre-alpha software.  Use at your own risk."
@@ -5445,24 +5476,6 @@ msgstr ""
 msgid "Search backward"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:479 src/ui/gui/var-display.c:14
-msgid "None"
-msgstr "Keine"
-
-#: src/ui/gui/psppire-var-store.c:489
-msgid "Scientific"
-msgstr "Wissenschäflich"
-
-#: src/ui/gui/psppire-var-store.c:492
-msgid "Custom"
-msgstr "Spezial"
-
-#: src/ui/gui/psppire-var-store.c:563 src/ui/gui/psppire-var-store.c:573
-#: src/ui/gui/psppire-var-store.c:583
-#, c-format
-msgid "%d"
-msgstr ""
-
 #: src/ui/gui/rank.glade:111
 msgid "By:"
 msgstr ""
@@ -5627,6 +5640,11 @@ msgstr ""
 msgid "To End"
 msgstr ""
 
+#: src/ui/gui/t-test-independent-samples-dialog.c:175
+#, c-format
+msgid "Confidence Interval: %2d %%"
+msgstr ""
+
 #: src/ui/gui/t-test.glade:56
 msgid "Define Groups"
 msgstr ""
@@ -5661,10 +5679,25 @@ msgstr ""
 msgid "Exclude cases _listwise"
 msgstr ""
 
-#: src/ui/gui/t-test-independent-samples-dialog.c:175
-#, c-format
-msgid "Confidence Interval: %2d %%"
-msgstr ""
+#: src/ui/gui/var-sheet.c:65
+msgid "Name"
+msgstr "Name"
+
+#: src/ui/gui/var-sheet.c:68
+msgid "Decimals"
+msgstr "Dezimalstellen"
+
+#: src/ui/gui/var-sheet.c:70
+msgid "Values"
+msgstr "Werten"
+
+#: src/ui/gui/var-sheet.c:73
+msgid "Align"
+msgstr "Einstellung"
+
+#: src/ui/gui/var-sheet.c:74
+msgid "Measure"
+msgstr "Messe"
 
 #: src/ui/gui/variable-info-dialog.c:88
 #, fuzzy, c-format
@@ -5696,26 +5729,6 @@ msgstr "Werten"
 msgid "%s %s\n"
 msgstr ""
 
-#: src/ui/gui/var-sheet.c:65
-msgid "Name"
-msgstr "Name"
-
-#: src/ui/gui/var-sheet.c:68
-msgid "Decimals"
-msgstr "Dezimalstellen"
-
-#: src/ui/gui/var-sheet.c:70
-msgid "Values"
-msgstr "Werten"
-
-#: src/ui/gui/var-sheet.c:73
-msgid "Align"
-msgstr "Einstellung"
-
-#: src/ui/gui/var-sheet.c:74
-msgid "Measure"
-msgstr "Messe"
-
 #: src/ui/gui/weight-cases-dialog.c:88
 #, c-format
 msgid "Weight cases by %s"
index 758a4e8ffb69a6a3380449f2a8cd1dee0833ad4d..fbafcf76d15733976696867b47e763da19a8cb34 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.4.3\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-11-08 09:15+0900\n"
+"POT-Creation-Date: 2007-11-10 20:49-0800\n"
 "PO-Revision-Date: 2007-09-15 08:29+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -44,12 +44,6 @@ msgstr ""
 msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
 msgstr ""
 
-#: src/data/casereader-filter.c:221
-msgid ""
-"At least one case in the data read had a weight value that was user-missing, "
-"system-missing, zero, or negative.  These case(s) were ignored."
-msgstr ""
-
 #: src/data/case-tmpfile.c:57
 msgid "failed to create temporary file"
 msgstr ""
@@ -70,157 +64,163 @@ msgstr ""
 msgid "writing to temporary file"
 msgstr ""
 
-#: src/data/data-in.c:267 src/data/data-in.c:457
+#: src/data/casereader-filter.c:221
+msgid ""
+"At least one case in the data read had a weight value that was user-missing, "
+"system-missing, zero, or negative.  These case(s) were ignored."
+msgstr ""
+
+#: src/data/data-in.c:287 src/data/data-in.c:477
 msgid "Field contents are not numeric."
 msgstr ""
 
-#: src/data/data-in.c:269 src/data/data-in.c:459
+#: src/data/data-in.c:289 src/data/data-in.c:479
 msgid "Number followed by garbage."
 msgstr ""
 
-#: src/data/data-in.c:280
+#: src/data/data-in.c:300
 msgid "Invalid numeric syntax."
 msgstr ""
 
-#: src/data/data-in.c:289 src/data/data-in.c:472
+#: src/data/data-in.c:309 src/data/data-in.c:492
 msgid "Too-large number set to system-missing."
 msgstr ""
 
-#: src/data/data-in.c:294 src/data/data-in.c:477
+#: src/data/data-in.c:314 src/data/data-in.c:497
 msgid "Too-small number set to zero."
 msgstr ""
 
-#: src/data/data-in.c:320
+#: src/data/data-in.c:340
 msgid "All characters in field must be digits."
 msgstr ""
 
-#: src/data/data-in.c:343
+#: src/data/data-in.c:363
 msgid "Unrecognized character in field."
 msgstr ""
 
-#: src/data/data-in.c:367 src/data/data-in.c:631
+#: src/data/data-in.c:387 src/data/data-in.c:660
 msgid "Field must have even length."
 msgstr ""
 
-#: src/data/data-in.c:372 src/data/data-in.c:637
+#: src/data/data-in.c:392 src/data/data-in.c:671
 msgid "Field must contain only hex digits."
 msgstr ""
 
-#: src/data/data-in.c:676 src/data/data-in.c:723
+#: src/data/data-in.c:710 src/data/data-in.c:757
 msgid "Syntax error in date field."
 msgstr ""
 
-#: src/data/data-in.c:692
+#: src/data/data-in.c:726
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr ""
 
-#: src/data/data-in.c:739
+#: src/data/data-in.c:773
 msgid "Delimiter expected between fields in date."
 msgstr ""
 
-#: src/data/data-in.c:813
+#: src/data/data-in.c:847
 msgid ""
 "Unrecognized month format.  Months may be specified as Arabic or Roman "
 "numerals or as at least 3 letters of their English names."
 msgstr ""
 
-#: src/data/data-in.c:840
+#: src/data/data-in.c:874
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr ""
 
-#: src/data/data-in.c:852
+#: src/data/data-in.c:886
 #, c-format
 msgid "Trailing garbage \"%.*s\" following date."
 msgstr ""
 
-#: src/data/data-in.c:868
+#: src/data/data-in.c:902
 msgid "Julian day must have exactly three digits."
 msgstr ""
 
-#: src/data/data-in.c:873
+#: src/data/data-in.c:907
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr ""
 
-#: src/data/data-in.c:897
+#: src/data/data-in.c:931
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr ""
 
-#: src/data/data-in.c:917
+#: src/data/data-in.c:951
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr ""
 
-#: src/data/data-in.c:930
+#: src/data/data-in.c:964
 msgid "Delimiter expected between fields in time."
 msgstr ""
 
-#: src/data/data-in.c:950
+#: src/data/data-in.c:984
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr ""
 
-#: src/data/data-in.c:990
+#: src/data/data-in.c:1024
 msgid ""
 "Unrecognized weekday name.  At least the first two letters of an English "
 "weekday name must be specified."
 msgstr ""
 
-#: src/data/data-in.c:1128
+#: src/data/data-in.c:1162
 #, c-format
 msgid "`%c' expected in date field."
 msgstr ""
 
-#: src/data/data-in.c:1169
+#: src/data/data-in.c:1203
 #, c-format
 msgid "column %d"
 msgstr ""
 
-#: src/data/data-in.c:1171
+#: src/data/data-in.c:1205
 #, c-format
 msgid "columns %d-%d"
 msgstr ""
 
-#: src/data/data-in.c:1175
+#: src/data/data-in.c:1209
 #, c-format
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:465
+#: src/data/data-out.c:476
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:486
+#: src/data/data-out.c:497
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
 
-#: src/data/dictionary.c:758
+#: src/data/dictionary.c:762
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1059
+#: src/data/dictionary.c:1060
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
 
-#: src/data/file-handle-def.c:452
+#: src/data/file-handle-def.c:462
 #, c-format
 msgid "Can't read from %s as a %s because it is already being read as a %s."
 msgstr ""
 
-#: src/data/file-handle-def.c:456
+#: src/data/file-handle-def.c:466
 #, c-format
 msgid "Can't write to %s as a %s because it is already being written as a %s."
 msgstr ""
 
-#: src/data/file-handle-def.c:463
+#: src/data/file-handle-def.c:473
 #, c-format
 msgid "Can't re-open %s as a %s."
 msgstr ""
@@ -302,33 +302,33 @@ msgstr[1] ""
 msgid "%s variables are not compatible with %s format %s."
 msgstr ""
 
-#: src/data/format.c:318 src/data/sys-file-reader.c:638
-#: src/ui/gui/data-editor.glade:1285 src/ui/gui/psppire.glade:2176
-#: src/ui/gui/psppire-var-store.c:493
+#: src/data/format.c:318 src/data/sys-file-reader.c:639
+#: src/ui/gui/data-editor.glade:1285 src/ui/gui/psppire-var-store.c:493
+#: src/ui/gui/psppire.glade:2176
 msgid "String"
 msgstr ""
 
-#: src/data/format.c:318 src/data/sys-file-reader.c:638
-#: src/ui/gui/data-editor.glade:1174 src/ui/gui/psppire.glade:2131
-#: src/ui/gui/psppire-var-store.c:486
+#: src/data/format.c:318 src/data/sys-file-reader.c:639
+#: src/ui/gui/data-editor.glade:1174 src/ui/gui/psppire-var-store.c:486
+#: src/ui/gui/psppire.glade:2131
 msgid "Numeric"
 msgstr ""
 
-#: src/data/format.c:319 src/data/sys-file-reader.c:1113
-#: src/data/sys-file-reader.c:1115
+#: src/data/format.c:319 src/data/sys-file-reader.c:1114
+#: src/data/sys-file-reader.c:1116
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:471 src/language/xforms/recode.c:472
-#: src/language/xforms/recode.c:484 src/language/xforms/recode.c:485
+#: src/language/xforms/recode.c:472 src/language/xforms/recode.c:473
+#: src/language/xforms/recode.c:485 src/language/xforms/recode.c:486
 msgid "numeric"
 msgstr ""
 
-#: src/data/format.c:319 src/data/sys-file-reader.c:1113
-#: src/data/sys-file-reader.c:1115
+#: src/data/format.c:319 src/data/sys-file-reader.c:1114
+#: src/data/sys-file-reader.c:1116
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:471 src/language/xforms/recode.c:472
-#: src/language/xforms/recode.c:484 src/language/xforms/recode.c:485
+#: src/language/xforms/recode.c:472 src/language/xforms/recode.c:473
+#: src/language/xforms/recode.c:485 src/language/xforms/recode.c:486
 msgid "string"
 msgstr ""
 
@@ -402,149 +402,149 @@ msgstr ""
 msgid "Removing %s: %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:98
+#: src/data/por-file-reader.c:99
 #, c-format
 msgid "portable file %s corrupt at offset 0x%lx: "
 msgstr ""
 
-#: src/data/por-file-reader.c:127
+#: src/data/por-file-reader.c:128
 #, c-format
 msgid "reading portable file %s at offset 0x%lx: "
 msgstr ""
 
-#: src/data/por-file-reader.c:155
+#: src/data/por-file-reader.c:156
 #, c-format
 msgid "Error closing portable file \"%s\": %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:207
+#: src/data/por-file-reader.c:208
 msgid "unexpected end of file"
 msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:148
+#: src/data/por-file-reader.c:268 src/data/por-file-writer.c:148
 msgid "portable file"
 msgstr ""
 
-#: src/data/por-file-reader.c:275
+#: src/data/por-file-reader.c:276
 #, c-format
 msgid ""
 "An error occurred while opening \"%s\" for reading as a portable file: %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:296
+#: src/data/por-file-reader.c:297
 msgid "Data record expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:378
+#: src/data/por-file-reader.c:379
 msgid "Number expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:406
+#: src/data/por-file-reader.c:407
 msgid "Missing numeric terminator."
 msgstr ""
 
-#: src/data/por-file-reader.c:429
+#: src/data/por-file-reader.c:430
 msgid "Invalid integer."
 msgstr ""
 
-#: src/data/por-file-reader.c:440
+#: src/data/por-file-reader.c:441
 #, c-format
 msgid "Bad string length %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:501
+#: src/data/por-file-reader.c:502
 #, c-format
 msgid "%s: Not a portable file."
 msgstr ""
 
-#: src/data/por-file-reader.c:517
+#: src/data/por-file-reader.c:518
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr ""
 
-#: src/data/por-file-reader.c:526
+#: src/data/por-file-reader.c:527
 #, c-format
 msgid "Bad date string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:528
+#: src/data/por-file-reader.c:529
 #, c-format
 msgid "Bad time string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:570
+#: src/data/por-file-reader.c:571
 #, c-format
 msgid ""
 "%s: Bad format specifier byte (%d).  Variable will be assigned a default "
 "format."
 msgstr ""
 
-#: src/data/por-file-reader.c:591
+#: src/data/por-file-reader.c:592
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:595
+#: src/data/por-file-reader.c:596
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:619
+#: src/data/por-file-reader.c:620
 msgid "Expected variable count record."
 msgstr ""
 
-#: src/data/por-file-reader.c:623
+#: src/data/por-file-reader.c:624
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:633
+#: src/data/por-file-reader.c:634
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr ""
 
-#: src/data/por-file-reader.c:648
+#: src/data/por-file-reader.c:649
 msgid "Expected variable record."
 msgstr ""
 
-#: src/data/por-file-reader.c:652
+#: src/data/por-file-reader.c:653
 #, c-format
 msgid "Invalid variable width %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:660
+#: src/data/por-file-reader.c:661
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:664
+#: src/data/por-file-reader.c:665
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:679
+#: src/data/por-file-reader.c:680
 #, c-format
 msgid "Duplicate variable name %s in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:680
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:723
+#: src/data/por-file-reader.c:724
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr ""
 
-#: src/data/por-file-reader.c:770
+#: src/data/por-file-reader.c:771
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr ""
 
-#: src/data/por-file-reader.c:773
+#: src/data/por-file-reader.c:774
 #, c-format
 msgid ""
 "Cannot assign value labels to %s and %s, which have different variable types."
@@ -574,7 +574,7 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:151
+#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:180
 msgid "scratch file"
 msgstr ""
 
@@ -584,297 +584,297 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:197 src/data/sys-file-writer.c:190
+#: src/data/sys-file-reader.c:198 src/data/sys-file-writer.c:190
 msgid "system file"
 msgstr ""
 
-#: src/data/sys-file-reader.c:204
+#: src/data/sys-file-reader.c:205
 #, c-format
 msgid "Error opening \"%s\" for reading as a system file: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:243
+#: src/data/sys-file-reader.c:244
 msgid "Misplaced type 4 record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:254
+#: src/data/sys-file-reader.c:255
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:293
+#: src/data/sys-file-reader.c:294
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:333
+#: src/data/sys-file-reader.c:334
 #, c-format
 msgid "Error closing system file \"%s\": %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:398 src/data/sys-file-reader.c:408
+#: src/data/sys-file-reader.c:399 src/data/sys-file-reader.c:409
 msgid "This is not an SPSS system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:427
+#: src/data/sys-file-reader.c:428
 #, c-format
 msgid ""
 "Compression bias (%g) is not the usual value of 100, or system file uses "
 "unrecognized floating-point format."
 msgstr ""
 
-#: src/data/sys-file-reader.c:496
+#: src/data/sys-file-reader.c:497
 #, c-format
 msgid "Invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:500
+#: src/data/sys-file-reader.c:501
 #, c-format
 msgid "Bad variable width %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:504
+#: src/data/sys-file-reader.c:505
 #, c-format
 msgid "Duplicate variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:512
+#: src/data/sys-file-reader.c:513
 msgid "Variable label indicator field is not 0 or 1."
 msgstr ""
 
-#: src/data/sys-file-reader.c:520
+#: src/data/sys-file-reader.c:521
 #, c-format
 msgid "Variable %s has label of invalid length %zu."
 msgstr ""
 
-#: src/data/sys-file-reader.c:539
+#: src/data/sys-file-reader.c:540
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:554
+#: src/data/sys-file-reader.c:555
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:564
+#: src/data/sys-file-reader.c:565
 #, c-format
 msgid "Long string variable %s may not have missing values."
 msgstr ""
 
-#: src/data/sys-file-reader.c:585
+#: src/data/sys-file-reader.c:586
 msgid "Missing string continuation record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:619
+#: src/data/sys-file-reader.c:620
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr ""
 
-#: src/data/sys-file-reader.c:637
+#: src/data/sys-file-reader.c:638
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:640
+#: src/data/sys-file-reader.c:641
 msgid "print"
 msgstr ""
 
-#: src/data/sys-file-reader.c:640
+#: src/data/sys-file-reader.c:641
 msgid "write"
 msgstr ""
 
-#: src/data/sys-file-reader.c:644
+#: src/data/sys-file-reader.c:645
 msgid "Suppressing further invalid format warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:662
+#: src/data/sys-file-reader.c:663
 msgid "Weighting variable must be numeric."
 msgstr ""
 
-#: src/data/sys-file-reader.c:676
+#: src/data/sys-file-reader.c:677
 msgid "Multiple type 6 (document) records."
 msgstr ""
 
-#: src/data/sys-file-reader.c:680
+#: src/data/sys-file-reader.c:681
 #, c-format
 msgid "Number of document lines (%d) must be greater than 0."
 msgstr ""
 
-#: src/data/sys-file-reader.c:688
+#: src/data/sys-file-reader.c:689
 msgid "Document line contains null byte."
 msgstr ""
 
-#: src/data/sys-file-reader.c:755
+#: src/data/sys-file-reader.c:756
 #, c-format
 msgid "Unrecognized record type 7, subtype %d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:780
+#: src/data/sys-file-reader.c:781
 #, c-format
 msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:800
+#: src/data/sys-file-reader.c:801
 #, c-format
 msgid ""
 "Floating-point representation indicated by system file (%d) differs from "
 "expected (%d)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:813
+#: src/data/sys-file-reader.c:814
 msgid "little-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:813
+#: src/data/sys-file-reader.c:814
 msgid "big-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:814
+#: src/data/sys-file-reader.c:815
 #, c-format
 msgid ""
 "Integer format indicated by system file (%s) differs from expected (%s)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:830
+#: src/data/sys-file-reader.c:831
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 4."
 msgstr ""
 
-#: src/data/sys-file-reader.c:834
+#: src/data/sys-file-reader.c:835
 #, c-format
 msgid "File specifies unexpected value %g as SYSMIS."
 msgstr ""
 
-#: src/data/sys-file-reader.c:836
+#: src/data/sys-file-reader.c:837
 #, c-format
 msgid "File specifies unexpected value %g as HIGHEST."
 msgstr ""
 
-#: src/data/sys-file-reader.c:838
+#: src/data/sys-file-reader.c:839
 #, c-format
 msgid "File specifies unexpected value %g as LOWEST."
 msgstr ""
 
-#: src/data/sys-file-reader.c:852
+#: src/data/sys-file-reader.c:853
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 11."
 msgstr ""
 
-#: src/data/sys-file-reader.c:875
+#: src/data/sys-file-reader.c:876
 msgid "Invalid variable display parameters.  Default parameters substituted."
 msgstr ""
 
-#: src/data/sys-file-reader.c:914
+#: src/data/sys-file-reader.c:915
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:924
+#: src/data/sys-file-reader.c:925
 #, c-format
 msgid "Duplicate long variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:979
+#: src/data/sys-file-reader.c:980
 #, c-format
 msgid "%s listed as string of invalid length %s in very length string record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:989
+#: src/data/sys-file-reader.c:990
 #, c-format
 msgid ""
 "%s listed in very long string record with width %s, which requires only one "
 "segment."
 msgstr ""
 
-#: src/data/sys-file-reader.c:995
+#: src/data/sys-file-reader.c:996
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1009
+#: src/data/sys-file-reader.c:1010
 #, c-format
 msgid ""
 "Very long string with width %ld has segment %d of width %d (expected %d)"
 msgstr ""
 
-#: src/data/sys-file-reader.c:1054
+#: src/data/sys-file-reader.c:1055
 #, c-format
 msgid "Invalid number of labels: %d.  Ignoring labels."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1085
+#: src/data/sys-file-reader.c:1086
 msgid ""
 "Variable index record (type 4) does not immediately follow value label "
 "record (type 3) as it should."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1092
+#: src/data/sys-file-reader.c:1093
 #, c-format
 msgid ""
 "Number of variables associated with a value label (%d) is not between 1 and "
 "the number of variables (%zu)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1102
+#: src/data/sys-file-reader.c:1103
 #, c-format
 msgid "Value labels are not allowed on long string variables (%s)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1109
+#: src/data/sys-file-reader.c:1110
 #, c-format
 msgid ""
 "Variables associated with value label are not all of identical type.  "
 "Variable %s is %s, but variable %s is %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1142
+#: src/data/sys-file-reader.c:1143
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1145
+#: src/data/sys-file-reader.c:1146
 #, c-format
 msgid "Duplicate value label for \"%.*s\" on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1223
+#: src/data/sys-file-reader.c:1224
 msgid "File ends in partial case."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1231
+#: src/data/sys-file-reader.c:1232
 #, c-format
 msgid "Error reading case from file %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1328 src/data/sys-file-reader.c:1364
+#: src/data/sys-file-reader.c:1329 src/data/sys-file-reader.c:1365
 msgid "Compressed data is corrupt."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1451
+#: src/data/sys-file-reader.c:1452
 #, c-format
 msgid "Variable index %d not in valid range 1...%d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1456
+#: src/data/sys-file-reader.c:1457
 #, c-format
 msgid "Variable index %d refers to long string continuation."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1542
+#: src/data/sys-file-reader.c:1543
 #, c-format
 msgid "Suppressed %d additional variable map warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1555
+#: src/data/sys-file-reader.c:1556
 #, c-format
 msgid "Variable map refers to unknown variable %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1631
+#: src/data/sys-file-reader.c:1632
 #, c-format
 msgid "System error: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1633
+#: src/data/sys-file-reader.c:1634
 msgid "Unexpected end of file."
 msgstr ""
 
@@ -893,44 +893,32 @@ msgstr ""
 msgid "An I/O error occurred writing system file \"%s\"."
 msgstr ""
 
-#: src/data/variable.c:231
+#: src/data/variable.c:217
 #, c-format
 msgid ""
 "Character `%c' (in %s) may not appear as the first character in a variable "
 "name."
 msgstr ""
 
-#: src/data/variable.c:243
+#: src/data/variable.c:229
 #, c-format
 msgid "Character `%c' (in %s) may not appear in a variable name."
 msgstr ""
 
-#: src/data/variable.c:271
+#: src/data/variable.c:257
 msgid "Variable name cannot be empty string."
 msgstr ""
 
-#: src/data/variable.c:277
+#: src/data/variable.c:263
 #, c-format
 msgid "Variable name %s exceeds %d-character limit."
 msgstr ""
 
-#: src/data/variable.c:285
+#: src/data/variable.c:271
 #, c-format
 msgid "`%s' may not be used as a variable name because it is a reserved word."
 msgstr ""
 
-#: src/data/variable.c:1003
-msgid "ordinary"
-msgstr ""
-
-#: src/data/variable.c:1005
-msgid "system"
-msgstr ""
-
-#: src/data/variable.c:1007
-msgid "scratch"
-msgstr ""
-
 #: src/language/command.c:208
 #, c-format
 msgid "%s is unimplemented."
@@ -1169,7 +1157,7 @@ msgid ""
 msgstr ""
 
 #: src/language/data-io/data-list.c:434 src/language/data-io/data-list.c:543
-#: src/language/data-io/print.c:397 src/language/dictionary/split-file.c:84
+#: src/language/data-io/print.c:401 src/language/dictionary/split-file.c:84
 #: src/language/dictionary/sys-file-info.c:161
 #: src/language/dictionary/sys-file-info.c:390
 #: src/language/dictionary/sys-file-info.c:634
@@ -1177,17 +1165,17 @@ msgstr ""
 msgid "Variable"
 msgstr ""
 
-#: src/language/data-io/data-list.c:435 src/language/data-io/print.c:398
+#: src/language/data-io/data-list.c:435 src/language/data-io/print.c:402
 msgid "Record"
 msgstr ""
 
-#: src/language/data-io/data-list.c:436 src/language/data-io/print.c:399
+#: src/language/data-io/data-list.c:436 src/language/data-io/print.c:403
 #: src/ui/gui/var-sheet.c:72
 msgid "Columns"
 msgstr ""
 
 #: src/language/data-io/data-list.c:437 src/language/data-io/data-list.c:544
-#: src/language/data-io/print.c:400
+#: src/language/data-io/print.c:404
 msgid "Format"
 msgstr ""
 
@@ -1207,17 +1195,17 @@ msgstr ""
 msgid "Quoted string extends beyond end of line."
 msgstr ""
 
-#: src/language/data-io/data-list.c:689
+#: src/language/data-io/data-list.c:690
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr ""
 
-#: src/language/data-io/data-list.c:733
+#: src/language/data-io/data-list.c:736
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr ""
 
-#: src/language/data-io/data-list.c:764
+#: src/language/data-io/data-list.c:768
 #, c-format
 msgid ""
 "Missing value(s) for all variables from %s onward.  These will be filled "
@@ -1226,97 +1214,127 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/language/data-io/data-reader.c:116
-#: src/language/data-io/data-writer.c:56
+#: src/language/data-io/data-reader.c:120
+#: src/language/data-io/data-writer.c:58
 msgid "data file"
 msgstr ""
 
-#: src/language/data-io/data-reader.c:140
+#: src/language/data-io/data-reader.c:146
 #, c-format
 msgid "Could not open \"%s\" for reading as a data file: %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:178
+#: src/language/data-io/data-reader.c:184
 msgid ""
 "Unexpected end-of-file while reading data in BEGIN DATA.  This probably "
 "indicates a missing or misformatted END DATA command.  END DATA must appear "
 "by itself on a single line with exactly one space between words."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:210
-#: src/language/data-io/data-reader.c:223
+#: src/language/data-io/data-reader.c:209
 #, c-format
 msgid "Error reading file %s: %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:226
+#: src/language/data-io/data-reader.c:212
 #, c-format
-msgid "%s: Partial record at end of file."
+msgid "Unexpected end of file reading %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:277
+#: src/language/data-io/data-reader.c:221
+#, c-format
+msgid "Unexpected end of file in partial record reading %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:281
+#, c-format
+msgid "Corrupt block descriptor word at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:282
+#, c-format
+msgid "Corrupt record descriptor word at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:295
+#, c-format
+msgid "Corrupt record size at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:437
+msgid "Record exceeds remaining block length."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:511
 #, c-format
 msgid "Attempt to read beyond end-of-file on file %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:280
+#: src/language/data-io/data-reader.c:514
 msgid "Attempt to read beyond END DATA."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:438
+#: src/language/data-io/data-reader.c:679
 msgid ""
 "This command is not valid here since the current input program does not "
 "access the inline file."
 msgstr ""
 
-#: src/language/data-io/data-writer.c:72
+#: src/language/data-io/data-writer.c:74
 #, c-format
 msgid "An error occurred while opening \"%s\" for writing as a data file: %s."
 msgstr ""
 
-#: src/language/data-io/data-writer.c:150
+#: src/language/data-io/data-writer.c:191
 #, c-format
 msgid "I/O error occurred writing data file \"%s\"."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:65
+#: src/language/data-io/file-handle.q:64
 #, c-format
 msgid ""
 "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining "
 "a file handle."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:97
+#: src/language/data-io/file-handle.q:119
+msgid "RECFORM must be specified with MODE=360."
+msgstr ""
+
+#: src/language/data-io/file-handle.q:130
 #, c-format
-msgid ""
-"Fixed-length records were specified on /RECFORM, but record length was not "
-"specified on /LRECL.  Assuming %zu-character records."
+msgid "The specified file mode requires LRECL.  Assuming %d-character records."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:102
+#: src/language/data-io/file-handle.q:134
 #, c-format
 msgid ""
-"Record length (%ld) must be at least one byte.  Assuming %zu-character "
+"Record length (%ld) must be between 1 and %lu bytes.  Assuming %d-character "
 "records."
 msgstr ""
 
-#: src/language/data-io/file-handle.q:147
+#: src/language/data-io/file-handle.q:176
 msgid "file"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:149
+#: src/language/data-io/file-handle.q:178
 msgid "inline file"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:175
+#: src/language/data-io/file-handle.q:204
 msgid "expecting a file name or handle name"
 msgstr ""
 
-#: src/language/data-io/file-handle.q:195
+#: src/language/data-io/file-handle.q:224
 #, c-format
 msgid "Handle for %s not allowed here."
 msgstr ""
 
+#: src/language/data-io/get-data.c:48
+#, c-format
+msgid "Unsupported TYPE %s"
+msgstr ""
+
 #: src/language/data-io/get.c:106
 msgid "expecting COMM or TAPE"
 msgstr ""
@@ -1327,7 +1345,7 @@ msgstr ""
 msgid "expecting %s or %s"
 msgstr ""
 
-#: src/language/data-io/get.c:513 src/language/data-io/print.c:176
+#: src/language/data-io/get.c:513 src/language/data-io/print.c:177
 msgid "expecting a valid subcommand"
 msgstr ""
 
@@ -1406,11 +1424,6 @@ msgid ""
 "variable in earlier file (%s)."
 msgstr ""
 
-#: src/language/data-io/get-data.c:48
-#, c-format
-msgid "Unsupported TYPE %s"
-msgstr ""
-
 #: src/language/data-io/inpt-pgm.c:129
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr ""
@@ -1428,39 +1441,39 @@ msgid ""
 "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:156 src/language/stats/descriptives.c:362
+#: src/language/data-io/list.q:157 src/language/stats/descriptives.c:362
 msgid "No variables specified."
 msgstr ""
 
-#: src/language/data-io/list.q:164
+#: src/language/data-io/list.q:165
 #, c-format
 msgid ""
 "The first case (%ld) specified precedes the last case (%ld) specified.  The "
 "values will be swapped."
 msgstr ""
 
-#: src/language/data-io/list.q:172
+#: src/language/data-io/list.q:173
 #, c-format
 msgid ""
 "The first case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:178
+#: src/language/data-io/list.q:179
 #, c-format
 msgid ""
 "The last case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:184
+#: src/language/data-io/list.q:185
 #, c-format
 msgid "The step value %ld is less than 1.  The value is being reset to 1."
 msgstr ""
 
-#: src/language/data-io/list.q:210
+#: src/language/data-io/list.q:211
 msgid "`/FORMAT WEIGHT' specified, but weighting is not on."
 msgstr ""
 
-#: src/language/data-io/list.q:466
+#: src/language/data-io/list.q:467
 msgid "Line"
 msgstr ""
 
@@ -1504,39 +1517,39 @@ msgid ""
 "Data fields must be listed in order of increasing record number."
 msgstr ""
 
-#: src/language/data-io/print.c:261
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:476
+#: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
+msgid "expecting end of command"
+msgstr ""
+
+#: src/language/data-io/print-space.c:116
+msgid "The expression on PRINT SPACE evaluated to the system-missing value."
+msgstr ""
+
+#: src/language/data-io/print-space.c:119
+#, c-format
+msgid "The expression on PRINT SPACE evaluated to %g."
+msgstr ""
+
+#: src/language/data-io/print.c:265
 #, c-format
 msgid "Output calls for %d records but %zu specified on RECORDS subcommand."
 msgstr ""
 
-#: src/language/data-io/print.c:430
+#: src/language/data-io/print.c:434
 #, c-format
 msgid "Writing %d record to %s."
 msgid_plural "Writing %d records to %s."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print.c:434
+#: src/language/data-io/print.c:438
 #, c-format
 msgid "Writing %d record."
 msgid_plural "Writing %d records."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:476
-#: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
-msgid "expecting end of command"
-msgstr ""
-
-#: src/language/data-io/print-space.c:116
-msgid "The expression on PRINT SPACE evaluated to the system-missing value."
-msgstr ""
-
-#: src/language/data-io/print-space.c:119
-#, c-format
-msgid "The expression on PRINT SPACE evaluated to %g."
-msgstr ""
-
 #: src/language/dictionary/apply-dictionary.c:75
 #, c-format
 msgid "Variable %s is %s in target file, but %s in source file."
@@ -2295,11 +2308,11 @@ msgstr ""
 msgid "LO or LOWEST must be part of a range."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:106
+#: src/language/lexer/range-parser.c:107
 msgid "System-missing value is not valid here."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:114
+#: src/language/lexer/range-parser.c:115
 msgid "expecting number or data string"
 msgstr ""
 
@@ -3038,73 +3051,73 @@ msgstr ""
 msgid "Tukey's Hinges"
 msgstr ""
 
-#: src/language/stats/flip.c:95
+#: src/language/stats/flip.c:96
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/stats/flip.c:150
+#: src/language/stats/flip.c:151
 msgid "Could not create temporary file for FLIP."
 msgstr ""
 
-#: src/language/stats/flip.c:161
+#: src/language/stats/flip.c:162
 #, c-format
 msgid "Error writing FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:261
+#: src/language/stats/flip.c:262
 #, c-format
 msgid "Could not create acceptable variant for variable %s."
 msgstr ""
 
-#: src/language/stats/flip.c:277
+#: src/language/stats/flip.c:278
 msgid "Cannot create more than 99999 variable names."
 msgstr ""
 
-#: src/language/stats/flip.c:393
+#: src/language/stats/flip.c:394
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:400
+#: src/language/stats/flip.c:401
 msgid "Error creating FLIP source file."
 msgstr ""
 
-#: src/language/stats/flip.c:413
+#: src/language/stats/flip.c:414
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:415
+#: src/language/stats/flip.c:416
 msgid "Unexpected end of file reading FLIP file."
 msgstr ""
 
-#: src/language/stats/flip.c:431
+#: src/language/stats/flip.c:432
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:439
+#: src/language/stats/flip.c:440
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:450
+#: src/language/stats/flip.c:451
 #, c-format
 msgid "Error closing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:458
+#: src/language/stats/flip.c:459
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:487
+#: src/language/stats/flip.c:488
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:490
+#: src/language/stats/flip.c:491
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr ""
 
@@ -3191,11 +3204,11 @@ msgstr ""
 msgid "Multivariate GLM not yet supported"
 msgstr ""
 
-#: src/language/stats/glm.q:271 src/language/stats/regression.q:1165
+#: src/language/stats/glm.q:271 src/language/stats/regression.q:1164
 msgid "Dependent variable must be numeric."
 msgstr ""
 
-#: src/language/stats/glm.q:346 src/language/stats/regression.q:1262
+#: src/language/stats/glm.q:346 src/language/stats/regression.q:1261
 msgid "No valid data found. This command was skipped."
 msgstr ""
 
@@ -3207,6 +3220,22 @@ msgstr ""
 msgid "TABLES subcommand may not appear more than once."
 msgstr ""
 
+#: src/language/stats/npar-summary.c:108
+msgid "Descriptive Statistics"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:145
+msgid "25th"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:148
+msgid "50th (Median)"
+msgstr ""
+
+#: src/language/stats/npar-summary.c:151
+msgid "75th"
+msgstr ""
+
 #: src/language/stats/npar.q:98
 msgid "NPAR subcommand not currently implemented."
 msgstr ""
@@ -3231,22 +3260,6 @@ msgid ""
 "not match the number following (%zu)."
 msgstr ""
 
-#: src/language/stats/npar-summary.c:108
-msgid "Descriptive Statistics"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:145
-msgid "25th"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:148
-msgid "50th (Median)"
-msgstr ""
-
-#: src/language/stats/npar-summary.c:151
-msgid "75th"
-msgstr ""
-
 #: src/language/stats/oneway.q:169
 msgid "Number of contrast coefficients must equal the number of groups"
 msgstr ""
@@ -3342,56 +3355,56 @@ msgstr ""
 msgid "Does not assume equal"
 msgstr ""
 
-#: src/language/stats/rank.q:220
+#: src/language/stats/rank.q:221
 #, c-format
 msgid "%s of %s by %s"
 msgstr ""
 
-#: src/language/stats/rank.q:225
+#: src/language/stats/rank.q:226
 #, c-format
 msgid "%s of %s"
 msgstr ""
 
-#: src/language/stats/rank.q:601
+#: src/language/stats/rank.q:602
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr ""
 
-#: src/language/stats/rank.q:694
+#: src/language/stats/rank.q:695
 msgid "Variables Created By RANK"
 msgstr ""
 
-#: src/language/stats/rank.q:718
+#: src/language/stats/rank.q:719
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:729
+#: src/language/stats/rank.q:730
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:743
+#: src/language/stats/rank.q:744
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:753
+#: src/language/stats/rank.q:754
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:766
+#: src/language/stats/rank.q:767
 msgid ""
 "FRACTION has been specified, but NORMAL and PROPORTION rank functions have "
 "not been requested.  The FRACTION subcommand will be ignored."
 msgstr ""
 
-#: src/language/stats/rank.q:859
+#: src/language/stats/rank.q:860
 #, c-format
 msgid "Variable %s already exists."
 msgstr ""
 
-#: src/language/stats/rank.q:864
+#: src/language/stats/rank.q:865
 msgid "Too many variables in INTO clause."
 msgstr ""
 
@@ -3873,44 +3886,44 @@ msgstr ""
 msgid "Destination cannot be a string variable."
 msgstr ""
 
-#: src/language/xforms/recode.c:245
+#: src/language/xforms/recode.c:246
 msgid ""
 "Inconsistent target variable types.  Target variables must be all numeric or "
 "all string."
 msgstr ""
 
-#: src/language/xforms/recode.c:266
+#: src/language/xforms/recode.c:267
 msgid "CONVERT requires string input values and numeric output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:316
+#: src/language/xforms/recode.c:317
 msgid "THRU is not allowed with string variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:390
+#: src/language/xforms/recode.c:391
 msgid "expecting output value"
 msgstr ""
 
-#: src/language/xforms/recode.c:439
+#: src/language/xforms/recode.c:440
 #, c-format
 msgid ""
 "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same "
 "number of variables as source and target variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:454
+#: src/language/xforms/recode.c:455
 #, c-format
 msgid ""
 "There is no variable named %s.  (All string variables specified on INTO must "
 "already exist.  Use the STRING command to create a string variable.)"
 msgstr ""
 
-#: src/language/xforms/recode.c:469
+#: src/language/xforms/recode.c:470
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:482
+#: src/language/xforms/recode.c:483
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr ""
@@ -3941,23 +3954,23 @@ msgstr ""
 msgid "hash table:"
 msgstr ""
 
-#: src/math/percentiles.c:40
+#: src/math/percentiles.c:41
 msgid "HAverage"
 msgstr ""
 
-#: src/math/percentiles.c:41
+#: src/math/percentiles.c:42
 msgid "Weighted Average"
 msgstr ""
 
-#: src/math/percentiles.c:42
+#: src/math/percentiles.c:43
 msgid "Rounded"
 msgstr ""
 
-#: src/math/percentiles.c:43
+#: src/math/percentiles.c:44
 msgid "Empirical"
 msgstr ""
 
-#: src/math/percentiles.c:44
+#: src/math/percentiles.c:45
 msgid "Empirical with averaging"
 msgstr ""
 
@@ -4976,7 +4989,7 @@ msgstr ""
 msgid "Options:"
 msgstr ""
 
-#: src/ui/gui/find-dialog.c:657
+#: src/ui/gui/find-dialog.c:658
 #, c-format
 msgid "Bad regular expression: %s"
 msgstr ""
@@ -5142,10 +5155,6 @@ msgstr ""
 msgid "Paste"
 msgstr ""
 
-#: src/ui/gui/psppire.c:197
-msgid "_Reset"
-msgstr ""
-
 #: src/ui/gui/psppire-data-store.c:816
 msgid "var"
 msgstr ""
@@ -5155,6 +5164,28 @@ msgstr ""
 msgid "%ld"
 msgstr ""
 
+#: src/ui/gui/psppire-var-store.c:479 src/ui/gui/var-display.c:14
+msgid "None"
+msgstr ""
+
+#: src/ui/gui/psppire-var-store.c:489
+msgid "Scientific"
+msgstr ""
+
+#: src/ui/gui/psppire-var-store.c:492
+msgid "Custom"
+msgstr ""
+
+#: src/ui/gui/psppire-var-store.c:563 src/ui/gui/psppire-var-store.c:573
+#: src/ui/gui/psppire-var-store.c:583
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/ui/gui/psppire.c:198
+msgid "_Reset"
+msgstr ""
+
 #: src/ui/gui/psppire.glade:11
 msgid "This is pre-alpha software.  Use at your own risk."
 msgstr ""
@@ -5382,24 +5413,6 @@ msgstr ""
 msgid "Search backward"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:479 src/ui/gui/var-display.c:14
-msgid "None"
-msgstr ""
-
-#: src/ui/gui/psppire-var-store.c:489
-msgid "Scientific"
-msgstr ""
-
-#: src/ui/gui/psppire-var-store.c:492
-msgid "Custom"
-msgstr ""
-
-#: src/ui/gui/psppire-var-store.c:563 src/ui/gui/psppire-var-store.c:573
-#: src/ui/gui/psppire-var-store.c:583
-#, c-format
-msgid "%d"
-msgstr ""
-
 #: src/ui/gui/rank.glade:111
 msgid "By:"
 msgstr ""
@@ -5556,6 +5569,11 @@ msgstr ""
 msgid "To End"
 msgstr ""
 
+#: src/ui/gui/t-test-independent-samples-dialog.c:175
+#, c-format
+msgid "Confidence Interval: %2d %%"
+msgstr ""
+
 #: src/ui/gui/t-test.glade:56
 msgid "Define Groups"
 msgstr ""
@@ -5588,9 +5606,24 @@ msgstr ""
 msgid "Exclude cases _listwise"
 msgstr ""
 
-#: src/ui/gui/t-test-independent-samples-dialog.c:175
-#, c-format
-msgid "Confidence Interval: %2d %%"
+#: src/ui/gui/var-sheet.c:65
+msgid "Name"
+msgstr ""
+
+#: src/ui/gui/var-sheet.c:68
+msgid "Decimals"
+msgstr ""
+
+#: src/ui/gui/var-sheet.c:70
+msgid "Values"
+msgstr ""
+
+#: src/ui/gui/var-sheet.c:73
+msgid "Align"
+msgstr ""
+
+#: src/ui/gui/var-sheet.c:74
+msgid "Measure"
 msgstr ""
 
 #: src/ui/gui/variable-info-dialog.c:88
@@ -5622,26 +5655,6 @@ msgstr ""
 msgid "%s %s\n"
 msgstr ""
 
-#: src/ui/gui/var-sheet.c:65
-msgid "Name"
-msgstr ""
-
-#: src/ui/gui/var-sheet.c:68
-msgid "Decimals"
-msgstr ""
-
-#: src/ui/gui/var-sheet.c:70
-msgid "Values"
-msgstr ""
-
-#: src/ui/gui/var-sheet.c:73
-msgid "Align"
-msgstr ""
-
-#: src/ui/gui/var-sheet.c:74
-msgid "Measure"
-msgstr ""
-
 #: src/ui/gui/weight-cases-dialog.c:88
 #, c-format
 msgid "Weight cases by %s"
index 7ddf9fd280b87705dea1bbf3fa4d8387447aec69..05bafc37136fcb5cb1332e48ac91e3880b324523 100644 (file)
@@ -1,3 +1,80 @@
+2007-11-10  Ben Pfaff  <blp@gnu.org>
+
+       Cleanups and bug fixes devised while writing up documentation.
+       Patch #6262.
+
+       * automake.mk (src_data_libdata_a_SOURCES): Add new files.
+
+       * dict-class.c: New file.
+       (dict_class_from_id): Move here.
+       (dict_class_to_name): Move here.
+
+       * dict-class.h: New file.
+       (enum dict_class): Move here.  Change from consecutive integers to
+       consecutive bits, to make testing for any of multiple values
+       easier.  Add new DC_ALL constant.
+
+       * dictionary.c (struct dictionary): Change `case_limit' from
+       size_t to casenumber.
+       (dict_get_vars): Make final argument an enum dict_class.
+       (dict_get_vars_mutable): Ditto.
+       (dict_get_case_limit): Change return value to casenumber.
+       (dict_set_case_limit): Change final argument to a casenumber.
+       (dict_unset_split_var): Add assertion.  Rephrase slightly.
+       (dict_set_label): Use xstrndup to simplify.
+
+       * format.c (fmt_step_width): AHEX format also needs 2-byte
+       stepping.
+       (fmt_set_style): Simplify assertions.
+
+       * missing-values.c (mv_add_num_range): Rename mv_add_range.
+       Simplify implementation.
+       (mv_has_value): Simplify implementation.
+       (mv_pop_value): Remove the first value, not the last, to avoid
+       having GET followed by SAVE reverse the order of missing values.
+       (mv_peek_value): Rename mv_get_value.  Simplify assertion.
+       (mv_has_range): Simplify implementation.
+       (mv_peek_range): Rename mv_get_range.
+       (can_resize_string): Removed.
+       (mv_is_resizable): Use value_is_resizable.
+       (mv_resize): Use value_resize.
+
+       * short-names.h (SHORT_NAME_LEN): Move here.
+
+       * val-type.h: New file, for definitions related to type and width
+       of abstract values.  Before, these definitions were mixed among
+       those related to "union value" and those related to variables.
+       (macro SYSMIS): Move here.
+       (macro LOWEST): Move here.
+       (macro HIGHEST): Move here.
+       (macro MAX_STRING); Move here.
+       (enum val_type): New enum with values VAL_NUMERIC and VAL_STRING.
+       Replaces enum var_type that had values VAR_NUMERIC and VAR_STRING.
+       All references updated.
+       (val_type_is_valid): New function.  Replaces var_type_is_valid.
+       All references updated.
+       (val_type_from_width): New function.  Replaces
+       var_type_from_width.  All references updated.
+
+       * value-labels.c (val_labs_copy): Renamed val_labs_clone.  All
+       references updated.
+       (val_labs_can_set_width): Use value_is_resizable.
+       (val_labs_add): Simply return false if the value labels set is too
+       wide, instead of having undefined behavior.
+       (val_labs_replace): Ditto.
+       (val_labs_replace): Ditto.
+       (val_labs_first): Set iterator to null if iteration is complete.
+       (val_labs_first_sorted): Ditto.
+       (val_labs_done): Become a no-op if the iterator is null.
+
+       * value.c (value_is_resizable): New function.
+       (value_resize): New function.
+
+       * variable.c (var_get_dict_class): New function.
+
+       * variable.h (macro LONG_NAME_LEN): Rename VAR_NAME_LEN.  Update
+       all references.
+
 2007-11-08  Ben Pfaff  <blp@gnu.org>
 
        * data-in.c: Make formatted data parsing locale-independent.
index 112dc3b071d124d9db59baaf42eb6d499103f8b0..dc28a7f87112f4c521c1a39498fc4aaccaddeb6b 100644 (file)
@@ -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 7330b1a659621d850d4acf9d78ec8fd968bb97e9..ac37f86987341d7085d01990ba947ab1cd9cdecb 100644 (file)
@@ -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 10963a6e7bbe8cd211843e5b00e12d4e0f22c228..aa5b9dd0d7c99397ebcb00c7ef908f6ee6a4d719 100644 (file)
@@ -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 ccase *, const struct ccase *,
 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 198128863bebec7e502d3e308600965905d50320..d66b1c644903cd9795821c03e2ad71da453eea71 100644 (file)
    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 integer_format);
 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 02ff06572fabcb1f282c2b9aa51319ee32ae0850..26abc7cc112a9897f1ebf4b928a429000ed67b5a 100644 (file)
 #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"
diff --git a/src/data/dict-class.c b/src/data/dict-class.c
new file mode 100644 (file)
index 0000000..c79b29a
--- /dev/null
@@ -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 ();
+    }
+}
diff --git a/src/data/dict-class.h b/src/data/dict-class.h
new file mode 100644 (file)
index 0000000..e3872e8
--- /dev/null
@@ -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 0f3e25e3285d0ac76fe6814c1a29436ed5ac196c..94a0292e17b54d878b69e6d37539118cff47b6e2 100644 (file)
@@ -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, size_t idx)
   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 dictionary *d, struct variable ***vars,
   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 dictionary *d, struct variable ***vars,
   *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_t from, size_t to)
    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 dictionary *d)
   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 *d)
   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, struct variable *v)
 {
   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, struct variable *v)
 
 /* 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 dictionary *d)
 /* 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 dictionary *d, unsigned int exclude_classes)
   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 dictionary *d)
   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, const char *label)
   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 581a49d827614a56277dd65cf7564addc9a0f49b..167487fbd10a34182ed5457c62a7770262c8e794 100644 (file)
    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 54c6281716b5025d0c23ebd47a9ed9cf1e203bfb..c90ff95b6f5fc51a486b58cd1f10c6ce2ce07220 100644 (file)
@@ -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 *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_spec *format, enum var_type var_type)
 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_spec *format, int width)
   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 type, int width)
 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, struct fmt_number_style *style)
   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 fbaf062558aab7e5704cbc190da9fe6577c651ee..d00cb1d9eefc1ea46e3c2166afcf601475da379d 100644 (file)
    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_FUNCTION;
 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 *);
 \f
@@ -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 c4d40baae13c0c25c23d9bdd3226837a6c438844..07ebb77a17312a388ced25b3f04e2ae4f4f0fea5 100644 (file)
@@ -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, double 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 *mv, double low, double high)
 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 *mv)
 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, double *low, double *high)
   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 4f87f54360ff3aa19616489ef1c9a0848a219620..b504f8c769a928be238ce8d161a8cf577dbee051 100644 (file)
    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 ce1f562f4f9389f323acacdeff5f606e289f68a7..b5486a4a0e3dcfa1ee795869b46a2922fe03b725 100644 (file)
@@ -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, struct dictionary *dict)
           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, struct dictionary *dict)
         {
           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 e446a659b907e14680e9cf20e0f2415ea201436a..278077e7db93bf3e8786308c85adcac9fe55f78a 100644 (file)
@@ -664,10 +664,10 @@ static trns_free_func case_limit_trns_free;
 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 d5bbb205f517bb245c3d75ad32b148a2da7adae8..2bce53e98c246aa60792912dda462d214e7c3491 100644 (file)
@@ -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 b00a7b236a891e97a6752eb9a748d50692e3965c..1d172adefd46a65d9751832ffc10a7df3cf90efc 100644 (file)
@@ -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, struct dictionary **dict,
       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 *r, struct dictionary *dict,
             {
               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 3e0d3499c9cd543450929e1b5dbb628552bc6640..acf9d5c0b681d4d702a52b81b6798bc93a54358c 100644 (file)
@@ -445,14 +445,14 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   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);
     }
 
diff --git a/src/data/val-type.h b/src/data/val-type.h
new file mode 100644 (file)
index 0000000..27139af
--- /dev/null
@@ -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 b9acc2bda59ffb8a199efafc425a852afb2ec55f..6387f72fc44d4c321d4857cf7194e35bd794c3ce 100644 (file)
@@ -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 *vls)
   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;
+  struct val_labs_iterator *i;
+  struct val_lab *lab;
 
-  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))
+    if (!value_is_resizable (&lab->value, vls->width, new_width))
+      {
+        val_labs_done (&i);
+        return false;
+      }
 
-      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;
+  return true;
 }
 
-/* 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. */
+/* 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, union value value, const char *label)
   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->width < MIN_LONG_STRING)
+    {
+      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);
+      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;
+      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 *vls, struct val_labs_iterator **ip)
   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_labs *vls,
   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 *vls, struct val_labs_iterator **ip)
 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;
+    }
 }
 \f
 /* Compares two value labels and returns a strcmp()-type result. */
index ce863a40db82df3aec7eb22653773e8358d12f49..fb7ec22b57564a922562fa2c46acc557532bc6d5 100644 (file)
    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 struct val_labs *,
                                struct val_labs_iterator **);
 void val_labs_done (struct val_labs_iterator **);
 
-#endif /* value-labels.h */
+#endif /* data/value-labels.h */
index cd52f147ca3a0f4fd924c40861788cfc22081623..34e3fe58bb37bf40d80943d38fc4d5ecafdc76d2 100644 (file)
@@ -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 width)
   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 b7a7ee701f8ae31f695e35629ca26b562b853842..cb66cb0836c7b00eeb7e992199650c192b15f780 100644 (file)
@@ -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
    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 aaf8ba05e6573e9658640b4032402099d5365b87..35440a0de644af2fbeb3a407d7da837fe97aca1d 100644 (file)
@@ -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 4a2e44057c70c23aeff99d17ee206cc205ad5105..4623b77b13a9f65ddcab64565898dcfc390c4cc5 100644 (file)
@@ -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;
-}
 \f
 /* 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, bool issue_error)
         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, bool issue_error)
   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_, const void *aux UNUSED)
 }
 \f
 /* 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 new_width)
 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, const struct val_labs *vls)
   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, enum alignment alignment)
    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 leave)
 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;
 }
 \f
 /* Returns the number of short names stored in VAR.
@@ -960,7 +953,8 @@ var_get_obs_vals (const struct variable *v)
   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 *v)
   return v->obs_vals != NULL;
 }
 \f
-/* 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 ();
-    }
-}
-\f
 /* Returns V's vardict structure. */
 const struct vardict_info *
 var_get_vardict (const struct variable *v)
index 44cfba703fe56a162f9bd6f418cb311df95c27d1..66257e0e16437a72867df05db9b6c5b3e63e6c36 100644 (file)
    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 *, 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 variable *, double, enum mv_class);
 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 struct variable *);
 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 cc4c96f0ab8744538fafb4e4e35d9dd1e99bf832..fd65d284d43ea6d75d1db2885f1b9ad87d37bce9 100644 (file)
@@ -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 *vector)
 }
 
 /* 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 0f4359826c5c3d22b331d0dbb0109d1fba4c3488..b009fcb2922f3ac4c7a67422e2089cef1311c5bf 100644 (file)
@@ -30,7 +30,7 @@ struct vector *vector_clone (const struct vector *old,
 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 4fea7a407038364aca731376c6c86d11d9e66caf..9e950e9ce69bd24799660908606a308962282e84 100644 (file)
@@ -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 35fabc08842a25dc79453f3597853ded2df2620f..af5fa3321fdfa2b25972cf0691bb3539bce2b689 100644 (file)
@@ -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 d22a4e50ddd93911a64b514ea61bc76fa4eb0692..ed490cedda625e8254680334b491b4c0282de0d8 100644 (file)
@@ -735,8 +735,8 @@ cmd_match_files (struct lexer *lexer, struct dataset *ds)
   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 8b3eead83fb41c65ec697b74047a92cf4de44569..8e8bba9b69a281ae707cd021d2bd777e0176bf6f 100644 (file)
@@ -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 dataset *ds)
     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_driver *d)
          }
 
          {
-           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 3be32e76c62f8ed452c5630f29e582e07376816c..d18606a5ce2eda8e4d9508e406e7170f7c3d9231 100644 (file)
@@ -91,7 +91,7 @@ internal_cmd_formats (struct lexer *lexer, struct dataset *ds, int which)
        }
       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 120953188ac87a2872b386430f06d668aebd5edc..d5bbf108832dc747fa6a9aec418898ac260bcea0 100644 (file)
@@ -88,7 +88,7 @@ cmd_missing_values (struct lexer *lexer, struct dataset *ds)
 
                   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 9fc6fa55c452c3a03ffeba7e7e6633c376f48bc2..cd5016910d61242c0c6afa8698a8f43553d38308 100644 (file)
@@ -138,7 +138,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
                           "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 void *a_, const void *b_,
 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 e61ee53a44ce3f04c87d356c065c7c5198cab13c..1a616ab27ad858170f96ae7e99af12a91fe79c31 100644 (file)
@@ -135,7 +135,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
                   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 dataset *ds)
             }
 
          /* 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 dataset *ds)
               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 52dafef8c62edd7a939feb6735e18e0e798b1d23..a0a133ad66ebd8d483e97e57c86ecf87b5fef6b9 100644 (file)
@@ -126,7 +126,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
         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 5ae4994484c685362d2daa689e79544c78a9f140..40b0a7ab53c1be8b25b515c021f244551e2002e7 100644 (file)
@@ -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 *lexer, struct expression *e)
       || !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 79657df7d52793ec2b9cc8f385947de13bac3203..ac0af60005edc2e97f3c7c491309ceca51af8a10 100644 (file)
@@ -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 3778156133d38daaadf13251ab568df32ab190fe..1194110efa3ac850ed1584451e2782ec12870b83 100644 (file)
@@ -405,8 +405,8 @@ parse_DATA_LIST_vars (struct lexer *lexer, char ***names, size_t *nnames, int pv
   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 *lexer, char ***names, size_t *nnames, int pv
 
          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_set *vs, const char *name,
 {
   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 18d78f238ae1f3038168cad0538d119c8903a0c5..f58b97cf8994c4eebcef4509c5cc1b8267f7f871 100644 (file)
@@ -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_tab[] =
     {"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 *lexer, const struct dictionary *dict, s
                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 *lexer, const struct dictionary *dict, s
                    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 e1ca73bb3111e0b1e0c2a4b7a3d3ebb3ad0f7ec0..72f7476ae4e89fbc42c6ebe340c134b9b0353b2d 100644 (file)
@@ -123,7 +123,7 @@ static const struct dsc_statistic_info dsc_info[DSC_N_STATS] =
 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 3fe43eb90858993a54b0f23bb6dc2ea07265c28f..6c49bd3798e5376555dd785ca85bab6ef61c7469 100644 (file)
@@ -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 dataset *ds)
       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 ce313678db2591d78dc6ab186cb8f8f48beb5aae..fdb19b0391f9c23dec4e036217e40b9bfa6af466 100644 (file)
@@ -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 91520f5e011e2bbe2e4c819bb2ec830a7c8ec4d4..5bc88c4a97a84fe91aabf77fc897df9e30e4a9bf 100644 (file)
 #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 e3b3f5ee9338b37ff671c55bce0cb83063129881..12a7cf5efca6ed103957768c9032bec9d1f611aa 100644 (file)
@@ -637,16 +637,16 @@ try_name (const struct dictionary *dict, const char *name)
 }
 
 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 char *prefix, trns_proc_func * f,
 {
   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, struct cmd_regression *cmd,
 
   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 23237072c4651a24868e411fa60fb355b667b78d..c0e90705c3e1fae05af88fcfab7244226697f246 100644 (file)
@@ -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, struct dataset *ds, struct cmd_t_test *cm
 /* 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 ec5a15a1f33f2a9d12f53cbd42e7d3c334ebbafe..f17798f77722a35cb2597a82f5ecaea4ccfcced7 100644 (file)
@@ -258,7 +258,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds)
 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 1cb29b8440ab5c1eb51d806b3996ebc2bb1b2895..85fcb9ea01f72bd8ece9ecc8b76807c96910daba 100644 (file)
@@ -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_trns *,
                          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 dataset *ds)
 
       /* 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, struct recode_trns *trns)
     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, struct recode_trns *trns)
 
           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, struct recode_trns *trns)
           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, struct recode_trns *trns)
    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, struct recode_trns *trns,
         {
           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, struct recode_trns *trns,
         {
           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, struct recode_trns *trns,
         {
           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 ccase *c, casenumber case_idx UNUSED)
 
       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 1026aa9c9bafd6e1ccfdb1326ead297c64b79803..cb51c485df27ae983104b7540888c1b6492bb16d 100644 (file)
@@ -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 1b91e84eb717296c5bbf1e57fe1477ab52f1b207..582b83468ca77f2516dc42b248e2dd6a8359fd44 100644 (file)
@@ -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 a5be12e9cd0d53a108cd91ea98b3d85bd6daf4f3..084e6d8c8b22f24c469212fec682080c204da6d9 100644 (file)
@@ -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 5c36fc14b1fcbfa2d4a48f308f61ad89b8ab5cab..aa7eead6c03980d9b1dc2bafca96777341678351 100644 (file)
@@ -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 3a350735b99f17bf207bc0b5c7221f107a1c57af..576701c127e6b51eff28c9730a7bbd773c96c653 100644 (file)
@@ -148,7 +148,7 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
        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_val_dialog *dialog)
       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_val_dialog *dialog)
        {
          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_val_dialog *dialog)
              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 05068d0f964523a91df558a58230c8c928ebcb56..7e558eec3f8fb62fe5cf88fda95fda02a5ebc890 100644 (file)
@@ -519,7 +519,7 @@ val_labs_dialog_show (struct val_labs_dialog *dialog)
   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 114156d7476a09e098f8ba9d34be4713bdc232a8..62c3eeee7e763e0747041723750d9a73fbdfdf18 100644 (file)
@@ -63,7 +63,7 @@ missing_values_to_string (const struct variable *pv, GError **err)
          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 variable *pv, GError **err)
          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 variable *pv, GError **err)
            {
              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 dfdd895f6192f9964bda5785b02748d85441fe29..bee65de8edc44e7febee965eeb030562f6f30c71 100644 (file)
@@ -790,14 +790,14 @@ on_var_type_ok_clicked (GtkWidget *w, gpointer data)
     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;