Files
clawhdf5/crates/clawhdf5-tools/src/main.rs
T
osobhandClaude Opus 5.5 310448bfcb feat(tools): h5rs, pure-Rust HDF5 tools (ls, dump, stat, diff, check)
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]>
2026-09-26 00:29:28 -05:00

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);
}