From b2374eb1746f54f58ecf1a3ac5d375b3d0f15da0 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Mon, 3 Mar 2025 21:03:24 +1300 Subject: Report malformed switches as errors Previously, malformed arguments were silently ignored when encountered. This could cause unexpected behaviour if the malformed argument is safety critical, so now an error is reported. --- src/switchboard.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'src/switchboard.rs') diff --git a/src/switchboard.rs b/src/switchboard.rs index f19db13..1c3ed81 100644 --- a/src/switchboard.rs +++ b/src/switchboard.rs @@ -15,7 +15,7 @@ pub struct Switchboard { // All queried values. pub values: HashMap, // All query errors - pub errors: Vec, + pub errors: Vec, // Total number of popped positional arguments pub i: usize, } @@ -26,6 +26,7 @@ impl Switchboard { let mut switches = Vec::new(); let mut unprocessed = None; let mut args = VecDeque::from(args); + let mut errors = Vec::new(); while let Some(arg) = args.pop_front() { if arg.is_empty() { @@ -33,23 +34,27 @@ impl Switchboard { } else if arg == "--" { unprocessed = Some(Vec::from(args)); break; - } else if let Some(arg) = arg.strip_prefix("--") { - let (name, value) = match arg.split_once("=") { + } else if let Some(stripped) = arg.strip_prefix("--") { + let (name, value) = match stripped.split_once("=") { Some((name, "")) => (name, None), Some((name, value)) => (name, Some(value.to_string())), - None => (arg, None), + None => (stripped, None), }; - if name.is_empty() { continue } - switches.push((SwitchName::Long(name.to_string()), value)); - } else if let Some(arg) = arg.strip_prefix("-") { - let (name, value) = match arg.split_once("=") { + match !name.is_empty() { + true => switches.push((SwitchName::Long(name.to_string()), value)), + false => errors.push(SwitchboardError::Malformed(arg.to_string())), + } + } else if let Some(stripped) = arg.strip_prefix("-") { + let (name, value) = match stripped.split_once("=") { Some((name, "")) => (name, None), Some((name, value)) => (name, Some(value.to_string())), - None => (arg, None), + None => (stripped, None), }; let chars: Vec = name.chars().collect(); - if chars.len() != 1 { continue } - switches.push((SwitchName::Short(chars[0]), value)); + match chars.len() == 1 { + true => switches.push((SwitchName::Short(chars[0]), value)), + false => errors.push(SwitchboardError::Malformed(arg.to_string())), + } } else { positional.push(arg) } @@ -58,7 +63,6 @@ impl Switchboard { positional.reverse(); let program = positional.pop().unwrap(); let values = HashMap::new(); - let errors = Vec::new(); let i = 0; Self { program, positional, switches, unprocessed, values, errors, i @@ -109,15 +113,18 @@ impl Switchboard { } for error in &self.errors { match error { - QueryError::MissingNamed(name) => { + SwitchboardError::MissingNamed(name) => { error!("The {name} switch is required") } - QueryError::MissingPositional(name) => { + SwitchboardError::MissingPositional(name) => { error!("The <{name}> argument is required") } - QueryError::Repeated(name) => { + SwitchboardError::Repeated(name) => { error!("The {name} switch was passed multiple times") } + SwitchboardError::Malformed(string) => { + error!("The '{string}' argument is malformed") + } } } std::process::exit(1); -- cgit v1.2.3-70-g09d2