diff --git a/src/app/macros.rs b/src/app/macros.rs deleted file mode 100644 index e3f15e96733..00000000000 --- a/src/app/macros.rs +++ /dev/null @@ -1,165 +0,0 @@ -macro_rules! remove_overriden { - (@remove_requires $rem_from:expr, $a:ident.$ov:ident) => { - if let Some(ora) = $a.$ov() { - for i in (0 .. $rem_from.len()).rev() { - let should_remove = ora.iter().any(|&(_, ref name)| name == &$rem_from[i]); - if should_remove { $rem_from.swap_remove(i); } - } - } - }; - (@remove $rem_from:expr, $a:ident.$ov:ident) => { - if let Some(ora) = $a.$ov() { - vec_remove_all!($rem_from, ora.iter()); - } - }; - (@arg $_self:ident, $arg:ident) => { - remove_overriden!(@remove_requires $_self.required, $arg.requires); - remove_overriden!(@remove $_self.blacklist, $arg.blacklist); - remove_overriden!(@remove $_self.overrides, $arg.overrides); - }; - ($_self:ident, $name:expr) => { - debugln!("remove_overriden!;"); - if let Some(o) = $_self.opts.iter() .find(|o| o.b.name == *$name) { - remove_overriden!(@arg $_self, o); - } else if let Some(f) = $_self.flags.iter() .find(|f| f.b.name == *$name) { - remove_overriden!(@arg $_self, f); - } else { - let p = $_self.positionals.values() - .find(|p| p.b.name == *$name) - .expect(INTERNAL_ERROR_MSG); - remove_overriden!(@arg $_self, p); - } - }; -} - -macro_rules! arg_post_processing { - ($me:ident, $arg:ident, $matcher:ident) => { - debugln!("arg_post_processing!;"); - // Handle POSIX overrides - debug!("arg_post_processing!: Is '{}' in overrides...", $arg.to_string()); - if $me.overrides.contains(&$arg.name()) { - if let Some(ref name) = find_name_from!($me, &$arg.name(), overrides, $matcher) { - sdebugln!("Yes by {}", name); - $matcher.remove(name); - remove_overriden!($me, name); - } - } else { sdebugln!("No"); } - - // Add overrides - debug!("arg_post_processing!: Does '{}' have overrides...", $arg.to_string()); - if let Some(or) = $arg.overrides() { - sdebugln!("Yes"); - $matcher.remove_all(or); - for pa in or { remove_overriden!($me, pa); } - $me.overrides.extend(or); - vec_remove_all!($me.required, or.iter()); - } else { sdebugln!("No"); } - - // Handle conflicts - debug!("arg_post_processing!: Does '{}' have conflicts...", $arg.to_string()); - if let Some(bl) = $arg.blacklist() { - sdebugln!("Yes"); - - for c in bl { - // Inject two-way conflicts - debug!("arg_post_processing!: Has '{}' already been matched...", c); - if $matcher.contains(c) { - sdebugln!("Yes"); - // find who blacklisted us... - $me.blacklist.push(&$arg.b.name); - } else { - sdebugln!("No"); - } - } - - $me.blacklist.extend_from_slice(bl); - vec_remove_all!($me.overrides, bl.iter()); - // vec_remove_all!($me.required, bl.iter()); - } else { sdebugln!("No"); } - - // Add all required args which aren't already found in matcher to the master - // list - debug!("arg_post_processing!: Does '{}' have requirements...", $arg.to_string()); - if let Some(reqs) = $arg.requires() { - for n in reqs.iter() - .filter(|&&(val, _)| val.is_none()) - .filter(|&&(_, req)| !$matcher.contains(&req)) - .map(|&(_, name)| name) { - - $me.required.push(n); - } - } else { sdebugln!("No"); } - - _handle_group_reqs!($me, $arg); - }; -} - -macro_rules! _handle_group_reqs{ - ($me:ident, $arg:ident) => ({ - use args::AnyArg; - debugln!("_handle_group_reqs!;"); - for grp in &$me.groups { - let found = if grp.args.contains(&$arg.name()) { - if let Some(ref reqs) = grp.requires { - debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs); - $me.required.extend(reqs); - } - if let Some(ref bl) = grp.conflicts { - $me.blacklist.extend(bl); - } - true // What if arg is in more than one group with different reqs? - } else { - false - }; - debugln!("_handle_group_reqs!:iter: grp={}, found={:?}", grp.name, found); - if found { - for i in (0 .. $me.required.len()).rev() { - let should_remove = grp.args.contains(&$me.required[i]); - if should_remove { $me.required.swap_remove(i); } - } - debugln!("_handle_group_reqs!:iter: Adding args from group to blacklist...{:?}", grp.args); - if !grp.multiple { - $me.blacklist.extend(&grp.args); - debugln!("_handle_group_reqs!: removing {:?} from blacklist", $arg.name()); - for i in (0 .. $me.blacklist.len()).rev() { - let should_remove = $me.blacklist[i] == $arg.name(); - if should_remove { $me.blacklist.swap_remove(i); } - } - } - } - } - }) -} - -macro_rules! parse_positional { - ( - $_self:ident, - $p:ident, - $arg_os:ident, - $pos_counter:ident, - $matcher:ident - ) => { - debugln!("parse_positional!;"); - - if !$_self.is_set(AS::TrailingValues) && - ($_self.is_set(AS::TrailingVarArg) && - $pos_counter == $_self.positionals.len()) { - $_self.settings.set(AS::TrailingValues); - } - let _ = $_self.add_val_to_arg($p, &$arg_os, $matcher)?; - - $matcher.inc_occurrence_of($p.b.name); - let _ = $_self.groups_for_arg($p.b.name) - .and_then(|vec| Some($matcher.inc_occurrences_of(&*vec))); - if $_self.cache.map_or(true, |name| name != $p.b.name) { - arg_post_processing!($_self, $p, $matcher); - $_self.cache = Some($p.b.name); - } - - $_self.settings.set(AS::ValidArgFound); - // Only increment the positional counter if it doesn't allow multiples - if !$p.b.settings.is_set(ArgSettings::Multiple) { - $pos_counter += 1; - } - }; -} diff --git a/src/app/parser.rs b/src/app/parser.rs index 22c45c9a769..01e0e1f3561 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -61,8 +61,7 @@ where pub global_args: Vec>, pub required: Vec<&'a str>, pub r_ifs: Vec<(&'a str, &'b str, &'a str)>, - pub blacklist: Vec<&'b str>, - pub overrides: Vec<&'b str>, + pub overrides: Vec<(&'b str, &'a str)>, help_short: Option, version_short: Option, cache: Option<&'a str>, @@ -346,9 +345,9 @@ where if let Some(ref reqs) = group.requires { self.required.extend_from_slice(reqs); } - if let Some(ref bl) = group.conflicts { - self.blacklist.extend_from_slice(bl); - } +// if let Some(ref bl) = group.conflicts { +// self.blacklist.extend_from_slice(bl); +// } } if self.groups.iter().any(|g| g.name == group.name) { let grp = self.groups @@ -773,12 +772,8 @@ where // allow wrong self convention due to self.valid_neg_num = true and it's a private method #[cfg_attr(feature = "lints", allow(wrong_self_convention))] - fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool { - debugln!( - "Parser::is_new_arg: arg={:?}, Needs Val of={:?}", - arg_os, - needs_val_of - ); + fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { + debugln!( "Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { true } else if self.is_set(AS::AllowNegativeNumbers) { @@ -807,12 +802,10 @@ where .expect(INTERNAL_ERROR_MSG); (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) } + ParseResult::ValuesDone => return true, _ => false, }; - debugln!( - "Parser::is_new_arg: Arg::allow_leading_hyphen({:?})", - arg_allows_tac - ); + debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac ); // Is this a new argument, or values from a previous option? let mut ret = if arg_os.starts_with(b"--") { @@ -913,7 +906,52 @@ where } } - if !starts_new_arg { + if starts_new_arg { + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + } + + if arg_os.starts_with(b"--") { + needs_val_of = self.parse_long_arg(matcher, &arg_os)?; + debugln!( "Parser:get_matches_with: After parse_long_arg {:?}", needs_val_of ); + match needs_val_of { + ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 { + // Try to parse short args like normal, if AllowLeadingHyphen or + // AllowNegativeNumbers is set, parse_short_arg will *not* throw + // an error, and instead return Ok(None) + needs_val_of = self.parse_short_arg(matcher, &arg_os)?; + // If it's None, we then check if one of those two AppSettings was set + debugln!( + "Parser:get_matches_with: After parse_short_arg {:?}", + needs_val_of + ); + match needs_val_of { + ParseResult::MaybeNegNum => { + if !(arg_os.to_string_lossy().parse::().is_ok() + || arg_os.to_string_lossy().parse::().is_ok()) + { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + }, + ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } + + } else { if let ParseResult::Opt(name) = needs_val_of { // Check to see if parsing a value from a previous arg let arg = self.opts @@ -925,62 +963,20 @@ where // get the next value from the iterator continue; } - } else if arg_os.starts_with(b"--") { - needs_val_of = self.parse_long_arg(matcher, &arg_os)?; - debugln!( - "Parser:get_matches_with: After parse_long_arg {:?}", - needs_val_of - ); - match needs_val_of { - ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => { - continue - } - _ => (), - } - } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 { - // Try to parse short args like normal, if AllowLeadingHyphen or - // AllowNegativeNumbers is set, parse_short_arg will *not* throw - // an error, and instead return Ok(None) - needs_val_of = self.parse_short_arg(matcher, &arg_os)?; - // If it's None, we then check if one of those two AppSettings was set - debugln!( - "Parser:get_matches_with: After parse_short_arg {:?}", - needs_val_of - ); - match needs_val_of { - ParseResult::MaybeNegNum => { - if !(arg_os.to_string_lossy().parse::().is_ok() - || arg_os.to_string_lossy().parse::().is_ok()) - { - return Err(Error::unknown_argument( - &*arg_os.to_string_lossy(), - "", - &*usage::create_error_usage(self, matcher, None), - self.color(), - )); - } - } - ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => { - continue - } - _ => (), - } } + } - if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) - && !self.is_set(AS::InferSubcommands) - { - if let Some(cdate) = - suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) - { - return Err(Error::invalid_subcommand( - arg_os.to_string_lossy().into_owned(), - cdate, - self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), - &*usage::create_error_usage(self, matcher, None), - self.color(), - )); - } + if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) + && !self.is_set(AS::InferSubcommands) + { + if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) { + return Err(Error::invalid_subcommand( + arg_os.to_string_lossy().into_owned(), + cdate, + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); } } @@ -1035,7 +1031,29 @@ where self.color(), )); } - parse_positional!(self, p, arg_os, pos_counter, matcher); + if !self.is_set(AS::TrailingValues) && + (self.is_set(AS::TrailingVarArg) && + pos_counter == self.positionals.len()) { + self.settings.set(AS::TrailingValues); + } + if self.cache.map_or(true, |name| name != p.b.name) { + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + } + self.cache = Some(p.b.name); + } + let _ = self.add_val_to_arg(p, &arg_os, matcher)?; + + matcher.inc_occurrence_of(p.b.name); + let _ = self.groups_for_arg(p.b.name) + .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + + self.settings.set(AS::ValidArgFound); + // Only increment the positional counter if it doesn't allow multiples + if !p.b.settings.is_set(ArgSettings::Multiple) { + pos_counter += 1; + } self.settings.set(AS::ValidArgFound); } else if self.is_set(AS::AllowExternalSubcommands) { // Get external subcommand name @@ -1136,9 +1154,34 @@ where }); } + // In case the last arg was new, we need to process it's overrides + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + } + + self.remove_overrides(matcher); + Validator::new(self).validate(needs_val_of, subcmd_name, matcher) } + fn remove_overrides(&mut self, matcher: &mut ArgMatcher) { + debugln!("Parser::remove_overrides:{:?};", self.overrides); + for &(overr, name) in &self.overrides { + debugln!("Parser::remove_overrides:iter:({},{});", overr, name); + if matcher.is_present(overr) { + debugln!("Parser::remove_overrides:iter:({},{}): removing {};", overr, name, name); + matcher.remove(name); + for i in (0 .. self.required.len()).rev() { + debugln!("Parser::remove_overrides:iter:({},{}): removing required {};", overr, name, name); + if self.required[i] == name { + self.required.swap_remove(i); + break; + } + } + } + } + } fn propagate_help_version(&mut self) { debugln!("Parser::propagate_help_version;"); @@ -1483,7 +1526,6 @@ where self.settings.set(AS::ValidArgFound); let ret = self.parse_opt(val, opt, val.is_some(), matcher)?; if self.cache.map_or(true, |name| name != opt.b.name) { - arg_post_processing!(self, opt, matcher); self.cache = Some(opt.b.name); } @@ -1501,10 +1543,9 @@ where self.parse_flag(flag, matcher)?; // Handle conflicts, requirements, etc. - // if self.cache.map_or(true, |name| name != flag.b.name) { - arg_post_processing!(self, flag, matcher); - // self.cache = Some(flag.b.name); - // } + if self.cache.map_or(true, |name| name != flag.b.name) { + self.cache = Some(flag.b.name); + } return Ok(ParseResult::Flag); } else if self.is_set(AS::AllowLeadingHyphen) { @@ -1580,7 +1621,6 @@ where let ret = self.parse_opt(val, opt, false, matcher)?; if self.cache.map_or(true, |name| name != opt.b.name) { - arg_post_processing!(self, opt, matcher); self.cache = Some(opt.b.name); } @@ -1595,7 +1635,6 @@ where // Handle conflicts, requirements, overrides, etc. // Must be called here due to mutablilty if self.cache.map_or(true, |name| name != flag.b.name) { - arg_post_processing!(self, flag, matcher); self.cache = Some(flag.b.name); } } else { @@ -1844,7 +1883,6 @@ where $_self.add_val_to_arg($a, OsStr::new(val), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { - arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } } else if $m.get($a.b.name).is_some() { @@ -1855,7 +1893,6 @@ where $_self.add_val_to_arg($a, OsStr::new(val), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { - arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } } @@ -1881,7 +1918,6 @@ where if add { $_self.add_val_to_arg($a, OsStr::new(default), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { - arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } done = true; @@ -1920,7 +1956,6 @@ where $_self.add_val_to_arg($a, OsStr::new(val), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { - arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } } @@ -1929,7 +1964,6 @@ where $_self.add_val_to_arg($a, OsStr::new(val), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { - arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } } @@ -1972,7 +2006,7 @@ where } } - pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg> { + pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> { if let Some(f) = find_by_name!(self, name, flags, iter) { return Some(f); } diff --git a/src/app/validator.rs b/src/app/validator.rs index 01373dd5f9f..9751321a149 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -78,7 +78,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { Ok(()) } - fn validate_values( + fn validate_arg_values( &self, arg: &A, ma: &MatchedArg, @@ -87,11 +87,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { where A: AnyArg<'a, 'b> + Display, { - debugln!("Validator::validate_values: arg={:?}", arg.name()); + debugln!("Validator::validate_arg_values: arg={:?}", arg.name()); for val in &ma.vals { if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() { debugln!( - "Validator::validate_values: invalid UTF-8 found in val {:?}", + "Validator::validate_arg_values: invalid UTF-8 found in val {:?}", val ); return Err(Error::invalid_utf8( @@ -100,7 +100,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { )); } if let Some(p_vals) = arg.possible_vals() { - debugln!("Validator::validate_values: possible_vals={:?}", p_vals); + debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals); let val_str = val.to_string_lossy(); let ok = if arg.is_set(ArgSettings::CaseInsensitive) { p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str)) @@ -120,7 +120,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() && matcher.contains(&*arg.name()) { - debugln!("Validator::validate_values: illegal empty val found"); + debugln!("Validator::validate_arg_values: illegal empty val found"); return Err(Error::empty_value( arg, &*usage::create_error_usage(self.0, matcher, None), @@ -128,7 +128,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { )); } if let Some(vtor) = arg.validator() { - debug!("Validator::validate_values: checking validator..."); + debug!("Validator::validate_arg_values: checking validator..."); if let Err(e) = vtor(val.to_string_lossy().into_owned()) { sdebugln!("error"); return Err(Error::value_validation(Some(arg), e, self.0.color())); @@ -137,7 +137,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { } } if let Some(vtor) = arg.validator_os() { - debug!("Validator::validate_values: checking validator_os..."); + debug!("Validator::validate_arg_values: checking validator_os..."); if let Err(e) = vtor(val) { sdebugln!("error"); return Err(Error::value_validation( @@ -153,44 +153,83 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { Ok(()) } - fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { - debugln!( - "Validator::validate_blacklist: blacklist={:?}", - self.0.blacklist + fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> { + debugln!("build_err!: name={}", name); + let mut c_with = find_from!(self.0, &name, blacklist, &matcher); + c_with = c_with.or( + self.0.find_any_arg(&name).map_or(None, |aa| aa.blacklist()) + .map_or(None, + |bl| bl.iter().find(|arg| matcher.contains(arg))) + .map_or(None, |an| self.0.find_any_arg(an)) + .map_or(None, |aa| Some(format!("{}", aa))) ); - macro_rules! build_err { - ($p:expr, $name:expr, $matcher:ident) => ({ - debugln!("build_err!: name={}", $name); - let mut c_with = find_from!($p, &$name, blacklist, &$matcher); - c_with = c_with.or( - $p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist()) - .map_or(None, - |bl| bl.iter().find(|arg| $matcher.contains(arg))) - .map_or(None, |an| $p.find_any_arg(an)) - .map_or(None, |aa| Some(format!("{}", aa))) - ); - debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &$name); - $matcher.remove(&$name); - let usg = usage::create_error_usage($p, $matcher, None); - if let Some(f) = find_by_name!($p, $name, flags, iter) { - debugln!("build_err!: It was a flag..."); - Error::argument_conflict(f, c_with, &*usg, self.0.color()) - } else if let Some(o) = find_by_name!($p, $name, opts, iter) { - debugln!("build_err!: It was an option..."); - Error::argument_conflict(o, c_with, &*usg, self.0.color()) - } else { - match find_by_name!($p, $name, positionals, values) { - Some(p) => { - debugln!("build_err!: It was a positional..."); - Error::argument_conflict(p, c_with, &*usg, self.0.color()) - }, - None => panic!(INTERNAL_ERROR_MSG) + debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name); +// matcher.remove(&name); + let usg = usage::create_error_usage(self.0, matcher, None); + if let Some(f) = find_by_name!(self.0, name, flags, iter) { + debugln!("build_err!: It was a flag..."); + Err(Error::argument_conflict(f, c_with, &*usg, self.0.color())) + } else if let Some(o) = find_by_name!(self.0, name, opts, iter) { + debugln!("build_err!: It was an option..."); + Err(Error::argument_conflict(o, c_with, &*usg, self.0.color())) + } else { + match find_by_name!(self.0, name, positionals, values) { + Some(p) => { + debugln!("build_err!: It was a positional..."); + Err(Error::argument_conflict(p, c_with, &*usg, self.0.color())) + }, + None => panic!(INTERNAL_ERROR_MSG) + } + } + } + + fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { + debugln!("Validator::validate_blacklist;"); + let mut conflicts: Vec<&str> = vec![]; + for (&name, _) in matcher.iter() { + debugln!("Validator::validate_blacklist:iter:{};", name); + if let Some(grps) = self.0.groups_for_arg(name) { + for grp in &grps { + if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) { + if !g.multiple { + for arg in &g.args { + if arg == &name { + continue; + } + conflicts.push(arg); + } + } + if let Some(ref gc) = g.conflicts { + conflicts.extend(&*gc); + } } } - }); + } + if let Some(arg) = find_any_by_name!(self.0, name) { + if let Some(bl) = arg.blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } else { + debugln!("Validator::validate_blacklist:iter:{}:group;", name); + let args = self.0.arg_names_in_group(name); + for arg in &args { + debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg); + if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } + } } - for name in &self.0.blacklist { + for name in &conflicts { debugln!( "Validator::validate_blacklist:iter:{}: Checking blacklisted arg", name @@ -213,7 +252,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { name, n ); - return Err(build_err!(self.0, n, matcher)); + return self.build_err(n, matcher); } } } else if let Some(ma) = matcher.get(name) { @@ -224,7 +263,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { should_err = ma.occurs > 0; } if should_err { - return Err(build_err!(self.0, *name, matcher)); + return self.build_err(*name, matcher); } } Ok(()) @@ -240,7 +279,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { ); if let Some(opt) = find_by_name!(self.0, *name, opts, iter) { self.validate_arg_num_vals(opt, ma, matcher)?; - self.validate_values(opt, ma, matcher)?; + self.validate_arg_values(opt, ma, matcher)?; self.validate_arg_requires(opt, ma, matcher)?; self.validate_arg_num_occurs(opt, ma, matcher)?; } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) { @@ -249,7 +288,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) { self.validate_arg_num_vals(pos, ma, matcher)?; self.validate_arg_num_occurs(pos, ma, matcher)?; - self.validate_values(pos, ma, matcher)?; + self.validate_arg_values(pos, ma, matcher)?; self.validate_arg_requires(pos, ma, matcher)?; } else { let grp = self.0 @@ -381,7 +420,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { where A: AnyArg<'a, 'b> + Display, { - debugln!("Validator::validate_arg_requires;"); + debugln!("Validator::validate_arg_requires:{};", a.name()); if let Some(a_reqs) = a.requires() { for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) { let missing_req = @@ -390,6 +429,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { return self.missing_required_error(matcher, None); } } + for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) { + if !matcher.contains(name) { + return self.missing_required_error(matcher, Some(name)); + } + } } Ok(()) } @@ -399,20 +443,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { "Validator::validate_required: required={:?};", self.0.required ); + 'outer: for name in &self.0.required { debugln!("Validator::validate_required:iter:{}:", name); if matcher.contains(name) { continue 'outer; } - if let Some(a) = find_by_name!(self.0, *name, flags, iter) { - if self.is_missing_required_ok(a, matcher) { - continue 'outer; - } - } else if let Some(a) = find_by_name!(self.0, *name, opts, iter) { - if self.is_missing_required_ok(a, matcher) { - continue 'outer; - } - } else if let Some(a) = find_by_name!(self.0, *name, positionals, values) { + if let Some(a) = find_any_by_name!(self.0, *name) { if self.is_missing_required_ok(a, matcher) { continue 'outer; } @@ -431,11 +468,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { Ok(()) } - fn validate_conflicts(&self, a: &A, matcher: &ArgMatcher) -> Option - where - A: AnyArg<'a, 'b>, - { - debugln!("Validator::validate_conflicts: a={:?};", a.name()); + fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { + debugln!("Validator::validate_arg_conflicts: a={:?};", a.name()); a.blacklist().map(|bl| { bl.iter().any(|conf| { matcher.contains(conf) @@ -448,10 +482,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { }) } - fn validate_required_unless(&self, a: &A, matcher: &ArgMatcher) -> Option - where - A: AnyArg<'a, 'b>, - { + fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { debugln!("Validator::validate_required_unless: a={:?};", a.name()); macro_rules! check { ($how:ident, $_self:expr, $a:ident, $m:ident) => {{ @@ -506,12 +537,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { } #[inline] - fn is_missing_required_ok(&self, a: &A, matcher: &ArgMatcher) -> bool - where - A: AnyArg<'a, 'b>, - { + fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool { debugln!("Validator::is_missing_required_ok: a={}", a.name()); - self.validate_conflicts(a, matcher).unwrap_or(false) + self.validate_arg_conflicts(a, matcher).unwrap_or(false) || self.validate_required_unless(a, matcher).unwrap_or(false) } } diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs index 9fa34c7fa06..eee52283328 100644 --- a/src/args/any_arg.rs +++ b/src/args/any_arg.rs @@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString}; // Internal use args::settings::ArgSettings; use map::{self, VecMap}; +use INTERNAL_ERROR_MSG; #[doc(hidden)] pub trait AnyArg<'n, 'e>: std_fmt::Display { @@ -41,3 +42,33 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display { pub trait DispOrder { fn disp_ord(&self) -> usize; } + +impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z { + fn name(&self) -> &'n str { (*self).name() } + fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() } + fn aliases(&self) -> Option> { (*self).aliases() } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() } + fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() } + fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() } + fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) } + fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) } + fn has_switch(&self) -> bool { (*self).has_switch() } + fn max_vals(&self) -> Option { (*self).max_vals() } + fn min_vals(&self) -> Option { (*self).min_vals() } + fn num_vals(&self) -> Option { (*self).num_vals() } + fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() } + fn validator(&self) -> Option<&Rc Result<(), String>>> { (*self).validator() } + fn validator_os(&self) -> Option<&Rc Result<(), OsString>>> { (*self).validator_os() } + fn short(&self) -> Option { (*self).short() } + fn long(&self) -> Option<&'e str> { (*self).long() } + fn val_delim(&self) -> Option { (*self).val_delim() } + fn takes_value(&self) -> bool { (*self).takes_value() } + fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() } + fn help(&self) -> Option<&'e str> { (*self).help() } + fn long_help(&self) -> Option<&'e str> { (*self).long_help() } + fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { (*self).default_vals_ifs() } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() } + fn longest_filter(&self) -> bool { (*self).longest_filter() } + fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() } +} diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index 4e76802e6ed..25f3fc5d749 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -21,11 +21,36 @@ impl<'a> Default for ArgMatcher<'a> { 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>) { + debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); + if let Some(aa) = a { + if let Some(a_overrides) = aa.overrides() { + for overr in a_overrides { + debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr); + 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; + } + } + } else { + overrides.push((overr, aa.name())); + } + } + } + } + } + + 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 - ); + 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); } diff --git a/src/macros.rs b/src/macros.rs index 51bb95a7b07..52fb35a4de9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -853,15 +853,15 @@ macro_rules! write_nspaces { } // convenience macro for remove an item from a vec -macro_rules! vec_remove_all { - ($vec:expr, $to_rem:expr) => { - debugln!("vec_remove_all! to_rem={:?}", $to_rem); - for i in (0 .. $vec.len()).rev() { - let should_remove = $to_rem.any(|name| name == &$vec[i]); - if should_remove { $vec.swap_remove(i); } - } - }; -} +//macro_rules! vec_remove_all { +// ($vec:expr, $to_rem:expr) => { +// debugln!("vec_remove_all! to_rem={:?}", $to_rem); +// for i in (0 .. $vec.len()).rev() { +// let should_remove = $to_rem.any(|name| name == &$vec[i]); +// if should_remove { $vec.swap_remove(i); } +// } +// }; +//} macro_rules! find_from { ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ let mut ret = None; @@ -892,36 +892,49 @@ macro_rules! find_from { }}; } -macro_rules! find_name_from { - ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ - let mut ret = None; - for k in $matcher.arg_names() { - if let Some(f) = find_by_name!($_self, k, flags, iter) { - if let Some(ref v) = f.$from() { - if v.contains($arg_name) { - ret = Some(f.b.name); - } - } - } - if let Some(o) = find_by_name!($_self, k, opts, iter) { - if let Some(ref v) = o.$from() { - if v.contains(&$arg_name) { - ret = Some(o.b.name); - } - } - } - if let Some(pos) = find_by_name!($_self, k, positionals, values) { - if let Some(ref v) = pos.$from() { - if v.contains($arg_name) { - ret = Some(pos.b.name); - } - } - } +//macro_rules! find_name_from { +// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ +// let mut ret = None; +// for k in $matcher.arg_names() { +// if let Some(f) = find_by_name!($_self, k, flags, iter) { +// if let Some(ref v) = f.$from() { +// if v.contains($arg_name) { +// ret = Some(f.b.name); +// } +// } +// } +// if let Some(o) = find_by_name!($_self, k, opts, iter) { +// if let Some(ref v) = o.$from() { +// if v.contains(&$arg_name) { +// ret = Some(o.b.name); +// } +// } +// } +// if let Some(pos) = find_by_name!($_self, k, positionals, values) { +// if let Some(ref v) = pos.$from() { +// if v.contains($arg_name) { +// ret = Some(pos.b.name); +// } +// } +// } +// } +// ret +// }}; +//} + + +macro_rules! find_any_by_name { + ($p:expr, $name:expr) => { + { + fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x } + find_by_name!($p, $name, flags, iter).map(as_trait_obj).or( + find_by_name!($p, $name, opts, iter).map(as_trait_obj).or( + find_by_name!($p, $name, positionals, values).map(as_trait_obj) + ) + ) } - ret - }}; + } } - // Finds an arg by name macro_rules! find_by_name { ($p:expr, $name:expr, $what:ident, $how:ident) => {