fix more tests
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 5 Jul 2025 17:53:41 +0000 (10:53 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 5 Jul 2025 17:53:41 +0000 (10:53 -0700)
18 files changed:
rust/pspp/src/dictionary.rs
rust/pspp/src/format/display/mod.rs
rust/pspp/src/sys/cooked.rs
rust/pspp/src/sys/raw.rs
rust/pspp/src/sys/testdata/bad_very_long_string_segment_width.expected
rust/pspp/src/sys/testdata/duplicate_attribute_name.expected
rust/pspp/src/sys/testdata/duplicate_value_labels_type.expected
rust/pspp/src/sys/testdata/missing_attribute_value.expected
rust/pspp/src/sys/testdata/missing_type_4_record.expected
rust/pspp/src/sys/testdata/too_many_value_labels.expected
rust/pspp/src/sys/testdata/type_4_record_names_long_string_variable.expected
rust/pspp/src/sys/testdata/unquoted_attribute_value.expected
rust/pspp/src/sys/testdata/value_label_variable_indexes_must_be_in_correct_range.expected
rust/pspp/src/sys/testdata/value_label_variable_indexes_must_not_be_long_string_continuation.expected
rust/pspp/src/sys/testdata/value_label_with_no_associated_variables.expected
rust/pspp/src/sys/testdata/value_label_with_no_associated_variables.sack
rust/pspp/src/sys/testdata/variables_for_value_label_must_all_be_same_type.expected
tests/data/sys-file-reader.at

index 55a795fd1ac97934e29b2ed7088f9ed41e9114c1..cf416f5a79380a0a82037524ed5b8ac2b1d2ee89 100644 (file)
@@ -1066,6 +1066,14 @@ impl Attributes {
         Self(BTreeMap::new())
     }
 
+    pub fn contains_name(&self, name: &Identifier) -> bool {
+        self.0.contains_key(name)
+    }
+
+    pub fn insert(&mut self, name: Identifier, values: Vec<String>) {
+        self.0.insert(name, values);
+    }
+
     pub fn append(&mut self, other: &mut Self) {
         self.0.append(&mut other.0)
     }
index 7f259b94ee672cd0fdc821df2d595d0f34f1ca54..6fcce1791b3821087c57f3b5916cd2fd3d9cb8b7 100644 (file)
@@ -25,6 +25,15 @@ pub struct DisplayDatum<'a, 'b> {
     endian: EndianSettings,
     datum: &'a Datum,
     encoding: &'static Encoding,
+
+    /// If true, the output will remove leading and trailing spaces from numeric
+    /// values, and trailing spaces from string values.  (This might make the
+    /// output narrower than the requested width.)
+    trim_spaces: bool,
+
+    /// If true, the output will include a double quote before and after string
+    /// values.
+    quote_strings: bool,
 }
 
 #[cfg(test)]
@@ -118,11 +127,14 @@ impl Display for DisplayDatum<'_, '_> {
                         write!(f, "{byte:02x}")?;
                     }
                 } else {
-                    write!(
-                        f,
-                        "{}",
-                        self.encoding.decode_without_bom_handling(&string.0).0
-                    )?;
+                    let quote = if self.quote_strings { "\"" } else { "" };
+                    let s = self.encoding.decode_without_bom_handling(&string.0).0;
+                    let s = if self.trim_spaces {
+                        s.trim_end_matches(' ')
+                    } else {
+                        &s
+                    };
+                    write!(f, "{quote}{s}{quote}")?;
                 }
                 return Ok(());
             }
@@ -176,6 +188,8 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
             encoding,
             settings: &settings.formats,
             endian: settings.endian,
