use super::*; use lazy_static::lazy_static; use std::{ error, fmt, path::{ PathBuf, Path, }, }; lazy_static! { pub static ref PROGRAM_NAME: &'static str = Box::leak(std::env::args().next().unwrap().into_boxed_str()); } /// Print usage then exit with code `1` pub fn usage() -> ! { println!(concat!("lolistealer version ", env!("CARGO_PKG_VERSION"))); println!(concat!(" written by ",env!("CARGO_PKG_AUTHORS")," with <3")); println!(" licensed with GNU GPL 3.0 or later\n"); println!("Usage: {} [-q] [--rating ] [--tags ] []", &PROGRAM_NAME[..]); println!("Usage: {} --help", &PROGRAM_NAME[..]); println!("Options:"); println!(" -q\t\t\tQuiet mode, do not output progress"); println!(" --rating \tEither `s`afe, `q`uestionable, or `e`xplicit"); println!(" --tags \tFilter downloaded images out by tags, see below for format."); println!("Tags filter expreession:"); println!(" tag_name\tMust contain this tag"); println!(" -tag_name\tMust not contains this tag"); println!(" +tag_name\tMust contains at least one tag prepended with `+`"); println!("Note:"); println!(" Tag filter expreession is a single argument, tags must be seperated with spaces. e.g. 'tag1 -tag2 +tag3 +tag4'"); #[cfg(feature="async")] println!("\n (compiled with threading support)"); std::process::exit(1) } /// Parse the system args pub fn parse_args() -> Result { parse(std::env::args().skip(1)) } fn try_dir(path: impl AsRef) -> Result { let path = path.as_ref(); if path.is_dir() { Ok(config::OutputType::Directory(path.to_owned())) } else if !path.exists() { Ok(config::OutputType::File(path.to_owned())) } else { Err(Error::FileExists(path.to_owned())) } } #[derive(Debug)] pub enum Mode { Normal(config::Config), Help, } fn parse(args: I) -> Result where I: IntoIterator { let mut args = args.into_iter(); let mut rating = config::Rating::default(); let mut paths = Vec::new(); let mut one = String::default(); let mut reading = true; let mut tags = Vec::new(); let mut verbose = Default::default(); macro_rules! take_one { () => { { if let Some(new) = args.next() { one = new; true } else { false } } }; } while let Some(arg) = args.next() { if reading { match arg.to_lowercase().trim() { "-" => reading = false, "--help" => return Ok(Mode::Help), "-q" => verbose = config::Verbosity::Silent, "--rating" if take_one!() => rating = one.parse::()?, "--tags" if take_one!() => tags = tags::parse(&one), _ => paths.push(try_dir(arg)?), } } else { paths.push(try_dir(arg)?); } } if paths.len() < 1 { return Err(Error::NoOutput); } Ok(Mode::Normal(config::Config{rating, output: paths, tags, verbose})) } #[derive(Debug)] pub enum Error { UnknownRating(String), FileExists(PathBuf), NoOutput, Internal(Box), Unknown, } impl error::Error for Error{} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::NoOutput => write!(f, "need at least one output, try `{} --help`", &PROGRAM_NAME[..]), Error::UnknownRating(rating) => write!(f, "{} is not a valid rating", rating), Error::FileExists(path) => write!(f, "file already exists: {:?}", path), Error::Internal(bx) => write!(f, "internal error: {}", bx), _ => write!(f, "unknown error"), } } }