use std::{io::Write, process::ExitCode};
use nix::errno::Errno;
use syd::{
eprintfln,
hash::{hash, hash_list, hex_encode_lower},
printfln,
};
#[cfg(all(
not(target_os = "android"),
not(target_arch = "loongarch64"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
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" => {
for &(name, size) in hash_list() {
printfln!("{name:<12} {size}")?;
}
return Ok(ExitCode::SUCCESS);
}
Some(f) => f,
None => {
eprintfln!("Error: -a <algorithm> is required.")?;
eprintfln!("Run syd-sum -h for help.")?;
return Ok(ExitCode::FAILURE);
}
};
match opt_path.as_deref() {
None | Some("-") => {
let digest = hash(&opt_func, std::io::stdin())?;
if opt_bino {
std::io::stdout().write_all(&digest)?;
} else {
printfln!("{}", hex_encode_lower(&digest)?)?;
}
}
Some(path) => {
#[expect(clippy::disallowed_methods)]
#[expect(clippy::disallowed_types)]
let file = std::fs::File::open(path)?;
let digest = hash(&opt_func, &file)?;
if opt_bino {
std::io::stdout().write_all(&digest)?;
} else {
printfln!("{} {path}", hex_encode_lower(&digest)?)?;
}
}
}
Ok(ExitCode::SUCCESS)
}
fn help() -> Result<(), Errno> {
printfln!("Usage: syd-sum -a <algorithm> [-bhx] <file|->")?;
printfln!("Given a file, print the checksum of the file.")?;
printfln!("Given no positional arguments, calculate the checksum of standard input.")?;
printfln!()?;
printfln!(" -a <alg> Hash algorithm (required).")?;
printfln!(" Use `-a list' to list available algorithms and their digest sizes.")?;
printfln!(" Examples: sha256, sha512, sha3-512, blake2b-256, md5, crc32c")?;
printfln!(" -b Print binary output rather than hex-encoded string.")?;
printfln!(" -x Print hexadecimal output (default).")?;
printfln!(" -h Display this help.")?;
Ok(())
}