summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 8ca45fb82eda8fa0ac39f7a921cedefd532b1841 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::process::ExitCode;

mod definitions;
mod animalia;

fn do_write<W, E: Error>(path: &str, write_func: W) -> Result<(), Box<dyn Error>>
where
	W: FnOnce(BufWriter<File>) -> Result<(), E>,
{
	println!("Writing output to {path}...");
	let tmp_name = format!(".{path}.tmp");
	let file = File::create(&tmp_name).map_err(|e| format!("Error creating {tmp_name}: {e}"))?;
	let writer = BufWriter::new(file);
	write_func(writer).map_err(|e| format!("Error writing to {tmp_name}: {e}"))?;
	_ = std::fs::remove_file(path); // OK if this already exists
	std::fs::rename(&tmp_name, path)
		.map_err(|e| format!("Error renaming {tmp_name} => {path}: {e}"))?;
	Ok(())
}

fn try_main() -> Result<(), Box<dyn Error>> {
	let mut args = std::env::args_os().skip(1);
	let command = args.next();
	let no_command = "No command specified. Commands available:
- definitions
- animalia";
	let Some(command) = command else {
		return Err(no_command.into());
	};
	if command == "-h" || command == "--help" {
		return Err(no_command.into());
	}
	let mut command_args = vec![];
	for arg in args {
		let Some(arg) = arg.to_str() else {
			return Err(format!(
				"Bad UTF-8 in argument: {}",
				arg.to_string_lossy().escape_debug()
			)
			.into());
		};
		command_args.push(arg.to_owned());
	}
	match &command.to_string_lossy()[..] {
		"definitions" => definitions::main(command_args),
		"animalia" => animalia::main(command_args),
		x => Err(format!("Unrecognized command: {x}").into()),
	}
}

fn main() -> ExitCode {
	use std::time::Instant;
	let start_time = Instant::now();
	if let Err(e) = try_main() {
		eprintln!("Error: {e}");
		return ExitCode::FAILURE;
	}
	println!(
		"Time taken: {:?}",
		Instant::now().duration_since(start_time)
	);
	ExitCode::SUCCESS
}