X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=rust%2Fsrc%2Fmain.rs;h=404e96d57d07becaf09c4688319a0ac3739ceee4;hb=e0cbdf0daefcca81be9572aab0deedf945687f5a;hp=319d7aea7c0f32a020db403a21fe60fad96cac67;hpb=13d0badc005f46d33eb5a7ec4ef5d794b4512450;p=pspp diff --git a/rust/src/main.rs b/rust/src/main.rs index 319d7aea7c..404e96d57d 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -15,14 +15,15 @@ * along with this program. If not, see . */ use anyhow::Result; -use clap::Parser; -use pspp::{ - raw::{Reader, Record}, -}; +use clap::{Parser, ValueEnum}; +use encoding_rs::Encoding; +use pspp::cooked::decode; +use pspp::raw::{Reader, Record, Magic}; use std::fs::File; use std::io::BufReader; use std::path::{Path, PathBuf}; use std::str; +use thiserror::Error as ThisError; /// A utility to dissect SPSS system files. #[derive(Parser, Debug)] @@ -35,36 +36,84 @@ struct Args { /// Files to dissect. #[arg(required = true)] files: Vec, + + /// How to dissect the file. + #[arg(short, long, value_enum, default_value_t)] + mode: Mode, + + /// The encoding to use. + #[arg(long, value_parser = parse_encoding)] + encoding: Option<&'static Encoding>, +} + +#[derive(ThisError, Debug)] +#[error("{0}: unknown encoding")] +struct UnknownEncodingError(String); + +fn parse_encoding(arg: &str) -> Result<&'static Encoding, UnknownEncodingError> { + match Encoding::for_label_no_replacement(arg.as_bytes()) { + Some(encoding) => Ok(encoding), + None => Err(UnknownEncodingError(arg.to_string())), + } +} + +#[derive(Clone, Copy, Debug, Default, ValueEnum)] +enum Mode { + Identify, + Raw, + #[default] + Cooked, } fn main() -> Result<()> { - let Args { max_cases, files } = Args::parse(); + let Args { + max_cases, + files, + mode, + encoding, + } = Args::parse(); for file in files { - dissect(&file, max_cases)?; + dissect(&file, max_cases, mode, encoding)?; } Ok(()) } -fn dissect(file_name: &Path, max_cases: u64) -> Result<()> { +fn dissect(file_name: &Path, max_cases: u64, mode: Mode, encoding: Option<&'static Encoding>) -> Result<()> { let reader = File::open(file_name)?; let reader = BufReader::new(reader); let mut reader = Reader::new(reader)?; - let records: Vec = reader.collect_headers()?; - let mut n_cases = 0; - for record in records { - println!("{record:?}"); - match record { - Record::EndOfHeaders(_) if max_cases == 0 => break, - Record::Case(_) => { - n_cases += 1; - if n_cases >= max_cases { - break; - } + match mode { + Mode::Identify => { + let Record::Header(header) = reader.next().unwrap()? else { unreachable!() }; + match header.magic { + Magic::Sav => println!("SPSS System File"), + Magic::Zsav => println!("SPSS System File with Zlib compression"), + Magic::Ebcdic => println!("EBCDIC-encoded SPSS System File"), + } + return Ok(()) + } + Mode::Raw => { + let headers: Vec = reader.collect_headers()?; + for header in headers { + println!("{header:?}"); } - _ => (), } + Mode::Cooked => { + let headers: Vec = reader.collect_headers()?; + let headers = decode(headers, encoding, &|e| panic!("{e}"))?; + for header in headers { + println!("{header:?}"); + } + } + } + + for _ in 0..max_cases { + let Some(Ok(record)) = reader.next() else { + break; + }; + println!("{:?}", record); } Ok(()) }