use std::{io::Write, process::ExitCode};
use data_encoding::HEXLOWER;
use nix::errno::Errno;
use syd::{fd::open_static_proc, hash::hash_list};
#[cfg(all(
not(coverage),
not(feature = "prof"),
not(target_os = "android"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
let mut opt_func: Option<String> = None;
let mut opt_bino = false; let mut opt_path = None;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') => {
help();
return Ok(ExitCode::SUCCESS);
}
Short('b') => opt_bino = true,
Short('x') => opt_bino = false,
Short('a') => opt_func = Some(parser.value()?.to_str().ok_or(Errno::EINVAL)?.to_string()),
Value(path) if opt_path.is_none() => {
opt_path = Some(path.to_str().ok_or(Errno::EINVAL).map(String::from)?)
}
_ => return Err(arg.unexpected().into()),
}
}
let opt_func = match opt_func {
Some(f) if f == "list" => {
open_static_proc()?;
for name in hash_list()? {
println!("{name}");
}
return Ok(ExitCode::SUCCESS);
}
Some(f) => f,
None => {
eprintln!("Error: -a <algorithm> is required.");
eprintln!("Run syd-sum -h for help.");
return Ok(ExitCode::FAILURE);
}
};
match opt_path.as_deref() {
None | Some("-") => {
let digest = syd::hash::hash(&opt_func, std::io::stdin())?;
if opt_bino {
std::io::stdout().write_all(&digest)?;
} else {
println!("{}", HEXLOWER.encode(&digest));
}
}
Some(path) => {
#[expect(clippy::disallowed_methods)]
#[expect(clippy::disallowed_types)]
let file = std::fs::File::open(path)?;
let digest = syd::hash::hash(&opt_func, &file)?;
if opt_bino {
std::io::stdout().write_all(&digest)?;
} else {
println!("{} {path}", HEXLOWER.encode(&digest));
}
}
}
Ok(ExitCode::SUCCESS)
}
fn help() {
println!("Usage: syd-sum -a <algorithm> [-bhx] <file|->");
println!("Given a file, print the checksum of the file.");
println!("Given no positional arguments, calculate the checksum of standard input.");
println!();
println!(" -a <alg> Hash algorithm (required).");
println!(" Any algorithm listed in proc_crypto(5) with type ahash or shash.");
println!(" Use `-a list' to list available algorithms and their digest sizes.");
println!(" Examples: sha256, sha512, sha3-512, blake2b-256, md5, crc32c");
println!(" -b Print binary output rather than hex-encoded string.");
println!(" -x Print hexadecimal output (default).");
println!(" -h Display this help.");
}