+            trim_spaces: false,
+            quote_strings: false,
         }
     }
     pub fn with_settings(self, settings: &'b Settings) -> Self {
@@ -184,6 +198,18 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
     pub fn with_endian(self, endian: EndianSettings) -> Self {
         Self { endian, ..self }
     }
+    pub fn with_trimming(self) -> Self {
+        Self {
+            trim_spaces: true,
+            ..self
+        }
+    }
+    pub fn with_quoted_string(self) -> Self {
+        Self {
+            quote_strings: true,
+            ..self
+        }
+    }
     fn fmt_binary(&self, f: &mut Formatter) -> FmtResult {
         let output = self.to_binary().unwrap();
         for b in output {
@@ -226,7 +252,7 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
             } else {
                 "Unknown"
             };
-            let w = self.format.w();
+            let w = if self.trim_spaces { 0 } else { self.format.w() };
             write!(f, "{s:>0$.*}", w)
         } else {
             self.overflow(f)
@@ -240,6 +266,10 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
             _ => (),
         }
 
+        if self.trim_spaces {
+            return write!(f, ".");
+        }
+
         let w = self.format.w() as isize;
         let d = self.format.d() as isize;
         let dot_position = match self.format.type_ {
@@ -261,8 +291,12 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
     }
 
     fn overflow(&self, f: &mut Formatter<'_>) -> FmtResult {
-        for _ in 0..self.format.w {
+        if self.trim_spaces {
             write!(f, "*")?;
+        } else {
+            for _ in 0..self.format.w {
+                write!(f, "*")?;
+            }
         }
         Ok(())
     }
@@ -311,8 +345,10 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
             // Assemble number.
             let magnitude = rounder.format(decimals as usize);
             let mut output = SmallString::<[u8; 40]>::new();
-            for _ in width..self.format.w() {
-                output.push(' ');
+            if !self.trim_spaces {
+                for _ in width..self.format.w() {
+                    output.push(' ');
+                }
             }
             if negative {
                 output.push_str(&style.neg_prefix.s);
@@ -346,7 +382,7 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
                 }
             }
 
-            debug_assert!(output.len() >= self.format.w());
+            debug_assert!(self.trim_spaces || output.len() >= self.format.w());
             debug_assert!(output.len() <= self.format.w() + style.extra_bytes);
             f.write_str(&output)?;
             return Ok(true);
@@ -386,8 +422,10 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
         width += fraction_width;
 
         let mut output = SmallString::<[u8; 40]>::new();
-        for _ in width..self.format.w() {
-            output.push(' ');
+        if !self.trim_spaces {
+            for _ in width..self.format.w() {
+                output.push(' ');
+            }
         }
         if number < 0.0 {
             output.push_str(&style.neg_prefix.s);
@@ -438,7 +476,7 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
             "{} for {number} width={width} fraction_width={fraction_width}: {output:?}",
             self.format
         );
-        debug_assert!(output.len() >= self.format.w());
+        debug_assert!(self.trim_spaces || output.len() >= self.format.w());
         debug_assert!(output.len() <= self.format.w() + style.extra_bytes);
         f.write_str(&output)?;
         Ok(true)
@@ -597,12 +635,20 @@ impl<'a, 'b> DisplayDatum<'a, 'b> {
                 _ => unreachable!(),
             }
         }
-        write!(f, "{:>1$}", &output, self.format.w())
+        if !self.trim_spaces {
+            write!(f, "{:>1$}", &output, self.format.w())
+        } else {
+            f.write_str(&output)
+        }
     }
 
     fn month(&self, f: &mut Formatter<'_>, number: f64) -> FmtResult {
         if let Some(month) = month_name(number as u32) {
-            write!(f, "{month:.*}", self.format.w())
+            if !self.trim_spaces {
+                write!(f, "{month:.*}", self.format.w())
+            } else {
+                f.write_str(month)
+            }
         } else {
             self.missing(f)
         }
index d864504bd5396ae90a70a60582dce55ba06f57fa..84d3123be3a8f70562028786a281688421d7e6bd 100644 (file)
@@ -27,6 +27,7 @@ use crate::{
 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
 use encoding_rs::Encoding;
 use indexmap::set::MutableValues;
+use itertools::Itertools;
 use thiserror::Error as ThisError;
 
 pub use crate::sys::raw::{CategoryLabels, Compression};
@@ -102,7 +103,7 @@ pub enum Error {
     },
 
     #[error(
-        "At offsets {:#x}...{:#x}, record types 3 and 4 may not add value labels to one or more long string variables: {variables:?}", .offsets.start, .offsets.end
+        "At offsets {:#x}...{:#x}, record types 3 and 4 may not add value labels to one or more long string variables: {}", .offsets.start, .offsets.end, variables.iter().join(", ")
     )]
     InvalidLongStringValueLabels {
         offsets: Range<u64>,
@@ -115,6 +116,12 @@ pub enum Error {
         string_var: Identifier,
     },
 
+    #[error("{variable} has duplicate value labels for the following value(s): {}", values.iter().join(", "))]
+    DuplicateValueLabels {
+        variable: Identifier,
+        values: Vec<String>,
+    },
+
     #[error("Invalid multiple response set name.  {0}")]
     InvalidMrSetName(IdError),
 
@@ -187,6 +194,15 @@ pub enum Error {
         len: usize,
     },
 
+    #[error("Variable with short name {short_name} listed in very long string record with width {width} has segment {index} of width {actual} (expected {expected}).")]
+    VeryLongStringInvalidSegmentWidth {
+        short_name: Identifier,
+        width: u16,
+        index: usize,
+        actual: usize,
+        expected: usize,
+    },
+
     #[error("Invalid variable name in long string value label record.  {0}")]
     InvalidLongStringValueLabelName(IdError),
 
@@ -783,15 +799,41 @@ pub fn decode(
             });
         }
 
