use std::collections::HashMap;
use crate::result::ParseResult;
use crate::types::ParseError;
pub fn parse_loose() -> Result<ParseResult, ParseError> {
let mut args = Vec::new();
for os_arg in std::env::args_os().skip(1) {
match os_arg.into_string() {
Ok(s) => args.push(s),
Err(bad) => return Err(ParseError::InvalidUtf8(bad.to_string_lossy().into_owned())),
}
}
parse_loose_from(args)
}
pub(crate) fn parse_loose_from(args: Vec<String>) -> Result<ParseResult, ParseError> {
let mut flag_values: HashMap<String, bool> = HashMap::new();
let mut option_values: HashMap<String, Option<String>> = HashMap::new();
let mut positional_values: Vec<String> = Vec::new();
let mut rest_are_positional = false;
let mut i = 0;
while i < args.len() {
let token = &args[i];
if rest_are_positional {
positional_values.push(token.clone());
i += 1;
continue;
}
if token == "--" {
rest_are_positional = true;
i += 1;
continue;
}
if token == "--help" || token == "-h" {
return Err(ParseError::HelpRequested(String::from(
"Usage: [FLAGS] [OPTIONS] [ARGS]\n",
)));
}
if let Some(after) = token.strip_prefix("--") {
if let Some(eq_pos) = after.find('=') {
let key = &after[..eq_pos];
let value = &after[eq_pos + 1..];
option_values.insert(key.to_string(), Some(value.to_string()));
} else {
let key = after;
if i + 1 < args.len() && !args[i + 1].starts_with('-') {
i += 1;
option_values.insert(key.to_string(), Some(args[i].clone()));
} else {
flag_values.insert(key.to_string(), true);
}
}
} else if token.starts_with('-') && token.len() > 1 {
let after = &token[1..];
if let Some(eq_pos) = after.find('=') {
let key = &after[..eq_pos];
let value = &after[eq_pos + 1..];
option_values.insert(key.to_string(), Some(value.to_string()));
} else {
let key = after;
if i + 1 < args.len() && !args[i + 1].starts_with('-') {
i += 1;
option_values.insert(key.to_string(), Some(args[i].clone()));
} else {
flag_values.insert(key.to_string(), true);
}
}
} else {
positional_values.push(token.clone());
}
i += 1;
}
Ok(ParseResult::new(
flag_values,
option_values.into_iter().filter_map(|(k, v)| v.map(|val| (k, vec![val]))).collect(),
positional_values,
None,
None,
))
}