Add PIBHEX, PIB, RB tests.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Mar 2025 22:15:13 +0000 (15:15 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Mar 2025 22:15:13 +0000 (15:15 -0700)
rust/pspp/src/endian.rs
rust/pspp/src/format/display.rs
rust/pspp/src/format/testdata/pibhex.txt
rust/pspp/src/format/testdata/rb.txt [new file with mode: 0644]
rust/pspp/src/format/testdata/split-binhex-out.expected.py
rust/pspp/src/settings.rs

index ae3cd99c1466b0fda9ded0637e22fb16a1e4550c..d35b7daeade90fe988801031d22ad6fcc2f34fd8 100644 (file)
@@ -5,21 +5,18 @@ use smallvec::SmallVec;
 /// SPSS system files can declare IBM 370 and DEC VAX floating-point
 /// representations, but no file that uses either of these has ever been found
 /// in the wild, so this code does not handle them.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 pub enum Endian {
     /// Big-endian: MSB at lowest address.
+    #[cfg_attr(target_endian = "big", default)]
     Big,
 
     /// Little-endian: LSB at lowest address.
+    #[cfg_attr(target_endian = "little", default)]
     Little,
 }
 
 impl Endian {
-    #[cfg(target_endian = "big")]
-    pub const NATIVE: Endian = Endian::Big;
-    #[cfg(target_endian = "little")]
-    pub const NATIVE: Endian = Endian::Little;
-
     pub fn identify_u32(expected_value: u32, bytes: [u8; 4]) -> Option<Self> {
         let as_big: u32 = Endian::Big.parse(bytes);
         let as_little: u32 = Endian::Little.parse(bytes);
@@ -40,7 +37,7 @@ impl Endian {
         }
     }
 
-    pub fn to_smallvec(self, mut value: u64, n: usize) -> SmallVec<[u8; 16]> {
+    pub fn to_smallvec<const N: usize>(self, mut value: u64, n: usize) -> SmallVec<[u8; N]> {
         debug_assert!(n <= 8);
         let mut vec = SmallVec::new();
         value <<= 8 * (8 - n);
index ca1545240a29b813db554210558b6329d43d0b5f..647e258daf57acb256136eaa0b338f6991aaf576 100644 (file)
@@ -14,13 +14,15 @@ use smallvec::{Array, SmallVec};
 use crate::{
     calendar::{calendar_offset_to_gregorian, day_of_year, month_name, short_month_name},
     dictionary::Value,
+    endian::ToBytes,
     format::{Category, Decimal, Format, NumberStyle, Settings, Type},
-    settings::Settings as PsppSettings,
+    settings::{EndianSettings, Settings as PsppSettings},
 };
 
 pub struct DisplayValue<'a, 'b> {
     format: Format,
     settings: &'b Settings,
+    endian: EndianSettings,
     value: &'a Value,
     encoding: &'static Encoding,
 }
@@ -82,16 +84,21 @@ impl<'a, 'b> Display for DisplayValue<'a, 'b> {
 
 impl<'a, 'b> DisplayValue<'a, 'b> {
     pub fn new(format: Format, value: &'a Value, encoding: &'static Encoding) -> Self {
+        let settings = PsppSettings::global();
         Self {
             format,
             value,
             encoding,
-            settings: &PsppSettings::global().formats,
+            settings: &settings.formats,
+            endian: settings.endian,
         }
     }
     pub fn with_settings(self, settings: &'b Settings) -> Self {
         Self { settings, ..self }
     }
+    pub fn with_endian(self, endian: EndianSettings) -> Self {
+        Self { endian, ..self }
+    }
     fn fmt_binary(&self, f: &mut Formatter) -> FmtResult {
         let output = self.to_binary().unwrap();
         for b in output {
@@ -561,6 +568,8 @@ impl<'a, 'b> DisplayValue<'a, 'b> {
             Type::P => Some(self.p(number)),
             Type::PK => Some(self.pk(number)),
             Type::IB => Some(self.ib(number)),
+            Type::PIB => Some(self.pib(number)),
+            Type::RB => Some(self.rb(number)),
             _ => None,
         }
     }
@@ -630,10 +639,32 @@ impl<'a, 'b> DisplayValue<'a, 'b> {
         } else {
             integer
         };
-        PsppSettings::global()
+        self.endian
+            .output_integer_format
+            .to_smallvec(integer, self.format.w())
+    }
+
+    fn pib(&self, number: Option<f64>) -> SmallVec<[u8; 16]> {
+        let number = number.map_or(0.0, |number| (number * power10(self.format.d())).round());
+        let number = if number >= power256(self.format.w) || number < 0.0 {
+            0.0
+        } else {
+            number
+        };
+        let integer = number.abs() as u64;
+        self.endian
             .output_integer_format
             .to_smallvec(integer, self.format.w())
     }
+
+    fn rb(&self, number: Option<f64>) -> SmallVec<[u8; 16]> {
+        let number = number.unwrap_or(-f64::MAX);
+        let bytes: [u8; 8] = self.endian.output_float_format.to_bytes(number);
+        let mut vec = SmallVec::new();
+        vec.extend_from_slice(&bytes);
+        vec.resize(self.format.w(), 0);
+        vec
+    }
 }
 
 struct LegacyFormat {
@@ -1023,13 +1054,14 @@ mod test {
 
     use crate::{
         dictionary::Value,
+        endian::Endian,
         format::{AbstractFormat, Format, Settings, Type, UncheckedFormat, CC},
         lex::{
             scan::StringScanner,
             segment::Syntax,
             token::{Punct, Token},
         },
-        settings::Settings as PsppSettings,
+        settings::EndianSettings,
     };
 
     fn test(name: &str) {
@@ -1043,7 +1075,7 @@ mod test {
             .with_cc(CC::C, "((,[,],))".parse().unwrap())
             .with_cc(CC::D, ",XXX,,-".parse().unwrap())
             .with_cc(CC::E, ",,YYY,-".parse().unwrap());
-        let mut value = 0.0;
+        let mut value = Some(0.0);
         let mut value_name = String::new();
         for (line_number, line) in input.lines().map(|r| r.unwrap()).enumerate() {
             let line = line.trim();
@@ -1056,13 +1088,17 @@ mod test {
                     value = if let Some(Token::Punct(Punct::Exp)) = tokens.get(1) {
                         assert_eq!(tokens.len(), 3);
                         let exponent = tokens[2].as_number().unwrap();
-                        number.powf(exponent)
+                        Some(number.powf(exponent))
                     } else {
                         assert_eq!(tokens.len(), 1);
-                        *number
+                        Some(*number)
                     };
                     value_name = String::from(line);
                 }
+                Token::End => {
+                    value = None;
+                    value_name = String::from(line);
+                }
                 Token::Id(id) => {
                     let format: UncheckedFormat =
                         id.0.as_str()
@@ -1073,7 +1109,7 @@ mod test {
                     let format: Format = format.try_into().unwrap();
                     assert_eq!(tokens.get(1), Some(&Token::Punct(Punct::Colon)));
                     let expected = tokens[2].as_string().unwrap();
-                    let actual = Value::Number(Some(value))
+                    let actual = Value::Number(value)
                         .display(format, UTF_8)
                         .with_settings(&settings)
                         .to_string();
@@ -1154,6 +1190,11 @@ mod test {
         test("cce.txt");
     }
 
+    #[test]
+    fn pibhex() {
+        test("pibhex.txt");
+    }
+
     #[test]
     fn leading_zeros() {
         struct Test {
@@ -1227,6 +1268,11 @@ mod test {
         let mut value = None;
         let mut value_name = String::new();
 
+        let endian = EndianSettings {
+            output_integer_format: Endian::Big,
+            output_float_format: Endian::Big,
+            ..EndianSettings::default()
+        };
         for (line_number, line) in input.lines().map(|r| r.unwrap()).enumerate() {
             let line = line.trim();
             let line_number = line_number + 1;
@@ -1255,6 +1301,7 @@ mod test {
                     let mut actual = SmallVec::<[u8; 16]>::new();
                     Value::Number(value)
                         .display(format, UTF_8)
+                        .with_endian(endian)
                         .write(&mut actual, UTF_8)
                         .unwrap();
                     let mut actual_s = SmallString::<[u8; 32]>::new();
@@ -1274,17 +1321,27 @@ mod test {
     }
 
     #[test]
-    fn test_p() {
+    fn p() {
         test_binhex("p.txt");
     }
 
     #[test]
-    fn test_pk() {
+    fn pk() {
         test_binhex("pk.txt");
     }
 
     #[test]
-    fn test_ib() {
+    fn ib() {
         test_binhex("ib.txt");
     }
+
+    #[test]
+    fn pib() {
+        test_binhex("pib.txt");
+    }
+
+    #[test]
+    fn rb() {
+        test_binhex("rb.txt");
+    }
 }
index 4c6a9ded68eaa713142b673984a4a7a2e66ddcfa..23c50a803c84a4c6a666764d68cf2afb351efb42 100644 (file)
 .
-PIBHEX2: "b'  '"
-PIBHEX4: "b'    '"
-PIBHEX6: "b'      '"
-PIBHEX8: "b'        '"
+PIBHEX2: " ."
+PIBHEX4: "   ."
+PIBHEX6: "     ."
+PIBHEX8: "       ."
 2
-PIBHEX2: "b'02'"
-PIBHEX4: "b'0002'"
-PIBHEX6: "b'000002'"
-PIBHEX8: "b'00000002'"
+PIBHEX2: "02"
+PIBHEX4: "0002"
+PIBHEX6: "000002"
+PIBHEX8: "00000002"
 11
-PIBHEX2: "b'0B'"
-PIBHEX4: "b'000B'"
-PIBHEX6: "b'00000B'"
-PIBHEX8: "b'0000000B'"
+PIBHEX2: "0B"
+PIBHEX4: "000B"
+PIBHEX6: "00000B"
+PIBHEX8: "0000000B"
 123
-PIBHEX2: "b'7B'"
-PIBHEX4: "b'007B'"
-PIBHEX6: "b'00007B'"
-PIBHEX8: "b'0000007B'"
+PIBHEX2: "7B"
+PIBHEX4: "007B"
+PIBHEX6: "00007B"
+PIBHEX8: "0000007B"
 1234
-PIBHEX2: "b'**'"
-PIBHEX4: "b'04D2'"
-PIBHEX6: "b'0004D2'"
-PIBHEX8: "b'000004D2'"
+PIBHEX2: "**"
+PIBHEX4: "04D2"
+PIBHEX6: "0004D2"
+PIBHEX8: "000004D2"
 913
-PIBHEX2: "b'**'"
-PIBHEX4: "b'0391'"
-PIBHEX6: "b'000391'"
-PIBHEX8: "b'00000391'"
+PIBHEX2: "**"
+PIBHEX4: "0391"
+PIBHEX6: "000391"
+PIBHEX8: "00000391"
 3.14159
-PIBHEX2: "b'03'"
-PIBHEX4: "b'0003'"
-PIBHEX6: "b'000003'"
-PIBHEX8: "b'00000003'"
+PIBHEX2: "03"
+PIBHEX4: "0003"
+PIBHEX6: "000003"
+PIBHEX8: "00000003"
 777
-PIBHEX2: "b'**'"
-PIBHEX4: "b'0309'"
-PIBHEX6: "b'000309'"
-PIBHEX8: "b'00000309'"
+PIBHEX2: "**"
+PIBHEX4: "0309"
+PIBHEX6: "000309"
+PIBHEX8: "00000309"
 82
-PIBHEX2: "b'52'"
-PIBHEX4: "b'0052'"
-PIBHEX6: "b'000052'"
-PIBHEX8: "b'00000052'"
+PIBHEX2: "52"
+PIBHEX4: "0052"
+PIBHEX6: "000052"
+PIBHEX8: "00000052"
 690
-PIBHEX2: "b'**'"
-PIBHEX4: "b'02B2'"
-PIBHEX6: "b'0002B2'"
-PIBHEX8: "b'000002B2'"
+PIBHEX2: "**"
+PIBHEX4: "02B2"
+PIBHEX6: "0002B2"
+PIBHEX8: "000002B2"
 -2
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -11
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -123
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -1234
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -913
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -3.14159
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -777
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -82
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -690
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 9999.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'270F'"
-PIBHEX6: "b'00270F'"
-PIBHEX8: "b'0000270F'"
+PIBHEX2: "**"
+PIBHEX4: "270F"
+PIBHEX6: "00270F"
+PIBHEX8: "0000270F"
 9999.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'2710'"
-PIBHEX6: "b'002710'"
-PIBHEX8: "b'00002710'"
+PIBHEX2: "**"
+PIBHEX4: "2710"
+PIBHEX6: "002710"
+PIBHEX8: "00002710"
 9999.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'2710'"
-PIBHEX6: "b'002710'"
-PIBHEX8: "b'00002710'"
+PIBHEX2: "**"
+PIBHEX4: "2710"
+PIBHEX6: "002710"
+PIBHEX8: "00002710"
 10000
-PIBHEX2: "b'**'"
-PIBHEX4: "b'2710'"
-PIBHEX6: "b'002710'"
-PIBHEX8: "b'00002710'"
+PIBHEX2: "**"
+PIBHEX4: "2710"
+PIBHEX6: "002710"
+PIBHEX8: "00002710"
 18231237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'01162FC5'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "01162FC5"
 -9999.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -9999.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -9999.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -10000
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -8231237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 999.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'03E7'"
-PIBHEX6: "b'0003E7'"
-PIBHEX8: "b'000003E7'"
+PIBHEX2: "**"
+PIBHEX4: "03E7"
+PIBHEX6: "0003E7"
+PIBHEX8: "000003E7"
 999.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'03E8'"
-PIBHEX6: "b'0003E8'"
-PIBHEX8: "b'000003E8'"
+PIBHEX2: "**"
+PIBHEX4: "03E8"
+PIBHEX6: "0003E8"
+PIBHEX8: "000003E8"
 999.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'03E8'"
-PIBHEX6: "b'0003E8'"
-PIBHEX8: "b'000003E8'"
+PIBHEX2: "**"
+PIBHEX4: "03E8"
+PIBHEX6: "0003E8"
+PIBHEX8: "000003E8"
 1000
-PIBHEX2: "b'**'"
-PIBHEX4: "b'03E8'"
-PIBHEX6: "b'0003E8'"
-PIBHEX8: "b'000003E8'"
+PIBHEX2: "**"
+PIBHEX4: "03E8"
+PIBHEX6: "0003E8"
+PIBHEX8: "000003E8"
 8231237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'7D9945'"
-PIBHEX8: "b'007D9945'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "7D9945"
+PIBHEX8: "007D9945"
 -999.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -999.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -999.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -1000
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -8231237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 99.1
-PIBHEX2: "b'63'"
-PIBHEX4: "b'0063'"
-PIBHEX6: "b'000063'"
-PIBHEX8: "b'00000063'"
+PIBHEX2: "63"
+PIBHEX4: "0063"
+PIBHEX6: "000063"
+PIBHEX8: "00000063"
 99.5
-PIBHEX2: "b'64'"
-PIBHEX4: "b'0064'"
-PIBHEX6: "b'000064'"
-PIBHEX8: "b'00000064'"
+PIBHEX2: "64"
+PIBHEX4: "0064"
+PIBHEX6: "000064"
+PIBHEX8: "00000064"
 99.9
-PIBHEX2: "b'64'"
-PIBHEX4: "b'0064'"
-PIBHEX6: "b'000064'"
-PIBHEX8: "b'00000064'"
+PIBHEX2: "64"
+PIBHEX4: "0064"
+PIBHEX6: "000064"
+PIBHEX8: "00000064"
 100
-PIBHEX2: "b'64'"
-PIBHEX4: "b'0064'"
-PIBHEX6: "b'000064'"
-PIBHEX8: "b'00000064'"
+PIBHEX2: "64"
+PIBHEX4: "0064"
+PIBHEX6: "000064"
+PIBHEX8: "00000064"
 821237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'0C87F5'"
-PIBHEX8: "b'000C87F5'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "0C87F5"
+PIBHEX8: "000C87F5"
 -99.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -99.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -99.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -100
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -831237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 9.1
-PIBHEX2: "b'09'"
-PIBHEX4: "b'0009'"
-PIBHEX6: "b'000009'"
-PIBHEX8: "b'00000009'"
+PIBHEX2: "09"
+PIBHEX4: "0009"
+PIBHEX6: "000009"
+PIBHEX8: "00000009"
 9.5
-PIBHEX2: "b'0A'"
-PIBHEX4: "b'000A'"
-PIBHEX6: "b'00000A'"
-PIBHEX8: "b'0000000A'"
+PIBHEX2: "0A"
+PIBHEX4: "000A"
+PIBHEX6: "00000A"
+PIBHEX8: "0000000A"
 9.9
-PIBHEX2: "b'0A'"
-PIBHEX4: "b'000A'"
-PIBHEX6: "b'00000A'"
-PIBHEX8: "b'0000000A'"
+PIBHEX2: "0A"
+PIBHEX4: "000A"
+PIBHEX6: "00000A"
+PIBHEX8: "0000000A"
 10
-PIBHEX2: "b'0A'"
-PIBHEX4: "b'000A'"
-PIBHEX6: "b'00000A'"
-PIBHEX8: "b'0000000A'"
+PIBHEX2: "0A"
+PIBHEX4: "000A"
+PIBHEX6: "00000A"
+PIBHEX8: "0000000A"
 81237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'013D55'"
-PIBHEX8: "b'00013D55'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "013D55"
+PIBHEX8: "00013D55"
 -9.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -9.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -9.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -10
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 -81237
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 1.1
-PIBHEX2: "b'01'"
-PIBHEX4: "b'0001'"
-PIBHEX6: "b'000001'"
-PIBHEX8: "b'00000001'"
+PIBHEX2: "01"
+PIBHEX4: "0001"
+PIBHEX6: "000001"
+PIBHEX8: "00000001"
 -1.1
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 1.5
-PIBHEX2: "b'02'"
-PIBHEX4: "b'0002'"
-PIBHEX6: "b'000002'"
-PIBHEX8: "b'00000002'"
+PIBHEX2: "02"
+PIBHEX4: "0002"
+PIBHEX6: "000002"
+PIBHEX8: "00000002"
 -1.5
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
 1.9
-PIBHEX2: "b'02'"
-PIBHEX4: "b'0002'"
-PIBHEX6: "b'000002'"
-PIBHEX8: "b'00000002'"
+PIBHEX2: "02"
+PIBHEX4: "0002"
+PIBHEX6: "000002"
+PIBHEX8: "00000002"
 -1.9
-PIBHEX2: "b'**'"
-PIBHEX4: "b'****'"
-PIBHEX6: "b'******'"
-PIBHEX8: "b'********'"
+PIBHEX2: "**"
+PIBHEX4: "****"
+PIBHEX6: "******"
+PIBHEX8: "********"
diff --git a/rust/pspp/src/format/testdata/rb.txt b/rust/pspp/src/format/testdata/rb.txt
new file mode 100644 (file)
index 0000000..d3fad7a
--- /dev/null
@@ -0,0 +1,136 @@
+.
+RB8: "ffefffffffffffff"
+2
+RB8: "4000000000000000"
+11
+RB8: "4026000000000000"
+123
+RB8: "405ec00000000000"
+1234
+RB8: "4093480000000000"
+913
+RB8: "408c880000000000"
+3.14159
+RB8: "400921f9f01b866e"
+777
+RB8: "4088480000000000"
+82
+RB8: "4054800000000000"
+690
+RB8: "4085900000000000"
+-2
+RB8: "c000000000000000"
+-11
+RB8: "c026000000000000"
+-123
+RB8: "c05ec00000000000"
+-1234
+RB8: "c093480000000000"
+-913
+RB8: "c08c880000000000"
+-3.14159
+RB8: "c00921f9f01b866e"
+-777
+RB8: "c088480000000000"
+-82
+RB8: "c054800000000000"
+-690
+RB8: "c085900000000000"
+-.1
+RB8: "bfb999999999999a"
+-.5
+RB8: "bfe0000000000000"
+-.9
+RB8: "bfeccccccccccccd"
+9999.1
+RB8: "40c3878ccccccccd"
+9999.5
+RB8: "40c387c000000000"
+9999.9
+RB8: "40c387f333333333"
+10000
+RB8: "40c3880000000000"
+18231237
+RB8: "417162fc50000000"
+-9999.1
+RB8: "c0c3878ccccccccd"
+-9999.5
+RB8: "c0c387c000000000"
+-9999.9
+RB8: "c0c387f333333333"
+-10000
+RB8: "c0c3880000000000"
+-8231237
+RB8: "c15f665140000000"
+999.1
+RB8: "408f38cccccccccd"
+999.5
+RB8: "408f3c0000000000"
+999.9
+RB8: "408f3f3333333333"
+1000
+RB8: "408f400000000000"
+8231237
+RB8: "415f665140000000"
+-999.1
+RB8: "c08f38cccccccccd"
+-999.5
+RB8: "c08f3c0000000000"
+-999.9
+RB8: "c08f3f3333333333"
+-1000
+RB8: "c08f400000000000"
+-8231237
+RB8: "c15f665140000000"
+99.1
+RB8: "4058c66666666666"
+99.5
+RB8: "4058e00000000000"
+99.9
+RB8: "4058f9999999999a"
+100
+RB8: "4059000000000000"
+821237
+RB8: "41290fea00000000"
+-99.1
+RB8: "c058c66666666666"
+-99.5
+RB8: "c058e00000000000"
+-99.9
+RB8: "c058f9999999999a"
+-100
+RB8: "c059000000000000"
+-831237
+RB8: "c1295e0a00000000"
+9.1
+RB8: "4022333333333333"
+9.5
+RB8: "4023000000000000"
+9.9
+RB8: "4023cccccccccccd"
+10
+RB8: "4024000000000000"
+81237
+RB8: "40f3d55000000000"
+-9.1
+RB8: "c022333333333333"
+-9.5
+RB8: "c023000000000000"
+-9.9
+RB8: "c023cccccccccccd"
+-10
+RB8: "c024000000000000"
+-81237
+RB8: "c0f3d55000000000"
+1.1
+RB8: "3ff199999999999a"
+-1.1
+RB8: "bff199999999999a"
+1.5
+RB8: "3ff8000000000000"
+-1.5
+RB8: "bff8000000000000"
+1.9
+RB8: "3ffe666666666666"
+-1.9
+RB8: "bffe666666666666"
index c7d5e8706011850620f2dba7cdd1852d183b4f7b..e57accaf0bd0aa31a74e3c4db312b5c71753c95f 100644 (file)
@@ -2,9 +2,10 @@
 
 import sys
 import pathlib
+import struct
 
 outputs = {}
-for format in ["P", "PK", "IB", "PIB", "PIBHEX"]:
+for format in ["P", "PK", "IB", "PIB", "PIBHEX", "RB"]:
     outputs[format] = open(format.lower() + '.txt', 'w')
 
 values = [
@@ -101,7 +102,10 @@ for value in values:
             outputs["PIB"].write(f"PIB{w}.{d}: \"{b[x:x + w].hex()}\"\n")
             x += w
     for w in [2,4,6,8]:
-        outputs["PIBHEX"].write(f"PIBHEX{w}: \"{b[x:x + w]}\"\n")
+        outputs["PIBHEX"].write(f"PIBHEX{w}: \"{b[x:x + w].decode('UTF-8')}\"\n")
         x += w
 
+    value = -sys.float_info.max if value == '.' else float(value)
+    outputs["RB"].write(f"RB8: \"{struct.pack('>d', value).hex()}\"\n")
+
     ofs += 256
index ac41b22e64e2d69e94475e3f3c8ee4f723ecbba5..966f26bd5bb829fdcab5a103afda90dc1baa662c 100644 (file)
@@ -38,9 +38,8 @@ impl Show {
     }
 }
 
-pub struct Settings {
-    pub look: Arc<Look>,
-
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
+pub struct EndianSettings {
     /// Endianness for reading IB and PIB formats.
     pub input_integer_format: Endian,
 
@@ -52,6 +51,10 @@ pub struct Settings {
 
     /// Endianness for writing RB and RBHEX formats.
     pub output_float_format: Endian,
+}
+
+pub struct Settings {
+    pub look: Arc<Look>,
 
     /// `MDISPLAY`: how to display matrices in `MATRIX`...`END MATRIX`.
     pub matrix_display: MatrixDisplay,
@@ -78,6 +81,7 @@ pub struct Settings {
     pub global: Compatibility,
     pub syntax: Compatibility,
     pub formats: FormatSettings,
+    pub endian: EndianSettings,
     pub small: f64,
     pub show_values: Show,
     pub show_variables: Show,
@@ -87,10 +91,6 @@ impl Default for Settings {
     fn default() -> Self {
         Self {
             look: Arc::new(Look::default()),
-            input_integer_format: Endian::NATIVE,
-            input_float_format: Endian::NATIVE,
-            output_integer_format: Endian::NATIVE,
-            output_float_format: Endian::NATIVE,
             matrix_display: MatrixDisplay::default(),
             view_length: 24,
             view_width: 79,
@@ -114,6 +114,7 @@ impl Default for Settings {
             global: Compatibility::default(),
             syntax: Compatibility::default(),
             formats: FormatSettings::default(),
+            endian: EndianSettings::default(),
             small: 0.0001,
             show_values: Show::default(),
             show_variables: Show::default(),