//! 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::() { 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 = 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); }