// Std use std::collections::hash_map::{Entry, Iter}; use std::collections::HashMap; use std::ffi::OsStr; use std::ops::Deref; use std::mem; // Internal use args::{ArgMatches, MatchedArg, SubCommand}; use args::AnyArg; use args::settings::ArgSettings; #[doc(hidden)] #[allow(missing_debug_implementations)] pub struct ArgMatcher<'a>(pub ArgMatches<'a>); impl<'a> Default for ArgMatcher<'a> { fn default() -> Self { ArgMatcher(ArgMatches::default()) } } impl<'a> ArgMatcher<'a> { pub fn new() -> Self { ArgMatcher::default() } pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>, check_all: bool) { debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); if let Some(aa) = a { let mut self_done = false; if let Some(a_overrides) = aa.overrides() { for overr in a_overrides { debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr); if overr == &aa.name() { self_done = true; self.handle_self_overrides(a); } else if self.is_present(overr) { debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr); self.remove(overr); for i in (0 .. required.len()).rev() { if &required[i] == overr { debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr); required.swap_remove(i); break; } } overrides.push((overr, aa.name())); } else { overrides.push((overr, aa.name())); } } } if check_all && !self_done { self.handle_self_overrides(a); } } } pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) { debugln!("ArgMatcher::handle_self_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); if let Some(aa) = a { if !aa.has_switch() || aa.is_set(ArgSettings::Multiple) { // positional args can't override self or else we would never advance to the next // Also flags with --multiple set are ignored otherwise we could never have more // than one return; } if let Some(ma) = self.get_mut(aa.name()) { if ma.vals.len() > 1 { // swap_remove(0) would be O(1) but does not preserve order, which // we need ma.vals.remove(0); ma.occurs = 1; } else if !aa.takes_value() && ma.occurs > 1 { ma.occurs = 1; } } } } pub fn is_present(&self, name: &str) -> bool { self.0.is_present(name) } pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) { debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec ); let mut vals_map = HashMap::new(); self.fill_in_global_values(global_arg_vec, &mut vals_map); } fn fill_in_global_values( &mut self, global_arg_vec: &[&'a str], vals_map: &mut HashMap<&'a str, MatchedArg>, ) { for global_arg in global_arg_vec { if let Some(ma) = self.get(global_arg) { // We have to check if the parent's global arg wasn't used but still exists // such as from a default value. // // For example, `myprog subcommand --global-arg=value` where --global-arg defines // a default value of `other` myprog would have an existing MatchedArg for // --global-arg where the value is `other`, however the occurs will be 0. let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { if parent_ma.occurs > 0 && ma.occurs == 0 { parent_ma.clone() } else { ma.clone() } } else { ma.clone() }; vals_map.insert(global_arg, to_update); } } if let Some(ref mut sc) = self.0.subcommand { let mut am = ArgMatcher(mem::replace(&mut sc.matches, ArgMatches::new())); am.fill_in_global_values(global_arg_vec, vals_map); mem::swap(&mut am.0, &mut sc.matches); } for (name, matched_arg) in vals_map.into_iter() { self.0.args.insert(name, matched_arg.clone()); } } pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> { self.0.args.get_mut(arg) } pub fn get(&self, arg: &str) -> Option<&MatchedArg> { self.0.args.get(arg) } pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); } pub fn remove_all(&mut self, args: &[&str]) { for &arg in args { self.0.args.remove(arg); } } pub fn insert(&mut self, name: &'a str) { self.0.args.insert(name, MatchedArg::new()); } pub fn contains(&self, arg: &str) -> bool { self.0.args.contains_key(arg) } pub fn is_empty(&self) -> bool { self.0.args.is_empty() } pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); } pub fn arg_names(&'a self) -> Vec<&'a str> { self.0.args.keys().map(Deref::deref).collect() } pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> { self.0.args.entry(arg) } pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); } pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() } pub fn iter(&self) -> Iter<&str, MatchedArg> { self.0.args.iter() } pub fn inc_occurrence_of(&mut self, arg: &'a str) { debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg); if let Some(a) = self.get_mut(arg) { a.occurs += 1; return; } debugln!("ArgMatcher::inc_occurrence_of: first instance"); self.insert(arg); } pub fn inc_occurrences_of(&mut self, args: &[&'a str]) { debugln!("ArgMatcher::inc_occurrences_of: args={:?}", args); for arg in args { self.inc_occurrence_of(arg); } } pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) { let ma = self.entry(arg).or_insert(MatchedArg { occurs: 0, indices: Vec::with_capacity(1), vals: Vec::with_capacity(1), }); ma.vals.push(val.to_owned()); } pub fn add_index_to(&mut self, arg: &'a str, idx: usize) { let ma = self.entry(arg).or_insert(MatchedArg { occurs: 0, indices: Vec::with_capacity(1), vals: Vec::new(), }); ma.indices.push(idx); } pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool where A: AnyArg<'a, 'b>, { debugln!("ArgMatcher::needs_more_vals: o={}", o.name()); if let Some(ma) = self.get(o.name()) { if let Some(num) = o.num_vals() { debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num); return if o.is_set(ArgSettings::Multiple) { ((ma.vals.len() as u64) % num) != 0 } else { num != (ma.vals.len() as u64) }; } else if let Some(num) = o.max_vals() { debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num); return !((ma.vals.len() as u64) > num); } else if o.min_vals().is_some() { debugln!("ArgMatcher::needs_more_vals: min_vals...true"); return true; } return o.is_set(ArgSettings::Multiple); } true } } impl<'a> Into> for ArgMatcher<'a> { fn into(self) -> ArgMatches<'a> { self.0 } }