variable display
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 8 Jun 2025 19:48:37 +0000 (12:48 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 8 Jun 2025 19:48:37 +0000 (12:48 -0700)
rust/pspp/src/sys/raw.rs
rust/pspp/src/sys/test.rs
rust/pspp/src/sys/testdata/variable_display_without_width.expected [new file with mode: 0644]
rust/pspp/src/sys/testdata/variable_display_without_width.sack [new file with mode: 0644]

index eb3e0f4a0d067a25996058f8283611c1ab51457e..34693eb0f438924f048834f64423f0759bf8756f 100644 (file)
@@ -334,7 +334,7 @@ impl Record {
             2 => Ok(Some(VariableRecord::read(reader, endian, warn)?)),
             3 => Ok(ValueLabelRecord::read(reader, endian, var_types, warn)?),
             6 => Ok(Some(DocumentRecord::read(reader, endian)?)),
-            7 => Extension::read(reader, endian, var_types.n_values(), warn),
+            7 => Extension::read(reader, endian, var_types, warn),
             999 => Ok(Some(Record::EndOfHeaders(
                 endian.parse(read_bytes(reader)?),
             ))),
@@ -2281,10 +2281,9 @@ pub enum Alignment {
 impl Alignment {
     fn try_decode(source: u32) -> Result<Option<Alignment>, Warning> {
         match source {
-            0 => Ok(None),
-            1 => Ok(Some(Alignment::Left)),
-            2 => Ok(Some(Alignment::Right)),
-            3 => Ok(Some(Alignment::Center)),
+            0 => Ok(Some(Alignment::Left)),
+            1 => Ok(Some(Alignment::Right)),
+            2 => Ok(Some(Alignment::Center)),
             _ => Err(Warning::InvalidAlignment(source)),
         }
     }
@@ -2320,7 +2319,7 @@ impl VarDisplayRecord {
 
     fn parse(
         ext: &Extension,
-        n_vars: usize,
+        var_types: &VarTypes,
         endian: Endian,
         warn: &dyn Fn(Warning),
     ) -> Result<Record, Warning> {
@@ -2333,6 +2332,7 @@ impl VarDisplayRecord {
             });
         }
 
+        let n_vars = var_types.n_vars();
         let has_width = if ext.count as usize == 3 * n_vars {
             true
         } else if ext.count as usize == 2 * n_vars {
@@ -2341,7 +2341,7 @@ impl VarDisplayRecord {
             return Err(Warning::InvalidVariableDisplayCount {
                 count: ext.count as usize,
                 first: 2 * n_vars,
-                second: 2 * n_vars,
+                second: 3 * n_vars,
             });
         };
 
@@ -2885,7 +2885,7 @@ impl Extension {
     fn read<R: Read + Seek>(
         r: &mut R,
         endian: Endian,
-        n_vars: usize,
+        var_types: &VarTypes,
         warn: &dyn Fn(Warning),
     ) -> Result<Option<Record>, Error> {
         let subtype = endian.parse(read_bytes(r)?);
@@ -2913,7 +2913,9 @@ impl Extension {
         let result = match subtype {
             IntegerInfoRecord::SUBTYPE => IntegerInfoRecord::parse(&extension, endian),
             FloatInfoRecord::SUBTYPE => FloatInfoRecord::parse(&extension, endian),
-            VarDisplayRecord::SUBTYPE => VarDisplayRecord::parse(&extension, n_vars, endian, warn),
+            VarDisplayRecord::SUBTYPE => {
+                VarDisplayRecord::parse(&extension, var_types, endian, warn)
+            }
             MultipleResponseRecord::SUBTYPE | 19 => {
                 MultipleResponseRecord::parse(&extension, endian)
             }
@@ -3231,4 +3233,8 @@ impl VarTypes {
             .iter()
             .map(|var_type| var_type.unwrap_or(VarType::String))
     }
+
+    pub fn n_vars(&self) -> usize {
+        self.types.iter().flatten().count()
+    }
 }
index db94531a2faa527bf62ddac5654c26d0cee46373..3265db5c4834f6b1dcde277bff7e6dd3d2c46402 100644 (file)
@@ -62,6 +62,11 @@ fn extra_product_info() {
     test_sysfile("extra_product_info");
 }
 
+#[test]
+fn variable_display_without_width() {
+    test_sysfile("variable_display_without_width");
+}
+
 fn test_sysfile(name: &str) {
     let input_filename = Path::new(env!("CARGO_MANIFEST_DIR"))
         .join("src/sys/testdata")
diff --git a/rust/pspp/src/sys/testdata/variable_display_without_width.expected b/rust/pspp/src/sys/testdata/variable_display_without_width.expected
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rust/pspp/src/sys/testdata/variable_display_without_width.sack b/rust/pspp/src/sys/testdata/variable_display_without_width.sack
new file mode 100644 (file)
index 0000000..0137bd0
--- /dev/null
@@ -0,0 +1,53 @@
+# File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; # Layout code
+19; # Nominal case size
+0; # Not compressed
+0; # Not weighted
+0; # No cases.
+100.0; # Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+# Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "A";
+2; 0; 0; 0; 0x050800 *2; s8 "B";
+2; 0; 0; 0; 0x050800 *2; s8 "C";
+2; 0; 0; 0; 0x050800 *2; s8 "D";
+
+# Short string variables.
+2; 3; 0; 0; 0x010300 *2; s8 "H";
+2; 3; 0; 0; 0x010300 *2; s8 "I";
+2; 3; 0; 0; 0x010300 *2; s8 "J";
+2; 3; 0; 0; 0x010300 *2; s8 "K";
+
+# Long string variables.
+2; 9; 0; 0; 0x010900 *2; s8 "L";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 10; 0; 0; 0x010a00 *2; s8 "M";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 17; 0; 0; 0x011100 *2; s8 "N";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 2;
+2; 25; 0; 0; 0x011900 *2; s8 "O";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 3;
+
+# Variable display parameters
+7; 11; 4; 24;
+1; 0;
+2; 0;
+3; 0;
+1; 1;
+2; 1;
+3; 1;
+1; 2;
+2; 2;
+3; 2;
+0; 0;
+0; 1;
+0; 2;
+
+# Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+# Dictionary termination record.
+999; 0;