1 use std::fs::read_to_string;
2 use std::io::{stdout, IsTerminal, Write};
3 use std::path::PathBuf;
5 use anyhow::{anyhow, Result};
7 use pspp::endian::Endian;
10 /// SAv Construction Kit
12 /// The input is a sequence of data items, each followed by a semicolon. Each
13 /// data item is converted to the output format and written on stdout. A data
14 /// item is one of the following:
16 /// - An integer in decimal, in hexadecimal prefixed by `0x`, or in octal
17 /// prefixed by `0`. Output as a 32-bit binary integer.
19 /// - A floating-point number. Output in 64-bit IEEE 754 format.
21 /// - A string enclosed in double quotes. Output literally. There is no
22 /// syntax for "escapes". Strings may not contain new-lines.
24 /// - A literal of the form `s<number>` followed by a quoted string as above.
25 /// Output as the string's contents followed by enough spaces to fill up
26 /// `<number>` bytes. For example, `s8 "foo"` is output as `foo` followed
29 /// - The literal `i8`, `i16`, or `i64` followed by an integer. Output
30 /// as a binary integer with the specified number of bits.
32 /// - One of the literals `SYSMIS`, `LOWEST`, or `HIGHEST`. Output as a
33 /// 64-bit IEEE 754 float of the appropriate PSPP value.
35 /// - `PCSYSMIS`. Output as SPSS/PC+ system-missing value.
37 /// - The literal `ENDIAN`. Output as a 32-bit binary integer, either with
38 /// value 1 if `--be` is in effect or 2 if `--le` is in effect.
40 /// - A pair of parentheses enclosing a sequence of data items, each followed
41 /// by a semicolon (the last semicolon is optional). Output as the enclosed
42 /// data items in sequence.
44 /// - The literal `COUNT` or `COUNT8` followed by a sequence of parenthesized
45 /// data items, as above. Output as a 32-bit or 8-bit binary integer whose
46 /// value is the number of bytes enclosed within the parentheses, followed
47 /// by the enclosed data items themselves.
49 /// optionally followed by an asterisk and a positive integer, which specifies a
50 /// repeat count for the data item.
51 #[derive(Parser, Debug)]
53 /// Big-endian output format (default)
57 /// Little-endian output format
62 #[arg(required = true, name = "input")]
63 input_file_name: PathBuf,
66 fn main() -> Result<()> {
67 let Args { be, le, input_file_name } = Args::parse();
68 if stdout().is_terminal() {
70 "not writing binary data to a terminal; redirect to a file"
73 let endian = match (be, le) {
74 (false, false) | (true, false) => Endian::Big,
75 (false, true) => Endian::Little,
76 (true, true) => return Err(anyhow!("can't use both `--be` and `--le`")),
78 let input = read_to_string(&input_file_name)?;
79 let input_file_name = input_file_name.to_string_lossy();
80 let output = sack(&input, Some(&input_file_name), endian)?;
81 stdout().write_all(&output)?;