+        let written_by_readstat = headers.header.eye_catcher.contains("ReadStat");
         for dict_index in dict_indexes {
             let variable = dictionary.variables.get_index_mut2(dict_index).unwrap();
+            let mut duplicates = Vec::new();
             for ValueLabel {
                 datum: value,
                 label,
             } in record.labels.iter().cloned()
             {
-                let value = value.decode(variable.width);
-                variable.value_labels.insert(value, label);
+                let datum = value.decode(variable.width);
+                if variable.value_labels.insert(datum, label).is_some() {
+                    duplicates.push(value);
+                }
+            }
+            if written_by_readstat {
+                // Ignore any possible duplicates.  ReadStat is buggy and emits
+                // value labels whose values are longer than string variables'
+                // widths, that are identical in the actual width of the
+                // variable, e.g. both values "ABC123" and "ABC456" for a string
+                // variable with width 3.
+            } else if !duplicates.is_empty() {
+                warn(Error::DuplicateValueLabels {
+                    variable: variable.name.clone(),
+                    values: duplicates
+                        .iter()
+                        .map(|value| {
+                            value
+                                .decode(variable.width)
+                                .display(variable.print_format, variable.encoding)
+                                .with_trimming()
+                                .with_quoted_string()
+                                .to_string()
+                        })
+                        .collect(),
+                });
             }
         }
     }
@@ -862,7 +904,13 @@ pub fn decode(
             short_names.push(segment.short_names[0].clone());
             let segment_width = segment.width.as_string_width().unwrap_or(0);
             if segment_width.next_multiple_of(8) != alloc_width.next_multiple_of(8) {
-                warn(dbg!(Error::TBD));
+                warn(Error::VeryLongStringInvalidSegmentWidth {
+                    short_name: record.short_name.clone(),
+                    width: record.length,
+                    index: i,
+                    actual: segment_width,
+                    expected: alloc_width,
+                });
                 continue 'outer;
             }
         }
@@ -1185,3 +1233,33 @@ impl MultipleResponseType {
         }
     }
 }
