1 // std
2 use std::fmt::Display;
3 #[allow(deprecated, unused_imports)]
4 use std::ascii::AsciiExt;
5 
6 // Internal
7 use INTERNAL_ERROR_MSG;
8 use INVALID_UTF8;
9 use args::{AnyArg, ArgMatcher, MatchedArg};
10 use args::settings::ArgSettings;
11 use errors::{Error, ErrorKind};
12 use errors::Result as ClapResult;
13 use app::settings::AppSettings as AS;
14 use app::parser::{ParseResult, Parser};
15 use fmt::{Colorizer, ColorizerOption};
16 use app::usage;
17 
18 pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
19 where
20     'a: 'b,
21     'b: 'z;
22 
23 impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
new(p: &'z mut Parser<'a, 'b>) -> Self24     pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
25 
validate( &mut self, needs_val_of: ParseResult<'a>, subcmd_name: Option<String>, matcher: &mut ArgMatcher<'a>, ) -> ClapResult<()>26     pub fn validate(
27         &mut self,
28         needs_val_of: ParseResult<'a>,
29         subcmd_name: Option<String>,
30         matcher: &mut ArgMatcher<'a>,
31     ) -> ClapResult<()> {
32         debugln!("Validator::validate;");
33         let mut reqs_validated = false;
34         self.0.add_env(matcher)?;
35         self.0.add_defaults(matcher)?;
36         if let ParseResult::Opt(a) = needs_val_of {
37             debugln!("Validator::validate: needs_val_of={:?}", a);
38             let o = {
39                 self.0
40                 .opts
41                 .iter()
42                 .find(|o| o.b.name == a)
43                 .expect(INTERNAL_ERROR_MSG)
44                 .clone()
45             };
46             self.validate_required(matcher)?;
47             reqs_validated = true;
48             let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
49                 v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
50             } else {
51                 true
52             };
53             if should_err {
54                 return Err(Error::empty_value(
55                     &o,
56                     &*usage::create_error_usage(self.0, matcher, None),
57                     self.0.color(),
58                 ));
59             }
60         }
61 
62         if matcher.is_empty() && matcher.subcommand_name().is_none()
63             && self.0.is_set(AS::ArgRequiredElseHelp)
64         {
65             let mut out = vec![];
66             self.0.write_help_err(&mut out)?;
67             return Err(Error {
68                 message: String::from_utf8_lossy(&*out).into_owned(),
69                 kind: ErrorKind::MissingArgumentOrSubcommand,
70                 info: None,
71             });
72         }
73         self.validate_blacklist(matcher)?;
74         if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
75             self.validate_required(matcher)?;
76         }
77         self.validate_matched_args(matcher)?;
78         matcher.usage(usage::create_usage_with_title(self.0, &[]));
79 
80         Ok(())
81     }
82 
validate_arg_values<A>( &self, arg: &A, ma: &MatchedArg, matcher: &ArgMatcher<'a>, ) -> ClapResult<()> where A: AnyArg<'a, 'b> + Display,83     fn validate_arg_values<A>(
84         &self,
85         arg: &A,
86         ma: &MatchedArg,
87         matcher: &ArgMatcher<'a>,
88     ) -> ClapResult<()>
89     where
90         A: AnyArg<'a, 'b> + Display,
91     {
92         debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
93         for val in &ma.vals {
94             if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
95                 debugln!(
96                     "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
97                     val
98                 );
99                 return Err(Error::invalid_utf8(
100                     &*usage::create_error_usage(self.0, matcher, None),
101                     self.0.color(),
102                 ));
103             }
104             if let Some(p_vals) = arg.possible_vals() {
105                 debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
106                 let val_str = val.to_string_lossy();
107                 let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
108                     p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
109                 } else {
110                     p_vals.contains(&&*val_str)
111                 };
112                 if !ok {
113                     return Err(Error::invalid_value(
114                         val_str,
115                         p_vals,
116                         arg,
117                         &*usage::create_error_usage(self.0, matcher, None),
118                         self.0.color(),
119                     ));
120                 }
121             }
122             if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty()
123                 && matcher.contains(&*arg.name())
124             {
125                 debugln!("Validator::validate_arg_values: illegal empty val found");
126                 return Err(Error::empty_value(
127                     arg,
128                     &*usage::create_error_usage(self.0, matcher, None),
129                     self.0.color(),
130                 ));
131             }
132             if let Some(vtor) = arg.validator() {
133                 debug!("Validator::validate_arg_values: checking validator...");
134                 if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
135                     sdebugln!("error");
136                     return Err(Error::value_validation(Some(arg), e, self.0.color()));
137                 } else {
138                     sdebugln!("good");
139                 }
140             }
141             if let Some(vtor) = arg.validator_os() {
142                 debug!("Validator::validate_arg_values: checking validator_os...");
143                 if let Err(e) = vtor(val) {
144                     sdebugln!("error");
145                     return Err(Error::value_validation(
146                         Some(arg),
147                         (*e).to_string_lossy().to_string(),
148                         self.0.color(),
149                     ));
150                 } else {
151                     sdebugln!("good");
152                 }
153             }
154         }
155         Ok(())
156     }
157 
build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()>158     fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
159         debugln!("build_err!: name={}", name);
160         let mut c_with = find_from!(self.0, &name, blacklist, matcher);
161         c_with = c_with.or(
162         self.0.find_any_arg(name).map_or(None, |aa| aa.blacklist())
163             .map_or(None,
164                     |bl| bl.iter().find(|arg| matcher.contains(arg)))
165             .map_or(None, |an| self.0.find_any_arg(an))
166             .map_or(None, |aa| Some(format!("{}", aa)))
167         );
168         debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
169 //        matcher.remove(&name);
170         let usg = usage::create_error_usage(self.0, matcher, None);
171         if let Some(f) = find_by_name!(self.0, name, flags, iter) {
172             debugln!("build_err!: It was a flag...");
173             Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
174         } else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
175             debugln!("build_err!: It was an option...");
176             Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
177         } else {
178             match find_by_name!(self.0, name, positionals, values) {
179                 Some(p) => {
180                     debugln!("build_err!: It was a positional...");
181                     Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
182                 },
183                 None    => panic!(INTERNAL_ERROR_MSG)
184             }
185         }
186     }
187 
validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()>188     fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
189         debugln!("Validator::validate_blacklist;");
190         let mut conflicts: Vec<&str> = vec![];
191         for (&name, _) in matcher.iter() {
192             debugln!("Validator::validate_blacklist:iter:{};", name);
193             if let Some(grps) = self.0.groups_for_arg(name) {
194                 for grp in &grps {
195                     if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
196                         if !g.multiple {
197                             for arg in &g.args {
198                                 if arg == &name {
199                                     continue;
200                                 }
201                                 conflicts.push(arg);
202                             }
203                         }
204                         if let Some(ref gc) = g.conflicts {
205                             conflicts.extend(&*gc);
206                         }
207                     }
208                 }
209             }
210             if let Some(arg) = find_any_by_name!(self.0, name) {
211                 if let Some(bl) = arg.blacklist() {
212                     for conf in bl {
213                         if matcher.get(conf).is_some() {
214                             conflicts.push(conf);
215                         }
216                     }
217                 }
218             } else {
219                 debugln!("Validator::validate_blacklist:iter:{}:group;", name);
220                 let args = self.0.arg_names_in_group(name);
221                 for arg in &args {
222                     debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
223                     if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
224                         for conf in bl {
225                             if matcher.get(conf).is_some() {
226                                 conflicts.push(conf);
227                             }
228                         }
229                     }
230                 }
231             }
232         }
233 
234         for name in &conflicts {
235             debugln!(
236                 "Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
237                 name
238             );
239             let mut should_err = false;
240             if self.0.groups.iter().any(|g| &g.name == name) {
241                 debugln!(
242                     "Validator::validate_blacklist:iter:{}: groups contains it...",
243                     name
244                 );
245                 for n in self.0.arg_names_in_group(name) {
246                     debugln!(
247                         "Validator::validate_blacklist:iter:{}:iter:{}: looking in group...",
248                         name,
249                         n
250                     );
251                     if matcher.contains(n) {
252                         debugln!(
253                             "Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...",
254                             name,
255                             n
256                         );
257                         return self.build_err(n, matcher);
258                     }
259                 }
260             } else if let Some(ma) = matcher.get(name) {
261                 debugln!(
262                     "Validator::validate_blacklist:iter:{}: matcher contains it...",
263                     name
264                 );
265                 should_err = ma.occurs > 0;
266             }
267             if should_err {
268                 return self.build_err(*name, matcher);
269             }
270         }
271         Ok(())
272     }
273 
validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()>274     fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
275         debugln!("Validator::validate_matched_args;");
276         for (name, ma) in matcher.iter() {
277             debugln!(
278                 "Validator::validate_matched_args:iter:{}: vals={:#?}",
279                 name,
280                 ma.vals
281             );
282             if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
283                 self.validate_arg_num_vals(opt, ma, matcher)?;
284                 self.validate_arg_values(opt, ma, matcher)?;
285                 self.validate_arg_requires(opt, ma, matcher)?;
286                 self.validate_arg_num_occurs(opt, ma, matcher)?;
287             } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
288                 self.validate_arg_requires(flag, ma, matcher)?;
289                 self.validate_arg_num_occurs(flag, ma, matcher)?;
290             } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
291                 self.validate_arg_num_vals(pos, ma, matcher)?;
292                 self.validate_arg_num_occurs(pos, ma, matcher)?;
293                 self.validate_arg_values(pos, ma, matcher)?;
294                 self.validate_arg_requires(pos, ma, matcher)?;
295             } else {
296                 let grp = self.0
297                     .groups
298                     .iter()
299                     .find(|g| &g.name == name)
300                     .expect(INTERNAL_ERROR_MSG);
301                 if let Some(ref g_reqs) = grp.requires {
302                     if g_reqs.iter().any(|&n| !matcher.contains(n)) {
303                         return self.missing_required_error(matcher, None);
304                     }
305                 }
306             }
307         }
308         Ok(())
309     }
310 
validate_arg_num_occurs<A>( &self, a: &A, ma: &MatchedArg, matcher: &ArgMatcher, ) -> ClapResult<()> where A: AnyArg<'a, 'b> + Display,311     fn validate_arg_num_occurs<A>(
312         &self,
313         a: &A,
314         ma: &MatchedArg,
315         matcher: &ArgMatcher,
316     ) -> ClapResult<()>
317     where
318         A: AnyArg<'a, 'b> + Display,
319     {
320         debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
321         if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
322             // Not the first time, and we don't allow multiples
323             return Err(Error::unexpected_multiple_usage(
324                 a,
325                 &*usage::create_error_usage(self.0, matcher, None),
326                 self.0.color(),
327             ));
328         }
329         Ok(())
330     }
331 
validate_arg_num_vals<A>( &self, a: &A, ma: &MatchedArg, matcher: &ArgMatcher, ) -> ClapResult<()> where A: AnyArg<'a, 'b> + Display,332     fn validate_arg_num_vals<A>(
333         &self,
334         a: &A,
335         ma: &MatchedArg,
336         matcher: &ArgMatcher,
337     ) -> ClapResult<()>
338     where
339         A: AnyArg<'a, 'b> + Display,
340     {
341         debugln!("Validator::validate_arg_num_vals:{}", a.name());
342         if let Some(num) = a.num_vals() {
343             debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
344             let should_err = if a.is_set(ArgSettings::Multiple) {
345                 ((ma.vals.len() as u64) % num) != 0
346             } else {
347                 num != (ma.vals.len() as u64)
348             };
349             if should_err {
350                 debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
351                 return Err(Error::wrong_number_of_values(
352                     a,
353                     num,
354                     if a.is_set(ArgSettings::Multiple) {
355                         (ma.vals.len() % num as usize)
356                     } else {
357                         ma.vals.len()
358                     },
359                     if ma.vals.len() == 1
360                         || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1)
361                     {
362                         "as"
363                     } else {
364                         "ere"
365                     },
366                     &*usage::create_error_usage(self.0, matcher, None),
367                     self.0.color(),
368                 ));
369             }
370         }
371         if let Some(num) = a.max_vals() {
372             debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
373             if (ma.vals.len() as u64) > num {
374                 debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
375                 return Err(Error::too_many_values(
376                     ma.vals
377                         .iter()
378                         .last()
379                         .expect(INTERNAL_ERROR_MSG)
380                         .to_str()
381                         .expect(INVALID_UTF8),
382                     a,
383                     &*usage::create_error_usage(self.0, matcher, None),
384                     self.0.color(),
385                 ));
386             }
387         }
388         let min_vals_zero = if let Some(num) = a.min_vals() {
389             debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
390             if (ma.vals.len() as u64) < num && num != 0 {
391                 debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
392                 return Err(Error::too_few_values(
393                     a,
394                     num,
395                     ma.vals.len(),
396                     &*usage::create_error_usage(self.0, matcher, None),
397                     self.0.color(),
398                 ));
399             }
400             num == 0
401         } else {
402             false
403         };
404         // Issue 665 (https://github.com/clap-rs/clap/issues/665)
405         // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
406         if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
407             return Err(Error::empty_value(
408                 a,
409                 &*usage::create_error_usage(self.0, matcher, None),
410                 self.0.color(),
411             ));
412         }
413         Ok(())
414     }
415 
validate_arg_requires<A>( &self, a: &A, ma: &MatchedArg, matcher: &ArgMatcher, ) -> ClapResult<()> where A: AnyArg<'a, 'b> + Display,416     fn validate_arg_requires<A>(
417         &self,
418         a: &A,
419         ma: &MatchedArg,
420         matcher: &ArgMatcher,
421     ) -> ClapResult<()>
422     where
423         A: AnyArg<'a, 'b> + Display,
424     {
425         debugln!("Validator::validate_arg_requires:{};", a.name());
426         if let Some(a_reqs) = a.requires() {
427             for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
428                 let missing_req =
429                     |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
430                 if ma.vals.iter().any(missing_req) {
431                     return self.missing_required_error(matcher, None);
432                 }
433             }
434             for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
435                 if !matcher.contains(name) {
436                     return self.missing_required_error(matcher, Some(name));
437                 }
438             }
439         }
440         Ok(())
441     }
442 
validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()>443     fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> {
444         debugln!(
445             "Validator::validate_required: required={:?};",
446             self.0.required
447         );
448 
449         let mut should_err = false;
450         let mut to_rem = Vec::new();
451         for name in &self.0.required {
452             debugln!("Validator::validate_required:iter:{}:", name);
453             if matcher.contains(name) {
454                 continue;
455             }
456             if to_rem.contains(name) {
457                 continue;
458             } else if let Some(a) = find_any_by_name!(self.0, *name) {
459                 if self.is_missing_required_ok(a, matcher) {
460                     to_rem.push(a.name());
461                     if let Some(reqs) = a.requires() {
462                         for r in reqs
463                             .iter()
464                             .filter(|&&(val, _)| val.is_none())
465                             .map(|&(_, name)| name)
466                         {
467                             to_rem.push(r);
468                         }
469                     }
470                     continue;
471                 }
472             }
473             should_err = true;
474             break;
475         }
476         if should_err {
477             for r in &to_rem {
478                 'inner: for i in (0 .. self.0.required.len()).rev() {
479                     if &self.0.required[i] == r {
480                         self.0.required.swap_remove(i);
481                         break 'inner;
482                     }
483                 }
484             }
485             return self.missing_required_error(matcher, None);
486         }
487 
488         // Validate the conditionally required args
489         for &(a, v, r) in &self.0.r_ifs {
490             if let Some(ma) = matcher.get(a) {
491                 if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) {
492                     return self.missing_required_error(matcher, Some(r));
493                 }
494             }
495         }
496         Ok(())
497     }
498 
validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool>499     fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
500         debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
501         a.blacklist().map(|bl| {
502             bl.iter().any(|conf| {
503                 matcher.contains(conf)
504                     || self.0
505                         .groups
506                         .iter()
507                         .find(|g| &g.name == conf)
508                         .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
509             })
510         })
511     }
512 
validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool>513     fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
514         debugln!("Validator::validate_required_unless: a={:?};", a.name());
515         macro_rules! check {
516             ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
517                 $a.required_unless().map(|ru| {
518                     ru.iter().$how(|n| {
519                         $m.contains(n) || {
520                             if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
521                                      grp.args.iter().any(|arg| $m.contains(arg))
522                             } else {
523                                 false
524                             }
525                         }
526                     })
527                 })
528             }};
529         }
530         if a.is_set(ArgSettings::RequiredUnlessAll) {
531             check!(all, self.0, a, matcher)
532         } else {
533             check!(any, self.0, a, matcher)
534         }
535     }
536 
missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()>537     fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
538         debugln!("Validator::missing_required_error: extra={:?}", extra);
539         let c = Colorizer::new(ColorizerOption {
540             use_stderr: true,
541             when: self.0.color(),
542         });
543         let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
544         if let Some(r) = extra {
545             reqs.push(r);
546         }
547         reqs.retain(|n| !matcher.contains(n));
548         reqs.dedup();
549         debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
550         let req_args =
551             usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
552                 .iter()
553                 .fold(String::new(), |acc, s| {
554                     acc + &format!("\n    {}", c.error(s))[..]
555                 });
556         debugln!(
557             "Validator::missing_required_error: req_args={:#?}",
558             req_args
559         );
560         Err(Error::missing_required_argument(
561             &*req_args,
562             &*usage::create_error_usage(self.0, matcher, extra),
563             self.0.color(),
564         ))
565     }
566 
567     #[inline]
is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool568     fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
569         debugln!("Validator::is_missing_required_ok: a={}", a.name());
570         self.validate_arg_conflicts(a, matcher).unwrap_or(false)
571             || self.validate_required_unless(a, matcher).unwrap_or(false)
572     }
573 }
574