clap/app/
validator.rs

1// std
2use std::fmt::Display;
3#[allow(deprecated, unused_imports)]
4use std::ascii::AsciiExt;
5
6// Internal
7use INTERNAL_ERROR_MSG;
8use INVALID_UTF8;
9use args::{AnyArg, ArgMatcher, MatchedArg};
10use args::settings::ArgSettings;
11use errors::{Error, ErrorKind};
12use errors::Result as ClapResult;
13use app::settings::AppSettings as AS;
14use app::parser::{ParseResult, Parser};
15use fmt::{Colorizer, ColorizerOption};
16use app::usage;
17
18pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
19where
20    'a: 'b,
21    'b: 'z;
22
23impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
24    pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
25
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
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
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
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
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
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
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
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
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
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
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
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]
568    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}