use clap::Parser;
use wavetools::{compare_signal_names, diff_waves, open_and_read_waves, NameOptions};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "wavediff")]
#[command(about = "Compare two waveform files (FST or VCD)", long_about = "\
Compare two waveform files (FST or VCD format) by signal name and value.
Exit codes:
0 files are identical
1 differences found
2 error
Examples:
wavediff baseline.fst current.fst
wavediff --start 100 --end 500 sim1.vcd sim2.vcd
wavediff --epsilon 0.001 analog1.fst analog2.vcd")]
struct Args {
file1: PathBuf,
file2: PathBuf,
#[arg(short = 's', long)]
start: Option<u64>,
#[arg(short = 'e', long)]
end: Option<u64>,
#[arg(long)]
epsilon: Option<f64>,
}
fn main() {
let args = Args::parse();
match run(args) {
Ok(has_differences) => {
if has_differences {
std::process::exit(1);
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(2);
}
}
}
fn run(args: Args) -> Result<bool, String> {
if let (Some(s), Some(e)) = (args.start, args.end) {
if s > e {
return Err(format!("--start ({}) must be <= --end ({})", s, e));
}
}
if let Some(eps) = args.epsilon {
if eps < 0.0 {
return Err(format!("--epsilon must be non-negative, got {}", eps));
}
}
let name_options = NameOptions::default();
let (reader1, handle_to_names1, reader2, handle_to_names2) =
open_and_read_waves(&args.file1, &args.file2, &name_options)?;
let (only_in_1, only_in_2) = compare_signal_names(&handle_to_names1, &handle_to_names2);
if !only_in_1.is_empty() || !only_in_2.is_empty() {
eprintln!("Signal name mismatch:");
let print_sorted = |label: std::path::Display, names: std::collections::HashSet<String>| {
eprintln!(" Only in {}:", label);
let mut names: Vec<_> = names.into_iter().collect();
names.sort();
for name in names {
eprintln!(" {}", name);
}
};
if !only_in_1.is_empty() {
print_sorted(args.file1.display(), only_in_1);
}
if !only_in_2.is_empty() {
print_sorted(args.file2.display(), only_in_2);
}
return Err("Signal names differ between files".to_string());
}
let mut stdout = std::io::stdout();
let has_differences = diff_waves(
&mut stdout,
reader1,
&handle_to_names1,
reader2,
&handle_to_names2,
args.start.unwrap_or(0),
args.end,
args.epsilon,
)
.map_err(|e| format!("Failed to diff files: {}", e))?;
Ok(has_differences)
}