You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
3.2 KiB

use super::*;
use std::{
num::{
NonZeroUsize,
ParseIntError,
},
};
use lazy_static::lazy_static;
#[inline] pub fn program_name() -> &'static str
{
lazy_static!{
static ref PROG: &'static str = Box::leak(std::env::args().next().unwrap().into_boxed_str());
}
&PROG[..]
}
pub fn usage() -> !
{
#[cfg(feature="splash")]
splash::print();
println!(r"Usage: {prog} [--max-children <number>] [-] <files...>
Usage: {prog} --help
OPTIONS:
--max-children <number> Max subprocesses allowed to live at once. Infinite by default.
ENVIRONMENT VARS:
LEANIFY=<process name> Path to leanify executable, defaults to looking in `PATH' if set.", prog = program_name());
std::process::exit(1)
}
#[derive(Debug)]
pub enum Error {
#[cfg(nightly)] BadNumber(std::num::IntErrorKind),
#[cfg(not(nightly))] BadNumber(()),
NoFiles,
}
impl std::error::Error for Error{}
impl std::fmt::Display for Error
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
//write!(f, "arg parsing failed: ")?;
match self {
Self::BadNumber(_v) => {
write!(f, "expected non-zero integer")?;
#[cfg(nightly)] use std::num::IntErrorKind;
#[cfg(nightly)] return match _v {
IntErrorKind::Empty => write!(f, ": argument empty"),
IntErrorKind::InvalidDigit => write!(f, ": invalid digit"),
IntErrorKind::Overflow => write!(f, ": conversion would result in overflow"),
IntErrorKind::Underflow => write!(f, ": conversion would result in underflow"),
IntErrorKind::Zero => write!(f, ": found zero"),
_=> Ok(()),
};
#[cfg(not(nightly))] Ok(())
},
Self::NoFiles => write!(f, "need at least one argument")
}
}
}
impl From<ParseIntError> for Error
{
fn from(_er: ParseIntError) -> Self
{
#[cfg(nightly)] return Self::BadNumber(_er.kind().clone());
#[cfg(not(nightly))] Self::BadNumber
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config
{
pub max_children: Option<NonZeroUsize>,
pub files: Vec<String>,
}
impl Default for Config
{
#[inline]
fn default() -> Self
{
Self {
max_children: None,
files: Vec::new(),
}
}
}
/// Parse the `env::args()`
#[inline] pub fn parse_args() -> Result<Config, Error>
{
let args = std::env::args();
if args.len() <= 1 {
println!("Warning: No arguments specified, try passing `--help`.");
}
parse(args.skip(1))
}
fn parse<I,T>(args: I) -> Result<Config, Error>
where I: IntoIterator<Item=T>,
T: Into<String>
{
let mut args = args.into_iter().map(|x| x.into());
let mut cfg = Config::default();
let mut reading=true;
let mut first=true;
while let Some(arg) = args.next() {
if reading {
let lw_arg = arg.trim().to_lowercase();
if first {
match lw_arg.as_str() {
"--help" => {
usage()
},
_ => (),
}
}
first=false;
match lw_arg.as_str() {
"--max-children" => {
if let Some(nzi) = args.next() {
cfg.max_children = Some(nzi.parse()?);
continue;
}
}
"-" => {
reading= false;
continue;
},
_ => (),
}
}
reading = false;
cfg.files.push(arg);
}
if cfg.files.len() == 0 {
return Err(Error::NoFiles);
}
Ok(cfg)
}