#![forbid(unsafe_code)]
use std::process::ExitCode;
use zdump_rs::civil::parse_iso_utc;
use zdump_rs::witness::rows_to_json_array;
use zdump_rs::{parse, WitnessRow, PROBE_DEFAULT};
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
match run(&args) {
Ok(()) => ExitCode::SUCCESS,
Err((code, msg)) => {
eprintln!("zdump-rs: {msg}");
ExitCode::from(code)
}
}
}
fn run(args: &[String]) -> Result<(), (u8, String)> {
if args.is_empty() || args[0] == "-h" || args[0] == "--help" {
print_help();
return Ok(());
}
if args[0] != "inspect" {
return Err((
2,
format!("unknown subcommand {:?} (try `inspect`)", args[0]),
));
}
let mut tzif: Option<String> = None; let mut ats: Vec<String> = Vec::new(); let mut json = false; let mut probe_default = false; let mut i = 1; while i < args.len() {
match args[i].as_str() {
"--tzif" => {
i += 1;
tzif = Some(
args.get(i)
.ok_or((2, "--tzif needs a path".to_string()))?
.clone(),
);
}
"--at" => {
i += 1;
ats.push(
args.get(i)
.ok_or((2, "--at needs an instant".to_string()))?
.clone(),
);
}
"--json" => json = true,
"--probe-default" => probe_default = true,
other => return Err((2, format!("unknown flag {other:?}"))),
}
i += 1;
}
let path = tzif.ok_or((2, "missing --tzif FILE".to_string()))?;
if probe_default {
ats.extend(PROBE_DEFAULT.iter().map(|s| s.to_string()));
}
if ats.is_empty() {
return Err((
2,
"no instants: give --at <ISO8601> (repeatable) or --probe-default".to_string(),
));
}
let bytes = std::fs::read(&path).map_err(|e| (1, format!("cannot read {path:?}: {e}")))?;
let z = parse(&bytes).map_err(|e| (1, format!("not valid TZif ({path:?}): {e}")))?;
let mut rows = Vec::new();
for a in &ats {
let t = parse_iso_utc(a).map_err(|e| (2, format!("bad --at {a:?}: {e}")))?;
rows.push(WitnessRow::build(&path, &z, t));
}
if json {
print!("{}", rows_to_json_array(&rows));
} else {
for r in &rows {
println!("{}", r.to_text());
}
}
Ok(())
}
fn print_help() {
println!(
"zdump-rs — bounded, independent TZif witness (companion to zic-rs)\n\n\
USAGE:\n \
zdump-rs inspect --tzif FILE --at 2026-01-01T00:00:00Z [--at ...] [--json]\n \
zdump-rs inspect --tzif FILE --probe-default [--json]\n\n\
NON-CLAIMS: not full zdump, not stdout parity, not all flags, not locale behaviour,\n \
not a replacement oracle, not civil-time truth; footer/leap projection is Phase 2."
);
}