use std::env; use crate::{Error, Input, Result}; // NOTE: I assumed I should keep this "DIY". I would most likely use some "de facto" external // libraries like `clap`, `serde`, ect. #[derive(Debug, Default)] pub struct Cli { pub files: Vec, pub opts: Opts, } impl Cli { pub fn parse() -> Result { env::args() .skip(1) .try_fold(Cli::default(), |mut cli, opt| { match opt.as_str() { "-" => cli.files.push(Input::Stdin), o if o.starts_with("--") => cli.opts.parse_long(o)?, o if o.starts_with('-') => cli.opts.parse_short(o)?, s => cli.files.push(s.into()), }; Ok(cli) }) .map(|mut cli| { if cli.files.is_empty() { cli.files.push(Input::Stdin); } cli }) } } #[derive(Debug, Default)] pub struct Opts { /// number nonempty output lines, overrides -n pub number_nonblank: bool, /// display $ at end of each line pub show_ends: bool, /// number all output lines pub number: bool, /// suppress repeated empty output lines pub squeeze_blank: bool, /// display TAB characters as ^I pub show_tabs: bool, /// use ^ and M- notation, except for LFD and TAB pub show_nonprinting: bool, /// display help and exit pub help: bool, /// output version information and exit pub version: bool, } impl Opts { fn parse_long(&mut self, s: &str) -> Result<()> { match s { "--number-nonblank" => self.number_nonblank = true, "--show-ends" => self.show_ends = true, "--number" => self.number = true, "--squeeze-blank" => self.squeeze_blank = true, "--show-tabs" => self.show_tabs = true, "--show-nonprinting" => self.show_nonprinting = true, "--help" => self.help = true, "--version" => self.version = true, s => return Err(Error::Opts(s.to_string())), }; Ok(()) } fn parse_short(&mut self, s: &str) -> Result<()> { for o in s.chars().skip(1) { match o { 'b' => self.number_nonblank = true, 'E' => self.show_ends = true, 'n' => self.number = true, 's' => self.squeeze_blank = true, 'T' => self.show_tabs = true, 'v' => self.show_nonprinting = true, s => return Err(Error::Opts(s.to_string())), }; } Ok(()) } }