+
+/*
+trait Quoted {
+    fn quoted(self) -> WithQuotes<Self>
+    where
+        Self: Display + Sized;
+}
+
+impl<T> Quoted for T
+where
+    T: Display,
+{
+    fn quoted(self) -> WithQuotes<Self> {
+        WithQuotes(self)
+    }
+}
+
+struct WithQuotes<T>(T)
+where
+    T: Display;
+
+impl<T> Display for WithQuotes<T>
+where
+    T: Display,
+{
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "\"{}\"", &self.0)
+    }
+}
+*/
index 4fcd05562a76cbc4c42ce8c012a5d330d8169f45..50149caaea203f52bb6e3ab86b438605c3bbb358 100644 (file)
@@ -8,6 +8,7 @@ use crate::{
 
 use encoding_rs::{mem::decode_latin1, Encoding};
 use flate2::read::ZlibDecoder;
+use itertools::Itertools;
 use num::Integer;
 use std::{
     borrow::{Borrow, Cow},
@@ -257,11 +258,20 @@ pub enum Warning {
     #[error("Attribute record missing left parenthesis, in {0:?}.")]
     AttributeMissingLParen(String),
 
-    #[error("Attribute record missing new-line, in {0:?}.")]
-    AttributeMissingNewline(String),
+    #[error("Attribute for {name}[{}] lacks value.", index + 1)]
+    AttributeMissingValue { name: Identifier, index: usize },
 
-    #[error("Attribute record missing quotations, in {0:?}.")]
-    AttributeMissingQuotes(String),
+    #[error("Attribute for {name}[{}] missing quotations.", index + 1)]
+    AttributeMissingQuotes { name: Identifier, index: usize },
+
+    #[error("Duplicate attributes for variable {variable}: {}.", attributes.iter().join(", "))]
+    DuplicateVariableAttributes {
+        variable: Identifier,
+        attributes: Vec<Identifier>,
+    },
+
+    #[error("Duplicate dataset attributes with names: {}.", attributes.iter().join(", "))]
+    DuplicateFileAttributes { attributes: Vec<Identifier> },
 
     #[error("Compression bias is {0} instead of the usual values of 0 or 100.")]
     UnexpectedBias(f64),
@@ -1940,6 +1950,7 @@ impl ValueLabelRecord<RawStrArray<8>, RawString> {
                 max: Self::MAX_INDEXES,
             });
         } else if n == 0 {
+            dbg!();
             warn(Warning::NoVarIndexes {
                 offset: index_offset,
             });
@@ -2795,7 +2806,10 @@ impl Attribute {
         let mut values = Vec::new();
         loop {
             let Some((value, rest)) = input.split_once('\n') else {
-                return Err(Warning::AttributeMissingNewline(input.into()));
+                return Err(Warning::AttributeMissingValue {
+                    name: name.clone(),
+                    index: values.len(),
+                });
             };
             if let Some(stripped) = value
                 .strip_prefix('\'')
@@ -2803,7 +2817,10 @@ impl Attribute {
             {
                 values.push(stripped.into());
             } else {
-                decoder.warn(Warning::AttributeMissingQuotes(value.into()));
+                decoder.warn(Warning::AttributeMissingQuotes {
+                    name: name.clone(),
+                    index: values.len(),
+                });
                 values.push(value.into());
             }
             if let Some(rest) = rest.strip_prefix(')') {
@@ -2820,21 +2837,24 @@ impl Attributes {
         decoder: &mut Decoder,
         mut input: &'a str,
         sentinel: Option<char>,
-    ) -> Result<(Attributes, &'a str), Warning> {
+    ) -> Result<(Attributes, &'a str, Vec<Identifier>), Warning> {
         let mut attributes = BTreeMap::new();
+        let mut duplicates = Vec::new();
         let rest = loop {
             match input.chars().next() {
                 None => break input,
                 c if c == sentinel => break &input[1..],
                 _ => {
                     let (attribute, rest) = Attribute::parse(decoder, input)?;
-                    // XXX report duplicate name
+                    if attributes.contains_key(&attribute.name) {
+                        duplicates.push(attribute.name.clone());
+                    }
                     attributes.insert(attribute.name, attribute.values);
                     input = rest;
                 }
             }
         };
-        Ok((Attributes(attributes), rest))
+        Ok((Attributes(attributes), rest, duplicates))
     }
 }
 
@@ -2854,7 +2874,12 @@ impl RawFileAttributesRecord {
     fn decode(self, decoder: &mut Decoder) -> FileAttributesRecord {
         let input = decoder.decode(&self.0.text);
         match Attributes::parse(decoder, &input, None).issue_warning(&mut decoder.warn) {
-            Some((set, rest)) => {
+            Some((set, rest, duplicates)) => {
+                if !duplicates.is_empty() {
+                    decoder.warn(Warning::DuplicateFileAttributes {
+                        attributes: duplicates,
+                    });
+                }
                 if !rest.is_empty() {
                     decoder.warn(dbg!(Warning::TBD));
                 }
@@ -2883,7 +2908,13 @@ impl VarAttributes {
             .new_identifier(long_var_name)
             .and_then(Identifier::must_be_ordinary)
             .map_err(Warning::InvalidAttributeVariableName)?;
-        let (attributes, rest) = Attributes::parse(decoder, rest, Some('/'))?;
+        let (attributes, rest, duplicates) = Attributes::parse(decoder, rest, Some('/'))?;
+        if !duplicates.is_empty() {
+            decoder.warn(Warning::DuplicateVariableAttributes {
+                variable: long_var_name.clone(),
+                attributes: duplicates,
+            });
+        }
         let var_attribute = VarAttributes {
             long_var_name,
             attributes,
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75d706ab957fe742c2b92d69eb7db7f7fa2e4031 100644 (file)
@@ -0,0 +1,23 @@
+File header claims 1 variable positions but 34 were read from file.
+
+Variable with short name STR1 listed in very long string record with width 256 has segment 1 of width 9 (expected 4).
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭──────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│      │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├──────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1  │       1│     │Nominal          │Input│   32│Left     │A255        │A255        │              │
+│str1_a│       2│     │Nominal          │Input│    9│Left     │A9          │A9          │              │
+╰──────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8de0af1193a33196307b583e26037f2dbe654c4b 100644 (file)
@@ -0,0 +1,30 @@
+Duplicate dataset attributes with names: Attr1.
+
+Duplicate attributes for variable FIRSTVAR: fred.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│        │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭───────────────────────┬─────╮
+│Variable and Name      │Value│
+├───────────────────────┼─────┤
+│(dataset)         Attr1│value│
+├───────────────────────┼─────┤
+│firstvar          fred │23   │
+╰───────────────────────┴─────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e6416d44f3a5f90bba8580dcd447098fa91fc28b 100644 (file)
@@ -0,0 +1,31 @@
+STR1 has duplicate value labels for the following value(s): "xyzzy"
+
+NUM1 has duplicate value labels for the following value(s): 1
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│       1│     │Nominal          │Input│    6│Left     │A6          │A6          │              │
+│num1│       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭─────────────────────┬───╮
+│Variable Value       │   │
+├─────────────────────┼───┤
+│str1           xyzzy │one│
+├─────────────────────┼───┤
+│num1           1     │one│
+╰─────────────────────┴───╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ced2e811c9128738337c32abf8cfbc7a21279d4 100644 (file)
@@ -0,0 +1,22 @@
+Attribute for Attr1[1] lacks value.
+
+Attribute for fred[2] lacks value.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│        │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..78fac887fa9f1781d71034e6839cb594b0f8fe02 100644 (file)
@@ -0,0 +1 @@
+At offset 0xe8, following value label record, found record type 7 instead of expected type 4 for variable index record
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..08e21a713ea259a48f88bde2498f2ac5c4c15d40 100644 (file)
@@ -0,0 +1 @@
+At offset 0xd4, number of value labels (2147483647) is greater than the maximum number 536870911.
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ba37a94432737c954f009fc7f0adf645ff4313c9 100644 (file)
@@ -0,0 +1,20 @@
+At offsets 0xf4...0x114, record types 3 and 4 may not add value labels to one or more long string variables: STR1
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│       1│     │Nominal          │Input│    9│Left     │A9          │A9          │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..37611c1b4109aca9b69a646485cd190ee7566934 100644 (file)
@@ -0,0 +1,30 @@
+Attribute for Attr1[1] missing quotations.
+
+Attribute for fred[1] missing quotations.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│        │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│firstvar│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭───────────────────────┬─────╮
+│Variable and Name      │Value│
+├───────────────────────┼─────┤
+│(dataset)         Attr1│value│
+├───────────────────────┼─────┤
+│firstvar          fred │23   │
+╰───────────────────────┴─────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d7a6ca5e5e049a0925017facddf0ac0861874207 100644 (file)
@@ -0,0 +1,25 @@
+At offset 0x110, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [3, 4]
+
+At offset 0x138, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [5, 6]
+
+At offset 0x160, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [7, 8]
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│       1│     │Nominal          │Input│    6│Left     │A6          │A6          │              │
+│num1│       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dd7424e7d781f4f87e3e302f2c431ef835f22117 100644 (file)
@@ -0,0 +1,20 @@
+At offset 0x110, one or more variable indexes for value labels were not in the valid range [1,2] or referred to string continuations: [2]
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│       1│     │Nominal          │Input│    9│Left     │A9          │A9          │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..283dbd7f1e5ce8af8472d42bb750f7c37d997e24 100644 (file)
@@ -0,0 +1,22 @@
+At offset 0xe8, at least one valid variable index for value labels is required but none were specified.
+
+This system file does not indicate its own character encoding.  For best results, specify an encoding explicitly.  Use SYSFILE INFO with ENCODING="DETECT" to analyze the possible encodings.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
index c0bf70b22aa034febaea3d13c2943c8e9497a02f..4c6c8aa3f8280d44000dc072f70846faa1089a58 100644 (file)
@@ -7,3 +7,6 @@
 
 # Value label with no variables.
 3; 1; 1.0; i8 3; s7 "one"; 4; >>0<<;
+
+# End of dictionary.
+>>999; 0<<;
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d71b23b5ca5a1b5959225dc8bdb5bbac83f64750 100644 (file)
@@ -0,0 +1,27 @@
+At offset 0x110, the first variable index is for a string variable but the following variable indexes are for numeric variables: [2]
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str1│       1│     │Nominal          │Input│    6│Left     │A6          │A6          │              │
+│num1│       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭─────────────────────┬───╮
+│Variable Value       │   │
+├─────────────────────┼───┤
+│str1           xyzzy │one│
+╰─────────────────────┴───╯
index beb35adae9f90ae6704ea8aec25e5cfb0abf28e1..7408c57d31cf44d0183a6ef2f1af0a95baf9881f 100644 (file)
@@ -3269,7 +3269,7 @@ dnl Very long string map.
 7; 14; 1; COUNT (
 "STR1=00256"; i8 0; i8 9;
 );
-
 dnl Character encoding record.
 7; 20; 1; 12; "windows-1252";