1 use std::fs::read_to_string;
2 use std::path::PathBuf;
4 use anyhow::{anyhow, Result};
6 use pspp::endian::Endian;
9 /// SAv Construction Kit
11 /// The input is a sequence of data items, each followed by a semicolon. Each
12 /// data item is converted to the output format and written on stdout. A data
13 /// item is one of the following:
15 /// - An integer in decimal, in hexadecimal prefixed by `0x`, or in octal
16 /// prefixed by `0`. Output as a 32-bit binary integer.
18 /// - A floating-point number. Output in 64-bit IEEE 754 format.
20 /// - A string enclosed in double quotes. Output literally. There is no
21 /// syntax for "escapes". Strings may not contain new-lines.
23 /// - A literal of the form `s<number>` followed by a quoted string as above.
24 /// Output as the string's contents followed by enough spaces to fill up
25 /// `<number>` bytes. For example, `s8 "foo"` is output as `foo` followed
28 /// - The literal `i8`, `i16`, or `i64` followed by an integer. Output
29 /// as a binary integer with the specified number of bits.
31 /// - One of the literals `SYSMIS`, `LOWEST`, or `HIGHEST`. Output as a
32 /// 64-bit IEEE 754 float of the appropriate PSPP value.
34 /// - `PCSYSMIS`. Output as SPSS/PC+ system-missing value.
36 /// - The literal `ENDIAN`. Output as a 32-bit binary integer, either with
37 /// value 1 if `--be` is in effect or 2 if `--le` is in effect.
39 /// - A pair of parentheses enclosing a sequence of data items, each followed
40 /// by a semicolon (the last semicolon is optional). Output as the enclosed
41 /// data items in sequence.
43 /// - The literal `COUNT` or `COUNT8` followed by a sequence of parenthesized
44 /// data items, as above. Output as a 32-bit or 8-bit binary integer whose
45 /// value is the number of bytes enclosed within the parentheses, followed
46 /// by the enclosed data items themselves.
48 /// optionally followed by an asterisk and a positive integer, which specifies a
49 /// repeat count for the data item.
50 #[derive(Parser, Debug)]
52 /// Big-endian output format (default)
56 /// Little-endian output format
61 #[arg(required = true, name = "input")]
62 input_file_name: PathBuf,
65 #[arg(required = true, name = "output")]
66 output_file_name: PathBuf,
69 fn main() -> Result<()> {
76 let endian = match (be, le) {
77 (false, false) | (true, false) => Endian::Big,
78 (false, true) => Endian::Little,
79 (true, true) => return Err(anyhow!("can't use both `--be` and `--le`")),
82 let input_file_str = input_file_name.to_string_lossy();
83 let input = read_to_string(&input_file_name)
84 .map_err(|err| anyhow!("{input_file_str}: read failed ({err})"))?;
86 let output = sack(&input, Some(&input_file_str), endian)?;
88 let output_file_str = output_file_name.to_string_lossy();
89 std::fs::write(&output_file_name, output)
90 .map_err(|err| anyhow!("{output_file_str}: write failed ({err})"))?;