use clap::Parser;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::ExitCode;
use crate::{Options, conversion_map, convert};
const POPULARITY: &[&str] = &[
"png", "jpeg", "webp", "gif", "svg", "pdf", "ico",
"html", "md", "txt", "json", "yaml", "json5", "csv", "tsv", "xml", "toml",
"ini", "mp3", "wav", "flac", "aac", "ogg", "midi", "stl", "obj", "tif", "bmp", "tga", "ps", "eps", "js", "css",
];
fn popularity_rank(fmt: &str) -> (usize, String) {
match POPULARITY.iter().position(|p| *p == fmt) {
Some(i) => (i, String::new()),
None => (usize::MAX, fmt.to_string()),
}
}
fn print_list() {
let mut by_source: BTreeMap<&'static str, Vec<&'static str>> =
BTreeMap::new();
for (from, to) in conversion_map::list_all() {
by_source.entry(from).or_default().push(to);
}
let width = by_source.keys().map(|k| k.len()).max().unwrap_or(0);
for (from, mut targets) in by_source {
targets.sort_by_key(|t| popularity_rank(t));
targets.dedup();
println!("{from:<width$} -> {}", targets.join(", "));
}
}
#[derive(Parser, Debug)]
#[command(
name = "univert",
version,
about = "Universal file converter",
override_usage = "univert <input-file> <output-file> [OPTIONS]"
)]
pub struct Args {
#[arg(short, long)]
pub force: bool,
#[arg(short, long)]
pub list: bool,
#[arg(short, long)]
pub split: bool,
pub input: Option<PathBuf>,
pub output: Option<PathBuf>,
}
pub fn run() -> ExitCode {
#[cfg(unix)]
{
use std::os::raw::c_int;
unsafe extern "C" {
fn signal(signum: c_int, handler: usize) -> usize;
}
const SIGPIPE: c_int = 13;
const SIG_DFL: usize = 0;
unsafe {
signal(SIGPIPE, SIG_DFL);
}
}
let args = Args::parse();
if args.list {
print_list();
return ExitCode::SUCCESS;
}
let (Some(input), Some(output)) = (args.input.as_ref(), args.output.as_ref())
else {
eprintln!("usage: univert <input-file> <output-file> [OPTIONS]");
return ExitCode::from(2);
};
let options = Options {
force: args.force,
split: args.split,
};
match convert(input, output, &options) {
Ok(()) => {
println!("Converted {} to {}", input.display(), output.display());
ExitCode::SUCCESS
}
Err(err) => {
eprintln!("{err}");
ExitCode::FAILURE
}
}
}