From 4357a2be846e43fa6c200e0b43c40be9c7a849ae Mon Sep 17 00:00:00 2001 From: Alison Watson Date: Thu, 30 May 2019 03:11:05 -0400 Subject: [PATCH] leela: rewrite using clap --- source/leela/Cargo.toml | 2 +- source/leela/main.rs | 252 ++++++++++------------------------------ 2 files changed, 60 insertions(+), 194 deletions(-) diff --git a/source/leela/Cargo.toml b/source/leela/Cargo.toml index bbf314f..69f1459 100644 --- a/source/leela/Cargo.toml +++ b/source/leela/Cargo.toml @@ -7,7 +7,7 @@ description = "Maraiah testbed program." edition = "2018" [dependencies] -argparse = "0.2" +clap = "2" maraiah = {path = "../..", features = ["serde_obj"]} memmap = "0.7" serde = "1.0" diff --git a/source/leela/main.rs b/source/leela/main.rs index 0ceab46..86b446d 100644 --- a/source/leela/main.rs +++ b/source/leela/main.rs @@ -1,244 +1,110 @@ +#![allow(clippy::unit_arg)] + use maraiah::{durandal::{err::*, file::*, image::*, sound::*}, marathon::{machdr, map, ppm, shp, snd, tga, wav}}; use std::{fs, io, slice::from_ref}; -fn make_tga(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()> +fn open(path: &str) -> ResultS { - let mut out = io::BufWriter::new(fs::File::create(fname)?); - - tga::write_tga(&mut out, im) + let fp = fs::File::open(path)?; + Ok(unsafe {memmap::Mmap::map(&fp)?}) } -fn make_ppm(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()> +fn file_read(path: &str, f: F) -> ResultS + where F: FnOnce(&[u8]) -> ResultS { - let mut out = io::BufWriter::new(fs::File::create(fname)?); + let mm = open(path)?; + let bp = &mm[machdr::try_mac_header(&mm)..]; - ppm::write_ppm(&mut out, im) + f(bp) } -fn make_yaml(opt: &Options, data: &T) -> ResultS<()> - where T: serde::Serialize + std::fmt::Debug +fn exists(path: String) -> Result<(), String> { - if opt.out_debug { - println!("{:#?}", data); - } else { - serde_yaml::to_writer(io::stdout(), &data)?; - println!(); + match std::fs::metadata(path) { + Ok(_) => Ok(()), + Err(e) => Err(e.to_string()), } - - Ok(()) } -fn make_wav(fname: &str, snd: &impl Sound) -> ResultS<()> -{ - let mut out = io::BufWriter::new(fs::File::create(fname)?); - wav::write_wav(&mut out, snd) -} - -fn process_wad(opt: &Options, b: &[u8]) -> ResultS<()> -{ - let wad = map::read(b)?; - make_yaml(opt, &wad)?; - Ok(()) -} - -fn dump_bitmaps(opt: &Options, c: &shp::coll::Collection, i: usize) +fn each_value<'a, F>(opt: &'a clap::ArgMatches<'a>, name: &str, mut f: F) -> ResultS<()> + where F: FnMut(&'a str) -> ResultS<()> { - if !opt.shp_bmp { - return Ok(()); - } - - for (j, bmp) in c.bmps.iter().enumerate() { - if opt.shp_bmp_all { - for (k, tab) in c.tabs.iter().enumerate() { - let fname = format!("{}/shape{}_{}_{}.tga", opt.out_dir, i, j, k); - make_tga(opt, &fname, &shp::bmap::ImageShp::new(bmp, &tab))?; - } - } else { - let fname = format!("{}/shape{}_{}.tga", opt.out_dir, i, j); - make_tga(opt, &fname, &shp::bmap::ImageShp::new(bmp, &c.tabs[0]))?; + if let Some(values) = opt.values_of(name) { + for value in values { + f(value)?; } } Ok(()) } -fn write_shp_objs(opt: &Options, cl: &shp::coll::Collection) -> ResultS<()> +fn dump_info(data: impl std::fmt::Debug) { - if opt.shp_tab {make_yaml(opt, &cl.tabs)?;} - if opt.shp_frm {make_yaml(opt, &cl.frms)?;} - if opt.shp_seq {make_yaml(opt, &cl.seqs)?;} - - Ok(()) + println!("{:#?}", data); } -fn process_shp(opt: &Options, b: &[u8]) -> ResultS<()> +fn sub_data_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()> { - for (i, cl) in shp::read(b)?.iter().enumerate() { - if let Some(cl) = &cl.0 { - dump_bitmaps(opt, cl, i)?; - write_shp_objs(opt, cl)?; - } - - if let Some(cl) = &cl.1 { - dump_bitmaps(opt, cl, i + 100)?; - write_shp_objs(opt, cl)?; - } - } - - Ok(()) + unimplemented!(); } -fn dump_sounds(opt: &Options, st: &snd::SoundTable, c: usize) -> ResultS<()> +fn sub_dump_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()> { - if !opt.snd_dump { - return Ok(()); - } - - for (k, sd) in st { - for (i, snd) in sd.sounds.iter().enumerate() { - let fname = format!("{}/snd{}_{}_{}.wav", opt.out_dir, c, k, i); - make_wav(&fname, snd)?; - } - } - - Ok(()) + unimplemented!(); } -fn process_snd(opt: &Options, b: &[u8]) -> ResultS<()> +fn sub_info_c<'a>(opt: &clap::ArgMatches<'a>) -> ResultS<()> { - for (c, st) in snd::read(b)?.iter().enumerate() { - dump_sounds(opt, st, c)?; - } + each_value(opt, "map", |f| Ok(dump_info(file_read(f, map::read)?)))?; + each_value(opt, "shp", |f| Ok(dump_info(file_read(f, shp::read)?)))?; + each_value(opt, "snd", |f| Ok(dump_info(file_read(f, snd::read)?)))?; Ok(()) } -fn process_ppm(opt: &Options, b: &[u8]) -> ResultS<()> -{ - let im = ppm::read_ppm(b)?; - - let fname = format!("{}/out.tga", opt.out_dir); - make_tga(opt, &fname, &im)?; - - let fname = format!("{}/out.ppm", opt.out_dir); - make_ppm(opt, &fname, &im) -} - fn main() -> ResultS<()> { - use argparse::*; + use clap::clap_app; - let mut opt = Options::default(); - { - let mut ap = ArgumentParser::new(); + let sub_data = + clap_app!(@subcommand data => + (about: "Dumps data into a discrete folder/YAML format")); - macro_rules! arg { - ($name:expr, $ref:expr, $type:expr, $desc:expr) => { - ap.refer(&mut $ref).add_option(from_ref(&$name), $type, $desc); - }; - } + let sub_dump = + clap_app!(@subcommand dump => + (about: "Dumps particular parts of data")); - ap.set_description(env!("CARGO_PKG_DESCRIPTION")); + let sub_info = + clap_app!(@subcommand info => + (about: "Outputs debug info") + (@group files => + (@attributes +required +multiple) + (@arg map: -m --map [file]... {exists} "Loads a Map file") + (@arg shp: -s --shp [file]... {exists} "Loads a Shapes file") + (@arg snd: -n --snd [file]... {exists} "Loads a Sounds file"))); - ap.add_option(&["-v", "--version"], - Print(concat!(env!("CARGO_PKG_NAME"), - " ", - env!("CARGO_PKG_VERSION")).to_string()), - "Show the version"); + let opt = + clap_app!((env!("CARGO_PKG_NAME")) => + (version: env!("CARGO_PKG_VERSION")) + (author: env!("CARGO_PKG_AUTHORS")) + (about: env!("CARGO_PKG_DESCRIPTION")) + (setting: clap::AppSettings::SubcommandRequiredElseHelp) + (subcommand: sub_data) + (subcommand: sub_dump) + (subcommand: sub_info)); - ap.refer(&mut opt.inputs) - .add_argument("inputs", Collect, "Input files"); + let opt = opt.get_matches(); - arg!("--shp-write-tab", - opt.shp_tab, - StoreTrue, - "shp: Dump all CLUTs as YAML to standard output"); - - arg!("--shp-dump-bitmaps", - opt.shp_bmp, - StoreTrue, - "shp: Dump bitmaps into a folder"); - - arg!("--shp-dump-more-bitmaps", - opt.shp_bmp_all, - StoreTrue, - "shp: Dump all color variations of each bitmap"); - - arg!("--shp-write-frm", - opt.shp_frm, - StoreTrue, - "shp: Dump all frames as YAML to standard output"); - - arg!("--shp-write-seq", - opt.shp_seq, - StoreTrue, - "shp: Dump all sequences as YAML to standard output"); - - arg!("--snd-dump", - opt.snd_dump, - StoreTrue, - "snd: Dump all sounds to WAVE files"); - - arg!("--out-dir", - opt.out_dir, - Store, - "Sets output directory for dump options"); - - arg!("--out-debug", - opt.out_debug, - StoreTrue, - "Writes debugging output rather than YAML"); - - ap.parse_args_or_exit(); - } - - if opt.shp_bmp_all { - opt.shp_bmp = true; - } - - if opt.out_dir.is_empty() { - opt.out_dir = ".".to_string(); - } - - validate_folder_path(&opt.out_dir)?; - - for arg in &opt.inputs { - let (typ, fna) = if let Some(st) = arg.find(':') { - arg.split_at(st + 1) - } else { - ("wad:", arg.as_str()) - }; - - let fp = fs::File::open(fna)?; - let mm = unsafe {memmap::Mmap::map(&fp)?}; - let b = &mm[machdr::try_mac_header(&mm)..]; - - match typ { - "wad:" => process_wad(&opt, b), - "shp:" => process_shp(&opt, b), - "snd:" => process_snd(&opt, b), - "ppm:" => process_ppm(&opt, b), - _ => Err(err_msg("invalid file type specified on commandline")), - }?; + match opt.subcommand() { + ("data", Some(opt)) => sub_data_c(opt)?, + ("dump", Some(opt)) => sub_dump_c(opt)?, + ("info", Some(opt)) => sub_info_c(opt)?, + _ => unreachable!(), } Ok(()) } -#[derive(Default)] -struct Options -{ - inputs: Vec, - out_dir: String, - out_debug: bool, - shp_tab: bool, - shp_bmp: bool, - shp_bmp_all: bool, - shp_frm: bool, - shp_seq: bool, - snd_dump: bool, -} - // EOF