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