New workspace crate clawhdf5-tools with one binary, h5rs, built only on the clawhdf5 facade and clawhdf5-format (no libhdf5, no C): - ls [-r] [-v] FILE[/path]: h5ls's listing (same text in its first two columns) plus the datatype; -v adds address, link count, layout and chunk index, chunk size, storage, filters, datatype and attributes. - dump [--json] [-A] [-p] [-d PATH] FILE: h5dump DDL (byte-identical to h5dump 1.14.6 on the test files) or hdf5-json. - stat FILE: h5stat's object/link/rank/layout/filter/attribute counts, raw data and total size. - diff [-r] [-q] [-d D] [-p R] A B [OBJ1 [OBJ2]]: structural and value differences, exit 0/1/2 like h5diff. - check [--data] FILE: walks every object, parses every message, verifies the checksums of every v2+ structure (including the fractal heap blocks the library never checks), checks chunk indexes against their datasets and raw data for out-of-file or overlapping extents; every problem with its address. Values over --max-bytes are reported, not read; dense-storage heaps are verified before objects are read from them; panics are caught (exit 3). Tests compare with h5ls, h5stat, h5dump and h5diff and with h5py's values, and flip the checksum of every checksummed structure in a v1.14-format file. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
59 lines
1.8 KiB
Rust
59 lines
1.8 KiB
Rust
//! The `h5rs` binary. A panic anywhere is a bug: it is caught, reported as
|
|
//! an internal error and turned into exit status 3, never a crash.
|
|
|
|
use std::io::Write;
|
|
use std::panic::{self, AssertUnwindSafe};
|
|
|
|
use clawhdf5_tools::cli::Out;
|
|
|
|
/// Exit status for an internal error (a caught panic).
|
|
const INTERNAL_ERROR: i32 = 3;
|
|
|
|
fn main() {
|
|
panic::set_hook(Box::new(|info| {
|
|
let msg = if let Some(s) = info.payload().downcast_ref::<&str>() {
|
|
(*s).to_string()
|
|
} else if let Some(s) = info.payload().downcast_ref::<String>() {
|
|
s.clone()
|
|
} else {
|
|
"unknown panic".into()
|
|
};
|
|
let at = info
|
|
.location()
|
|
.map(|l| format!(" at {}:{}", l.file(), l.line()))
|
|
.unwrap_or_default();
|
|
eprintln!("h5rs: internal error (this is a bug; please report it): {msg}{at}");
|
|
}));
|
|
let argv: Vec<String> = std::env::args().skip(1).collect();
|
|
let stdout = std::io::stdout();
|
|
let mut o = std::io::BufWriter::new(stdout.lock());
|
|
let mut e = std::io::stderr();
|
|
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
|
let mut out = Out {
|
|
o: &mut o,
|
|
e: &mut e,
|
|
};
|
|
clawhdf5_tools::run(argv, &mut out)
|
|
}));
|
|
let code = match result {
|
|
Ok(Ok(code)) => match o.flush() {
|
|
Ok(()) => code,
|
|
Err(err) if err.kind() == std::io::ErrorKind::BrokenPipe => code,
|
|
Err(err) => {
|
|
eprintln!("h5rs: {err}");
|
|
2
|
|
}
|
|
},
|
|
Ok(Err(err)) if err.kind() == std::io::ErrorKind::BrokenPipe => 0,
|
|
Ok(Err(err)) => {
|
|
eprintln!("h5rs: {err}");
|
|
2
|
|
}
|
|
Err(_) => {
|
|
let _ = o.flush();
|
|
INTERNAL_ERROR
|
|
}
|
|
};
|
|
std::process::exit(code);
|
|
}
|