1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // ignore-lexer-test FIXME #15677
13 //! Simple getopt alternative.
15 //! Construct a vector of options, either by using `reqopt`, `optopt`, and
16 //! `optflag` or by building them from components yourself, and pass them to
17 //! `getopts`, along with a vector of actual arguments (not including
18 //! `argv[0]`). You'll either get a failure code back, or a match. You'll have
19 //! to verify whether the amount of 'free' arguments in the match is what you
20 //! expect. Use `opt_*` accessors to get argument values out of the matches
23 //! Single-character options are expected to appear on the command line with a
24 //! single preceding dash; multiple-character options are expected to be
25 //! proceeded by two dashes. Options that expect an argument accept their
26 //! argument following either a space or an equals sign. Single-character
27 //! options don't require the space.
31 //! This crate is [on crates.io](https://crates.io/crates/getopts) and can be
32 //! used by adding `getopts` to the dependencies in your project's `Cargo.toml`.
39 //! and this to your crate root:
42 //! extern crate getopts;
47 //! The following example shows simple command line parsing for an application
48 //! that requires an input file to be specified, accepts an optional output file
49 //! name following `-o`, and accepts both `-h` and `--help` as optional flags.
52 //! extern crate getopts;
53 //! use getopts::Options;
56 //! fn do_work(inp: &str, out: Option<String>) {
57 //! println!("{}", inp);
59 //! Some(x) => println!("{}", x),
60 //! None => println!("No Output"),
64 //! fn print_usage(program: &str, opts: Options) {
65 //! let brief = format!("Usage: {} FILE [options]", program);
66 //! print!("{}", opts.usage(&brief));
70 //! let args: Vec<String> = env::args().collect();
71 //! let program = args[0].clone();
73 //! let mut opts = Options::new();
74 //! opts.optopt("o", "", "set output file name", "NAME");
75 //! opts.optflag("h", "help", "print this help menu");
76 //! let matches = match opts.parse(&args[1..]) {
78 //! Err(f) => { panic!(f.to_string()) }
80 //! if matches.opt_present("h") {
81 //! print_usage(&program, opts);
84 //! let output = matches.opt_str("o");
85 //! let input = if !matches.free.is_empty() {
86 //! matches.free[0].clone()
88 //! print_usage(&program, opts);
91 //! do_work(&input, output);
95 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
96 html_favicon_url
= "https://www.rust-lang.org/favicon.ico",
97 html_root_url
= "https://doc.rust-lang.org/getopts/")]
98 #![deny(missing_docs)]
99 #![cfg_attr(test, deny(warnings))]
100 #![cfg_attr(rust_build, feature(staged_api))]
101 #![cfg_attr(rust_build, staged_api)]
102 #![cfg_attr(rust_build,
103 unstable(feature
= "rustc_private",
104 reason
= "use the crates.io `getopts` library instead"))]
106 #[cfg(test)] #[macro_use] extern crate log;
113 use self::SplitWithinState
::*;
114 use self::Whitespace
::*;
115 use self::LengthLimit
::*;
117 use std
::error
::Error
;
120 use std
::iter
::{repeat, IntoIterator}
;
123 /// A description of the options that a program can handle.
126 parsing_style
: ParsingStyle
,
131 /// Create a blank set of options.
132 pub fn new() -> Options
{
135 parsing_style
: ParsingStyle
::FloatingFrees
,
140 /// Set the parsing style.
141 pub fn parsing_style(&mut self, style
: ParsingStyle
) -> &mut Options
{
142 self.parsing_style
= style
;
146 /// Set or clear "long options only" mode.
148 /// In "long options only" mode, short options cannot be clustered
149 /// together, and long options can be given with either a single
150 /// "-" or the customary "--". This mode also changes the meaning
151 /// of "-a=b"; in the ordinary mode this will parse a short option
152 /// "-a" with argument "=b"; whereas in long-options-only mode the
153 /// argument will be simply "b".
154 pub fn long_only(&mut self, long_only
: bool
) -> &mut Options
{
155 self.long_only
= long_only
;
159 /// Create a generic option group, stating all parameters explicitly.
160 pub fn opt(&mut self, short_name
: &str, long_name
: &str, desc
: &str,
161 hint
: &str, hasarg
: HasArg
, occur
: Occur
) -> &mut Options
{
162 validate_names(short_name
, long_name
);
163 self.grps
.push(OptGroup
{
164 short_name
: short_name
.to_string(),
165 long_name
: long_name
.to_string(),
166 hint
: hint
.to_string(),
167 desc
: desc
.to_string(),
174 /// Create a long option that is optional and does not take an argument.
176 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
177 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
178 /// * `desc` - Description for usage help
179 pub fn optflag(&mut self, short_name
: &str, long_name
: &str, desc
: &str)
181 validate_names(short_name
, long_name
);
182 self.grps
.push(OptGroup
{
183 short_name
: short_name
.to_string(),
184 long_name
: long_name
.to_string(),
185 hint
: "".to_string(),
186 desc
: desc
.to_string(),
193 /// Create a long option that can occur more than once and does not
194 /// take an argument.
196 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
197 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
198 /// * `desc` - Description for usage help
199 pub fn optflagmulti(&mut self, short_name
: &str, long_name
: &str, desc
: &str)
201 validate_names(short_name
, long_name
);
202 self.grps
.push(OptGroup
{
203 short_name
: short_name
.to_string(),
204 long_name
: long_name
.to_string(),
205 hint
: "".to_string(),
206 desc
: desc
.to_string(),
213 /// Create a long option that is optional and takes an optional argument.
215 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
216 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
217 /// * `desc` - Description for usage help
218 /// * `hint` - Hint that is used in place of the argument in the usage help,
219 /// e.g. `"FILE"` for a `-o FILE` option
220 pub fn optflagopt(&mut self, short_name
: &str, long_name
: &str, desc
: &str,
221 hint
: &str) -> &mut Options
{
222 validate_names(short_name
, long_name
);
223 self.grps
.push(OptGroup
{
224 short_name
: short_name
.to_string(),
225 long_name
: long_name
.to_string(),
226 hint
: hint
.to_string(),
227 desc
: desc
.to_string(),
234 /// Create a long option that is optional, takes an argument, and may occur
237 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
238 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
239 /// * `desc` - Description for usage help
240 /// * `hint` - Hint that is used in place of the argument in the usage help,
241 /// e.g. `"FILE"` for a `-o FILE` option
242 pub fn optmulti(&mut self, short_name
: &str, long_name
: &str, desc
: &str, hint
: &str)
244 validate_names(short_name
, long_name
);
245 self.grps
.push(OptGroup
{
246 short_name
: short_name
.to_string(),
247 long_name
: long_name
.to_string(),
248 hint
: hint
.to_string(),
249 desc
: desc
.to_string(),
256 /// Create a long option that is optional and takes an argument.
258 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
259 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
260 /// * `desc` - Description for usage help
261 /// * `hint` - Hint that is used in place of the argument in the usage help,
262 /// e.g. `"FILE"` for a `-o FILE` option
263 pub fn optopt(&mut self, short_name
: &str, long_name
: &str, desc
: &str, hint
: &str)
265 validate_names(short_name
, long_name
);
266 self.grps
.push(OptGroup
{
267 short_name
: short_name
.to_string(),
268 long_name
: long_name
.to_string(),
269 hint
: hint
.to_string(),
270 desc
: desc
.to_string(),
277 /// Create a long option that is required and takes an argument.
279 /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none
280 /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none
281 /// * `desc` - Description for usage help
282 /// * `hint` - Hint that is used in place of the argument in the usage help,
283 /// e.g. `"FILE"` for a `-o FILE` option
284 pub fn reqopt(&mut self, short_name
: &str, long_name
: &str, desc
: &str, hint
: &str)
286 validate_names(short_name
, long_name
);
287 self.grps
.push(OptGroup
{
288 short_name
: short_name
.to_string(),
289 long_name
: long_name
.to_string(),
290 hint
: hint
.to_string(),
291 desc
: desc
.to_string(),
298 /// Parse command line arguments according to the provided options.
300 /// On success returns `Ok(Matches)`. Use methods such as `opt_present`
301 /// `opt_str`, etc. to interrogate results.
304 /// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail`
305 /// to display information about it.
306 pub fn parse
<C
: IntoIterator
>(&self, args
: C
) -> Result
307 where C
::Item
: AsRef
<OsStr
>
309 let opts
: Vec
<Opt
> = self.grps
.iter().map(|x
| x
.long_to_short()).collect();
310 let n_opts
= opts
.len();
312 fn f(_x
: usize) -> Vec
<Optval
> { return Vec::new(); }
314 let mut vals
= (0 .. n_opts
).map(f
).collect
::<Vec
<_
>>();
315 let mut free
: Vec
<String
> = Vec
::new();
316 let args
= try
!(args
.into_iter().map(|i
| {
317 i
.as_ref().to_str().ok_or_else(|| {
318 Fail
::UnrecognizedOption(format
!("{:?}", i
.as_ref()))
319 }).map(|s
| s
.to_owned())
320 }).collect
::<::std
::result
::Result
<Vec
<_
>, _
>>());
324 let cur
= args
[i
].clone();
325 let curlen
= cur
.len();
327 match self.parsing_style
{
328 ParsingStyle
::FloatingFrees
=> free
.push(cur
),
329 ParsingStyle
::StopAtFirstFree
=> {
331 free
.push(args
[i
].clone());
337 } else if cur
== "--" {
339 while j
< l { free.push(args[j].clone()); j += 1; }
343 let mut i_arg
= None
;
344 let mut was_long
= true;
345 if cur
.as_bytes()[1] == b'
-'
|| self.long_only
{
346 let tail
= if cur
.as_bytes()[1] == b'
-'
{
349 assert
!(self.long_only
);
352 let tail_eq
: Vec
<&str> = tail
.splitn(2, '
='
).collect();
353 if tail_eq
.len() <= 1 {
354 names
= vec
!(Name
::from_str(tail
));
357 vec
!(Name
::from_str(tail_eq
[0]));
358 i_arg
= Some(tail_eq
[1].to_string());
363 for (j
, ch
) in cur
.char_indices().skip(1) {
366 /* In a series of potential options (eg. -aheJ), if we
367 see one which takes an argument, we assume all
368 subsequent characters make up the argument. This
369 allows options such as -L/usr/local/lib/foo to be
370 interpreted correctly
373 let opt_id
= match find_opt(&opts
, opt
.clone()) {
375 None
=> return Err(UnrecognizedOption(opt
.to_string()))
380 let arg_follows
= match opts
[opt_id
].hasarg
{
386 let next
= j
+ ch
.len_utf8();
388 i_arg
= Some(cur
[next
..curlen
].to_string());
394 let mut name_pos
= 0;
395 for nm
in names
.iter() {
397 let optid
= match find_opt(&opts
, (*nm
).clone()) {
399 None
=> return Err(UnrecognizedOption(nm
.to_string()))
401 match opts
[optid
].hasarg
{
403 if name_pos
== names
.len() && !i_arg
.is_none() {
404 return Err(UnexpectedArgument(nm
.to_string()));
406 vals
[optid
].push(Given
);
409 // Note that here we do not handle `--arg value`.
410 // This matches GNU getopt behavior; but also
411 // makes sense, because if this were accepted,
412 // then users could only write a "Maybe" long
413 // option at the end of the arguments when
414 // FloatingFrees is in use.
415 if !i_arg
.is_none() {
417 .push(Val((i_arg
.clone())
419 } else if was_long
|| name_pos
< names
.len() || i
+ 1 == l
||
420 is_arg(&args
[i
+ 1]) {
421 vals
[optid
].push(Given
);
424 vals
[optid
].push(Val(args
[i
].clone()));
428 if !i_arg
.is_none() {
429 vals
[optid
].push(Val(i_arg
.clone().unwrap()));
430 } else if i
+ 1 == l
{
431 return Err(ArgumentMissing(nm
.to_string()));
434 vals
[optid
].push(Val(args
[i
].clone()));
442 for i
in 0 .. n_opts
{
443 let n
= vals
[i
].len();
444 let occ
= opts
[i
].occur
;
445 if occ
== Req
&& n
== 0 {
446 return Err(OptionMissing(opts
[i
].name
.to_string()));
448 if occ
!= Multi
&& n
> 1 {
449 return Err(OptionDuplicated(opts
[i
].name
.to_string()));
459 /// Derive a short one-line usage summary from a set of long options.
460 pub fn short_usage(&self, program_name
: &str) -> String
{
461 let mut line
= format
!("Usage: {} ", program_name
);
462 line
.push_str(&self.grps
.iter()
464 .collect
::<Vec
<String
>>()
469 /// Derive a usage message from a set of options.
470 pub fn usage(&self, brief
: &str) -> String
{
471 let desc_sep
= format
!("\n{}", repeat(" ").take(24).collect
::<String
>());
473 let any_short
= self.grps
.iter().any(|optref
| {
474 optref
.short_name
.len() > 0
477 let rows
= self.grps
.iter().map(|optref
| {
478 let OptGroup
{short_name
,
483 ..} = (*optref
).clone();
485 let mut row
= " ".to_string();
488 match short_name
.len() {
496 row
.push_str(&short_name
);
497 if long_name
.len() > 0 {
500 // Only a single space here, so that any
501 // argument is printed in the correct spot.
505 _
=> panic
!("the short name should only be 1 ascii char long"),
509 match long_name
.len() {
517 row
.push_str(&long_name
);
525 Yes
=> row
.push_str(&hint
),
533 // FIXME: #5516 should be graphemes not codepoints
534 // here we just need to indent the start of the description
535 let rowlen
= row
.chars().count();
537 for _
in 0 .. 24 - rowlen
{
541 row
.push_str(&desc_sep
)
544 // Normalize desc to contain words separated by one space character
545 let mut desc_normalized_whitespace
= String
::new();
546 for word
in desc
.split(|c
: char| c
.is_whitespace())
547 .filter(|s
| !s
.is_empty()) {
548 desc_normalized_whitespace
.push_str(word
);
549 desc_normalized_whitespace
.push(' '
);
552 // FIXME: #5516 should be graphemes not codepoints
553 let mut desc_rows
= Vec
::new();
554 each_split_within(&desc_normalized_whitespace
,
557 desc_rows
.push(substr
.to_string());
561 // FIXME: #5516 should be graphemes not codepoints
562 // wrapped description
563 row
.push_str(&desc_rows
.join(&desc_sep
));
568 format
!("{}\n\nOptions:\n{}\n", brief
,
569 rows
.collect
::<Vec
<String
>>().join("\n"))
573 fn validate_names(short_name
: &str, long_name
: &str) {
574 let len
= short_name
.len();
575 assert
!(len
== 1 || len
== 0,
576 "the short_name (first argument) should be a single character, \
577 or an empty string for none");
578 let len
= long_name
.len();
579 assert
!(len
== 0 || len
> 1,
580 "the long_name (second argument) should be longer than a single \
581 character, or an empty string for none");
584 /// What parsing style to use when parsing arguments.
585 #[derive(Clone, Copy, PartialEq, Eq)]
586 pub enum ParsingStyle
{
587 /// Flags and "free" arguments can be freely inter-mixed.
589 /// As soon as a "free" argument (i.e. non-flag) is encountered, stop
590 /// considering any remaining arguments as flags.
594 /// Name of an option. Either a string or a single char.
595 #[derive(Clone, PartialEq, Eq)]
597 /// A string representing the long name of an option.
598 /// For example: "help"
600 /// A char representing the short name of an option.
605 /// Describes whether an option has an argument.
606 #[derive(Clone, Copy, PartialEq, Eq)]
608 /// The option requires an argument.
610 /// The option takes no argument.
612 /// The option argument is optional.
616 /// Describes how often an option may occur.
617 #[derive(Clone, Copy, PartialEq, Eq)]
619 /// The option occurs once.
621 /// The option occurs at most once.
623 /// The option occurs zero or more times.
627 /// A description of a possible option.
628 #[derive(Clone, PartialEq, Eq)]
630 /// Name of the option
632 /// Whether it has an argument
634 /// How often it can occur
636 /// Which options it aliases
640 /// One group of options, e.g., both `-h` and `--help`, along with
641 /// their shared description and properties.
642 #[derive(Clone, PartialEq, Eq)]
644 /// Short name of the option, e.g. `h` for a `-h` option
646 /// Long name of the option, e.g. `help` for a `--help` option
648 /// Hint for argument, e.g. `FILE` for a `-o FILE` option
650 /// Description for usage help text
652 /// Whether option has an argument
654 /// How often it can occur
658 /// Describes whether an option is given at all or has a value.
659 #[derive(Clone, PartialEq, Eq)]
665 /// The result of checking command line arguments. Contains a vector
666 /// of matches and a vector of free strings.
667 #[derive(Clone, PartialEq, Eq)]
669 /// Options that matched
671 /// Values of the Options that matched
672 vals
: Vec
<Vec
<Optval
>>,
673 /// Free string fragments
674 pub free
: Vec
<String
>,
677 /// The type returned when the command line does not conform to the
678 /// expected format. Use the `Debug` implementation to output detailed
680 #[derive(Clone, Debug, PartialEq, Eq)]
682 /// The option requires an argument but none was passed.
683 ArgumentMissing(String
),
684 /// The passed option is not declared among the possible options.
685 UnrecognizedOption(String
),
686 /// A required option is not present.
687 OptionMissing(String
),
688 /// A single occurrence option is being used multiple times.
689 OptionDuplicated(String
),
690 /// There's an argument being passed to a non-argument option.
691 UnexpectedArgument(String
),
694 impl Error
for Fail
{
695 fn description(&self) -> &str {
697 ArgumentMissing(_
) => "missing argument",
698 UnrecognizedOption(_
) => "unrecognized option",
699 OptionMissing(_
) => "missing option",
700 OptionDuplicated(_
) => "duplicated option",
701 UnexpectedArgument(_
) => "unexpected argument",
706 /// The result of parsing a command line with a set of options.
707 pub type Result
= result
::Result
<Matches
, Fail
>;
710 fn from_str(nm
: &str) -> Name
{
712 Short(nm
.as_bytes()[0] as char)
718 fn to_string(&self) -> String
{
720 Short(ch
) => ch
.to_string(),
721 Long(ref s
) => s
.to_string()
727 /// Translate OptGroup into Opt.
728 /// (Both short and long names correspond to different Opts).
729 fn long_to_short(&self) -> Opt
{
738 match (short_name
.len(), long_name
.len()) {
739 (0,0) => panic
!("this long-format option was given no name"),
741 name
: Long((long_name
)),
747 name
: Short(short_name
.as_bytes()[0] as char),
753 name
: Long((long_name
)),
758 name
: Short(short_name
.as_bytes()[0] as char),
765 (_
,_
) => panic
!("something is wrong with the long-form opt")
771 fn opt_vals(&self, nm
: &str) -> Vec
<Optval
> {
772 match find_opt(&self.opts
, Name
::from_str(nm
)) {
773 Some(id
) => self.vals
[id
].clone(),
774 None
=> panic
!("No option '{}' defined", nm
)
778 fn opt_val(&self, nm
: &str) -> Option
<Optval
> {
779 self.opt_vals(nm
).into_iter().next()
781 /// Returns true if an option was defined
782 pub fn opt_defined(&self, nm
: &str) -> bool
{
783 find_opt(&self.opts
, Name
::from_str(nm
)).is_some()
786 /// Returns true if an option was matched.
787 pub fn opt_present(&self, nm
: &str) -> bool
{
788 !self.opt_vals(nm
).is_empty()
791 /// Returns the number of times an option was matched.
792 pub fn opt_count(&self, nm
: &str) -> usize {
793 self.opt_vals(nm
).len()
796 /// Returns true if any of several options were matched.
797 pub fn opts_present(&self, names
: &[String
]) -> bool
{
798 names
.iter().any(|nm
| {
799 match find_opt(&self.opts
, Name
::from_str(&nm
)) {
800 Some(id
) if !self.vals
[id
].is_empty() => true,
806 /// Returns the string argument supplied to one of several matching options or `None`.
807 pub fn opts_str(&self, names
: &[String
]) -> Option
<String
> {
808 names
.iter().filter_map(|nm
| {
809 match self.opt_val(&nm
) {
810 Some(Val(s
)) => Some(s
),
816 /// Returns a vector of the arguments provided to all matches of the given
819 /// Used when an option accepts multiple values.
820 pub fn opt_strs(&self, nm
: &str) -> Vec
<String
> {
821 self.opt_vals(nm
).into_iter().filter_map(|v
| {
829 /// Returns the string argument supplied to a matching option or `None`.
830 pub fn opt_str(&self, nm
: &str) -> Option
<String
> {
831 match self.opt_val(nm
) {
832 Some(Val(s
)) => Some(s
),
838 /// Returns the matching string, a default, or `None`.
840 /// Returns `None` if the option was not present, `def` if the option was
841 /// present but no argument was provided, and the argument if the option was
842 /// present and an argument was provided.
843 pub fn opt_default(&self, nm
: &str, def
: &str) -> Option
<String
> {
844 match self.opt_val(nm
) {
845 Some(Val(s
)) => Some(s
),
846 Some(_
) => Some(def
.to_string()),
853 fn is_arg(arg
: &str) -> bool
{
854 arg
.as_bytes().get(0) == Some(&b'
-'
) && arg
.len() > 1
857 fn find_opt(opts
: &[Opt
], nm
: Name
) -> Option
<usize> {
858 // Search main options.
859 let pos
= opts
.iter().position(|opt
| opt
.name
== nm
);
864 // Search in aliases.
865 for candidate
in opts
.iter() {
866 if candidate
.aliases
.iter().position(|opt
| opt
.name
== nm
).is_some() {
867 return opts
.iter().position(|opt
| opt
.name
== candidate
.name
);
874 impl fmt
::Display
for Fail
{
875 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
877 ArgumentMissing(ref nm
) => {
878 write
!(f
, "Argument to option '{}' missing", *nm
)
880 UnrecognizedOption(ref nm
) => {
881 write
!(f
, "Unrecognized option: '{}'", *nm
)
883 OptionMissing(ref nm
) => {
884 write
!(f
, "Required option '{}' missing", *nm
)
886 OptionDuplicated(ref nm
) => {
887 write
!(f
, "Option '{}' given more than once", *nm
)
889 UnexpectedArgument(ref nm
) => {
890 write
!(f
, "Option '{}' does not take an argument", *nm
)
896 fn format_option(opt
: &OptGroup
) -> String
{
897 let mut line
= String
::new();
899 if opt
.occur
!= Req
{
903 // Use short_name if possible, but fall back to long_name.
904 if opt
.short_name
.len() > 0 {
906 line
.push_str(&opt
.short_name
);
909 line
.push_str(&opt
.long_name
);
912 if opt
.hasarg
!= No
{
914 if opt
.hasarg
== Maybe
{
917 line
.push_str(&opt
.hint
);
918 if opt
.hasarg
== Maybe
{
923 if opt
.occur
!= Req
{
926 if opt
.occur
== Multi
{
933 #[derive(Clone, Copy)]
934 enum SplitWithinState
{
935 A
, // leading whitespace, initial state
937 C
, // internal and trailing whitespace
940 #[derive(Clone, Copy)]
942 Ws
, // current char is whitespace
943 Cr
// current char is not whitespace
946 #[derive(Clone, Copy)]
948 UnderLim
, // current char makes current substring still fit in limit
949 OverLim
// current char makes current substring no longer fit in limit
953 /// Splits a string into substrings with possibly internal whitespace,
954 /// each of them at most `lim` bytes long, if possible. The substrings
955 /// have leading and trailing whitespace removed, and are only cut at
956 /// whitespace boundaries.
958 /// Note: Function was moved here from `std::str` because this module is the only place that
959 /// uses it, and because it was too specific for a general string function.
960 fn each_split_within
<'a
, F
>(ss
: &'a
str, lim
: usize, mut it
: F
)
961 -> bool
where F
: FnMut(&'a
str) -> bool
{
962 // Just for fun, let's write this as a state machine:
964 let mut slice_start
= 0;
965 let mut last_start
= 0;
966 let mut last_end
= 0;
968 let mut fake_i
= ss
.len();
973 // if the limit is larger than the string, lower it to save cycles
978 let mut machine
= |cont
: &mut bool
, (i
, c
): (usize, char)| {
979 let whitespace
= if c
.is_whitespace() { Ws }
else { Cr }
;
980 let limit
= if (i
- slice_start
+ 1) <= lim { UnderLim }
else { OverLim }
;
982 state
= match (state
, whitespace
, limit
) {
984 (A
, Cr
, _
) => { slice_start = i; last_start = i; B }
986 (B
, Cr
, UnderLim
) => { B }
987 (B
, Cr
, OverLim
) if (i
- last_start
+ 1) > lim
=> {
988 // A single word has gone over the limit. In this
989 // case we just accept that the word will be too long.
992 (B
, Cr
, OverLim
) => {
993 *cont
= it(&ss
[slice_start
..last_end
]);
994 slice_start
= last_start
;
997 (B
, Ws
, UnderLim
) => {
1001 (B
, Ws
, OverLim
) => {
1003 *cont
= it(&ss
[slice_start
..last_end
]);
1007 (C
, Cr
, UnderLim
) => {
1011 (C
, Cr
, OverLim
) => {
1012 *cont
= it(&ss
[slice_start
..last_end
]);
1018 (C
, Ws
, OverLim
) => {
1019 *cont
= it(&ss
[slice_start
..last_end
]);
1022 (C
, Ws
, UnderLim
) => {
1030 ss
.char_indices().all(|x
| machine(&mut cont
, x
));
1032 // Let the automaton 'run out' by supplying trailing whitespace
1033 while cont
&& match state { B | C => true, A => false }
{
1034 machine(&mut cont
, (fake_i
, ' '
));
1041 fn test_split_within() {
1042 fn t(s
: &str, i
: usize, u
: &[String
]) {
1043 let mut v
= Vec
::new();
1044 each_split_within(s
, i
, |s
| { v.push(s.to_string()); true }
);
1045 assert
!(v
.iter().zip(u
.iter()).all(|(a
,b
)| a
== b
));
1049 t("hello", 15, &["hello".to_string()]);
1050 t("\nMary had a little lamb\nLittle lamb\n", 15, &[
1051 "Mary had a".to_string(),
1052 "little lamb".to_string(),
1053 "Little lamb".to_string()
1055 t("\nMary had a little lamb\nLittle lamb\n", ::std
::usize::MAX
,
1056 &["Mary had a little lamb\nLittle lamb".to_string()]);
1061 use super::{HasArg, Name, Occur, Opt, Options, ParsingStyle}
;
1067 let long_args
= vec
!("--test=20".to_string());
1068 let mut opts
= Options
::new();
1069 opts
.reqopt("t", "test", "testing", "TEST");
1070 match opts
.parse(&long_args
) {
1072 assert
!(m
.opt_present("test"));
1073 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1074 assert
!(m
.opt_present("t"));
1075 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1077 _
=> { panic!("test_reqopt failed (long arg)"); }
1079 let short_args
= vec
!("-t".to_string(), "20".to_string());
1080 match opts
.parse(&short_args
) {
1082 assert
!((m
.opt_present("test")));
1083 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1084 assert
!((m
.opt_present("t")));
1085 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1087 _
=> { panic!("test_reqopt failed (short arg)"); }
1092 fn test_reqopt_missing() {
1093 let args
= vec
!("blah".to_string());
1094 match Options
::new()
1095 .reqopt("t", "test", "testing", "TEST")
1097 Err(OptionMissing(_
)) => {}
,
1103 fn test_reqopt_no_arg() {
1104 let long_args
= vec
!("--test".to_string());
1105 let mut opts
= Options
::new();
1106 opts
.reqopt("t", "test", "testing", "TEST");
1107 match opts
.parse(&long_args
) {
1108 Err(ArgumentMissing(_
)) => {}
,
1111 let short_args
= vec
!("-t".to_string());
1112 match opts
.parse(&short_args
) {
1113 Err(ArgumentMissing(_
)) => {}
,
1119 fn test_reqopt_multi() {
1120 let args
= vec
!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1121 match Options
::new()
1122 .reqopt("t", "test", "testing", "TEST")
1124 Err(OptionDuplicated(_
)) => {}
,
1132 let long_args
= vec
!("--test=20".to_string());
1133 let mut opts
= Options
::new();
1134 opts
.optopt("t", "test", "testing", "TEST");
1135 match opts
.parse(&long_args
) {
1137 assert
!(m
.opt_present("test"));
1138 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1139 assert
!((m
.opt_present("t")));
1140 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1144 let short_args
= vec
!("-t".to_string(), "20".to_string());
1145 match opts
.parse(&short_args
) {
1147 assert
!((m
.opt_present("test")));
1148 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1149 assert
!((m
.opt_present("t")));
1150 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1157 fn test_optopt_missing() {
1158 let args
= vec
!("blah".to_string());
1159 match Options
::new()
1160 .optopt("t", "test", "testing", "TEST")
1163 assert
!(!m
.opt_present("test"));
1164 assert
!(!m
.opt_present("t"));
1171 fn test_optopt_no_arg() {
1172 let long_args
= vec
!("--test".to_string());
1173 let mut opts
= Options
::new();
1174 opts
.optopt("t", "test", "testing", "TEST");
1175 match opts
.parse(&long_args
) {
1176 Err(ArgumentMissing(_
)) => {}
,
1179 let short_args
= vec
!("-t".to_string());
1180 match opts
.parse(&short_args
) {
1181 Err(ArgumentMissing(_
)) => {}
,
1187 fn test_optopt_multi() {
1188 let args
= vec
!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1189 match Options
::new()
1190 .optopt("t", "test", "testing", "TEST")
1192 Err(OptionDuplicated(_
)) => {}
,
1197 // Tests for optflag
1200 let long_args
= vec
!("--test".to_string());
1201 let mut opts
= Options
::new();
1202 opts
.optflag("t", "test", "testing");
1203 match opts
.parse(&long_args
) {
1205 assert
!(m
.opt_present("test"));
1206 assert
!(m
.opt_present("t"));
1210 let short_args
= vec
!("-t".to_string());
1211 match opts
.parse(&short_args
) {
1213 assert
!(m
.opt_present("test"));
1214 assert
!(m
.opt_present("t"));
1221 fn test_optflag_missing() {
1222 let args
= vec
!("blah".to_string());
1223 match Options
::new()
1224 .optflag("t", "test", "testing")
1227 assert
!(!m
.opt_present("test"));
1228 assert
!(!m
.opt_present("t"));
1235 fn test_optflag_long_arg() {
1236 let args
= vec
!("--test=20".to_string());
1237 match Options
::new()
1238 .optflag("t", "test", "testing")
1240 Err(UnexpectedArgument(_
)) => {}
,
1246 fn test_optflag_multi() {
1247 let args
= vec
!("--test".to_string(), "-t".to_string());
1248 match Options
::new()
1249 .optflag("t", "test", "testing")
1251 Err(OptionDuplicated(_
)) => {}
,
1257 fn test_optflag_short_arg() {
1258 let args
= vec
!("-t".to_string(), "20".to_string());
1259 match Options
::new()
1260 .optflag("t", "test", "testing")
1263 // The next variable after the flag is just a free argument
1265 assert
!(m
.free
[0] == "20");
1271 // Tests for optflagmulti
1273 fn test_optflagmulti_short1() {
1274 let args
= vec
!("-v".to_string());
1275 match Options
::new()
1276 .optflagmulti("v", "verbose", "verbosity")
1279 assert_eq
!(m
.opt_count("v"), 1);
1286 fn test_optflagmulti_short2a() {
1287 let args
= vec
!("-v".to_string(), "-v".to_string());
1288 match Options
::new()
1289 .optflagmulti("v", "verbose", "verbosity")
1292 assert_eq
!(m
.opt_count("v"), 2);
1299 fn test_optflagmulti_short2b() {
1300 let args
= vec
!("-vv".to_string());
1301 match Options
::new()
1302 .optflagmulti("v", "verbose", "verbosity")
1305 assert_eq
!(m
.opt_count("v"), 2);
1312 fn test_optflagmulti_long1() {
1313 let args
= vec
!("--verbose".to_string());
1314 match Options
::new()
1315 .optflagmulti("v", "verbose", "verbosity")
1318 assert_eq
!(m
.opt_count("verbose"), 1);
1325 fn test_optflagmulti_long2() {
1326 let args
= vec
!("--verbose".to_string(), "--verbose".to_string());
1327 match Options
::new()
1328 .optflagmulti("v", "verbose", "verbosity")
1331 assert_eq
!(m
.opt_count("verbose"), 2);
1338 fn test_optflagmulti_mix() {
1339 let args
= vec
!("--verbose".to_string(), "-v".to_string(),
1340 "-vv".to_string(), "verbose".to_string());
1341 match Options
::new()
1342 .optflagmulti("v", "verbose", "verbosity")
1345 assert_eq
!(m
.opt_count("verbose"), 4);
1346 assert_eq
!(m
.opt_count("v"), 4);
1352 // Tests for optflagopt
1354 fn test_optflagopt() {
1355 let long_args
= vec
!("--test".to_string());
1356 let mut opts
= Options
::new();
1357 opts
.optflagopt("t", "test", "testing", "ARG");
1358 match opts
.parse(&long_args
) {
1360 assert
!(m
.opt_present("test"));
1361 assert
!(m
.opt_present("t"));
1365 let short_args
= vec
!("-t".to_string());
1366 match opts
.parse(&short_args
) {
1368 assert
!(m
.opt_present("test"));
1369 assert
!(m
.opt_present("t"));
1373 let short_args
= vec
!("-t".to_string(), "x".to_string());
1374 match opts
.parse(&short_args
) {
1376 assert_eq
!(m
.opt_str("t").unwrap(), "x");
1377 assert_eq
!(m
.opt_str("test").unwrap(), "x");
1381 let long_args
= vec
!("--test=x".to_string());
1382 match opts
.parse(&long_args
) {
1384 assert_eq
!(m
.opt_str("t").unwrap(), "x");
1385 assert_eq
!(m
.opt_str("test").unwrap(), "x");
1389 let long_args
= vec
!("--test".to_string(), "x".to_string());
1390 match opts
.parse(&long_args
) {
1392 assert_eq
!(m
.opt_str("t"), None
);
1393 assert_eq
!(m
.opt_str("test"), None
);
1397 let no_args
: Vec
<String
> = vec
!();
1398 match opts
.parse(&no_args
) {
1400 assert
!(!m
.opt_present("test"));
1401 assert
!(!m
.opt_present("t"));
1407 // Tests for optmulti
1409 fn test_optmulti() {
1410 let long_args
= vec
!("--test=20".to_string());
1411 let mut opts
= Options
::new();
1412 opts
.optmulti("t", "test", "testing", "TEST");
1413 match opts
.parse(&long_args
) {
1415 assert
!((m
.opt_present("test")));
1416 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1417 assert
!((m
.opt_present("t")));
1418 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1422 let short_args
= vec
!("-t".to_string(), "20".to_string());
1423 match opts
.parse(&short_args
) {
1425 assert
!((m
.opt_present("test")));
1426 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1427 assert
!((m
.opt_present("t")));
1428 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1435 fn test_optmulti_missing() {
1436 let args
= vec
!("blah".to_string());
1437 match Options
::new()
1438 .optmulti("t", "test", "testing", "TEST")
1441 assert
!(!m
.opt_present("test"));
1442 assert
!(!m
.opt_present("t"));
1449 fn test_optmulti_no_arg() {
1450 let long_args
= vec
!("--test".to_string());
1451 let mut opts
= Options
::new();
1452 opts
.optmulti("t", "test", "testing", "TEST");
1453 match opts
.parse(&long_args
) {
1454 Err(ArgumentMissing(_
)) => {}
,
1457 let short_args
= vec
!("-t".to_string());
1458 match opts
.parse(&short_args
) {
1459 Err(ArgumentMissing(_
)) => {}
,
1465 fn test_optmulti_multi() {
1466 let args
= vec
!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1467 match Options
::new()
1468 .optmulti("t", "test", "testing", "TEST")
1471 assert
!(m
.opt_present("test"));
1472 assert_eq
!(m
.opt_str("test").unwrap(), "20");
1473 assert
!(m
.opt_present("t"));
1474 assert_eq
!(m
.opt_str("t").unwrap(), "20");
1475 let pair
= m
.opt_strs("test");
1476 assert
!(pair
[0] == "20");
1477 assert
!(pair
[1] == "30");
1484 fn test_free_argument_is_hyphen() {
1485 let args
= vec
!("-".to_string());
1486 match Options
::new().parse(&args
) {
1488 assert_eq
!(m
.free
.len(), 1);
1489 assert_eq
!(m
.free
[0], "-");
1496 fn test_unrecognized_option() {
1497 let long_args
= vec
!("--untest".to_string());
1498 let mut opts
= Options
::new();
1499 opts
.optmulti("t", "test", "testing", "TEST");
1500 match opts
.parse(&long_args
) {
1501 Err(UnrecognizedOption(_
)) => {}
,
1504 let short_args
= vec
!("-u".to_string());
1505 match opts
.parse(&short_args
) {
1506 Err(UnrecognizedOption(_
)) => {}
,
1512 fn test_combined() {
1514 vec
!("prog".to_string(),
1515 "free1".to_string(),
1518 "free2".to_string(),
1519 "--flag".to_string(),
1520 "--long=30".to_string(),
1529 "-60 70".to_string());
1530 match Options
::new()
1531 .optopt("s", "something", "something", "SOMETHING")
1532 .optflag("", "flag", "a flag")
1533 .reqopt("", "long", "hi", "LONG")
1534 .optflag("f", "", "another flag")
1535 .optmulti("m", "", "mmmmmm", "YUM")
1536 .optmulti("n", "", "nothing", "NOTHING")
1537 .optopt("", "notpresent", "nothing to see here", "NOPE")
1540 assert
!(m
.free
[0] == "prog");
1541 assert
!(m
.free
[1] == "free1");
1542 assert_eq
!(m
.opt_str("s").unwrap(), "20");
1543 assert
!(m
.free
[2] == "free2");
1544 assert
!((m
.opt_present("flag")));
1545 assert_eq
!(m
.opt_str("long").unwrap(), "30");
1546 assert
!((m
.opt_present("f")));
1547 let pair
= m
.opt_strs("m");
1548 assert
!(pair
[0] == "40");
1549 assert
!(pair
[1] == "50");
1550 let pair
= m
.opt_strs("n");
1551 assert
!(pair
[0] == "-A B");
1552 assert
!(pair
[1] == "-60 70");
1553 assert
!((!m
.opt_present("notpresent")));
1560 fn test_mixed_stop() {
1562 vec
!("-a".to_string(),
1566 match Options
::new()
1567 .parsing_style(ParsingStyle
::StopAtFirstFree
)
1568 .optflag("a", "", "")
1569 .optopt("c", "", "", "")
1572 println
!("{}", m
.opt_present("c"));
1573 assert
!(m
.opt_present("a"));
1574 assert
!(!m
.opt_present("c"));
1575 assert_eq
!(m
.free
.len(), 3);
1576 assert_eq
!(m
.free
[0], "b");
1577 assert_eq
!(m
.free
[1], "-c");
1578 assert_eq
!(m
.free
[2], "d");
1585 fn test_mixed_stop_hyphen() {
1587 vec
!("-a".to_string(),
1591 match Options
::new()
1592 .parsing_style(ParsingStyle
::StopAtFirstFree
)
1593 .optflag("a", "", "")
1594 .optopt("c", "", "", "")
1597 println
!("{}", m
.opt_present("c"));
1598 assert
!(m
.opt_present("a"));
1599 assert
!(!m
.opt_present("c"));
1600 assert_eq
!(m
.free
.len(), 3);
1601 assert_eq
!(m
.free
[0], "-");
1602 assert_eq
!(m
.free
[1], "-c");
1603 assert_eq
!(m
.free
[2], "d");
1611 let mut opts
= Options
::new();
1612 opts
.optopt("e", "", "encrypt", "ENCRYPT");
1613 opts
.optopt("", "encrypt", "encrypt", "ENCRYPT");
1614 opts
.optopt("f", "", "flag", "FLAG");
1616 let args_single
= vec
!("-e".to_string(), "foo".to_string());
1617 let matches_single
= &match opts
.parse(&args_single
) {
1621 assert
!(matches_single
.opts_present(&["e".to_string()]));
1622 assert
!(matches_single
.opts_present(&["encrypt".to_string(), "e".to_string()]));
1623 assert
!(matches_single
.opts_present(&["e".to_string(), "encrypt".to_string()]));
1624 assert
!(!matches_single
.opts_present(&["encrypt".to_string()]));
1625 assert
!(!matches_single
.opts_present(&["thing".to_string()]));
1626 assert
!(!matches_single
.opts_present(&[]));
1628 assert_eq
!(matches_single
.opts_str(&["e".to_string()]).unwrap(), "foo");
1629 assert_eq
!(matches_single
.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(),
1631 assert_eq
!(matches_single
.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(),
1634 let args_both
= vec
!("-e".to_string(), "foo".to_string(), "--encrypt".to_string(),
1636 let matches_both
= &match opts
.parse(&args_both
) {
1640 assert
!(matches_both
.opts_present(&["e".to_string()]));
1641 assert
!(matches_both
.opts_present(&["encrypt".to_string()]));
1642 assert
!(matches_both
.opts_present(&["encrypt".to_string(), "e".to_string()]));
1643 assert
!(matches_both
.opts_present(&["e".to_string(), "encrypt".to_string()]));
1644 assert
!(!matches_both
.opts_present(&["f".to_string()]));
1645 assert
!(!matches_both
.opts_present(&["thing".to_string()]));
1646 assert
!(!matches_both
.opts_present(&[]));
1648 assert_eq
!(matches_both
.opts_str(&["e".to_string()]).unwrap(), "foo");
1649 assert_eq
!(matches_both
.opts_str(&["encrypt".to_string()]).unwrap(), "foo");
1650 assert_eq
!(matches_both
.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(),
1652 assert_eq
!(matches_both
.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(),
1658 let args
= vec
!("-Lfoo".to_string(), "-M.".to_string());
1659 let matches
= &match Options
::new()
1660 .optmulti("L", "", "library directory", "LIB")
1661 .optmulti("M", "", "something", "MMMM")
1666 assert
!(matches
.opts_present(&["L".to_string()]));
1667 assert_eq
!(matches
.opts_str(&["L".to_string()]).unwrap(), "foo");
1668 assert
!(matches
.opts_present(&["M".to_string()]));
1669 assert_eq
!(matches
.opts_str(&["M".to_string()]).unwrap(), ".");
1674 fn test_nospace_conflict() {
1675 let args
= vec
!("-vvLverbose".to_string(), "-v".to_string() );
1676 let matches
= &match Options
::new()
1677 .optmulti("L", "", "library directory", "LIB")
1678 .optflagmulti("v", "verbose", "Verbose")
1681 Err(e
) => panic
!( "{}", e
)
1683 assert
!(matches
.opts_present(&["L".to_string()]));
1684 assert_eq
!(matches
.opts_str(&["L".to_string()]).unwrap(), "verbose");
1685 assert
!(matches
.opts_present(&["v".to_string()]));
1686 assert_eq
!(3, matches
.opt_count("v"));
1690 fn test_long_to_short() {
1691 let mut short
= Opt
{
1692 name
: Name
::Long("banana".to_string()),
1693 hasarg
: HasArg
::Yes
,
1695 aliases
: Vec
::new(),
1697 short
.aliases
= vec
!(Opt
{ name
: Name
::Short('b'
),
1698 hasarg
: HasArg
::Yes
,
1700 aliases
: Vec
::new() });
1701 let mut opts
= Options
::new();
1702 opts
.reqopt("b", "banana", "some bananas", "VAL");
1703 let ref verbose
= opts
.grps
[0];
1704 assert
!(verbose
.long_to_short() == short
);
1708 fn test_aliases_long_and_short() {
1709 let args
= vec
!("-a".to_string(), "--apple".to_string(), "-a".to_string());
1711 let matches
= Options
::new()
1712 .optflagmulti("a", "apple", "Desc")
1715 assert_eq
!(3, matches
.opt_count("a"));
1716 assert_eq
!(3, matches
.opt_count("apple"));
1721 let mut opts
= Options
::new();
1722 opts
.reqopt("b", "banana", "Desc", "VAL");
1723 opts
.optopt("a", "012345678901234567890123456789",
1725 opts
.optflag("k", "kiwi", "Desc");
1726 opts
.optflagopt("p", "", "Desc", "VAL");
1727 opts
.optmulti("l", "", "Desc", "VAL");
1728 opts
.optflag("", "starfruit", "Starfruit");
1734 -b, --banana VAL Desc
1735 -a, --012345678901234567890123456789 VAL
1740 --starfruit Starfruit
1743 let generated_usage
= opts
.usage("Usage: fruits");
1745 debug
!("expected: <<{}>>", expected
);
1746 debug
!("generated: <<{}>>", generated_usage
);
1747 assert_eq
!(generated_usage
, expected
);
1751 fn test_usage_description_wrapping() {
1752 // indentation should be 24 spaces
1753 // lines wrap after 78: or rather descriptions wrap after 54
1755 let mut opts
= Options
::new();
1756 opts
.optflag("k", "kiwi",
1757 "This is a long description which won't be wrapped..+.."); // 54
1758 opts
.optflag("a", "apple",
1759 "This is a long description which _will_ be wrapped..+..");
1760 opts
.optflag("b", "banana",
1761 "HereWeNeedOneSingleWordThatIsLongerThanTheWrappingLengthAndThisIsIt");
1767 -k, --kiwi This is a long description which won't be wrapped..+..
1768 -a, --apple This is a long description which _will_ be
1770 -b, --banana HereWeNeedOneSingleWordThatIsLongerThanTheWrappingLengthAndThisIsIt
1773 let usage
= opts
.usage("Usage: fruits");
1775 debug
!("expected: <<{}>>", expected
);
1776 debug
!("generated: <<{}>>", usage
);
1777 assert
!(usage
== expected
)
1781 fn test_usage_description_multibyte_handling() {
1782 let mut opts
= Options
::new();
1783 opts
.optflag("k", "k\u{2013}w\u{2013}",
1784 "The word kiwi is normally spelled with two i's");
1785 opts
.optflag("a", "apple",
1786 "This \u{201C}description\u{201D} has some characters that could \
1787 confuse the line wrapping; an apple costs 0.51€ in some parts of Europe.");
1793 -k, --k–w– The word kiwi is normally spelled with two i's
1794 -a, --apple This “description” has some characters that could
1795 confuse the line wrapping; an apple costs 0.51€ in
1796 some parts of Europe.
1799 let usage
= opts
.usage("Usage: fruits");
1801 debug
!("expected: <<{}>>", expected
);
1802 debug
!("generated: <<{}>>", usage
);
1803 assert
!(usage
== expected
)
1807 fn test_usage_short_only() {
1808 let mut opts
= Options
::new();
1809 opts
.optopt("k", "", "Kiwi", "VAL");
1810 opts
.optflag("s", "", "Starfruit");
1811 opts
.optflagopt("a", "", "Apple", "TYPE");
1822 let usage
= opts
.usage("Usage: fruits");
1823 debug
!("expected: <<{}>>", expected
);
1824 debug
!("generated: <<{}>>", usage
);
1825 assert
!(usage
== expected
)
1829 fn test_usage_long_only() {
1830 let mut opts
= Options
::new();
1831 opts
.optopt("", "kiwi", "Kiwi", "VAL");
1832 opts
.optflag("", "starfruit", "Starfruit");
1833 opts
.optflagopt("", "apple", "Apple", "TYPE");
1840 --starfruit Starfruit
1841 --apple [TYPE] Apple
1844 let usage
= opts
.usage("Usage: fruits");
1845 debug
!("expected: <<{}>>", expected
);
1846 debug
!("generated: <<{}>>", usage
);
1847 assert
!(usage
== expected
)
1851 fn test_short_usage() {
1852 let mut opts
= Options
::new();
1853 opts
.reqopt("b", "banana", "Desc", "VAL");
1854 opts
.optopt("a", "012345678901234567890123456789",
1856 opts
.optflag("k", "kiwi", "Desc");
1857 opts
.optflagopt("p", "", "Desc", "VAL");
1858 opts
.optmulti("l", "", "Desc", "VAL");
1860 let expected
= "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string();
1861 let generated_usage
= opts
.short_usage("fruits");
1863 debug
!("expected: <<{}>>", expected
);
1864 debug
!("generated: <<{}>>", generated_usage
);
1865 assert_eq
!(generated_usage
, expected
);
1868 fn test_nonexistant_opt() {
1869 let mut opts
= Options
::new();
1870 opts
.optflag("b", "bar", "Desc");
1871 let args
: Vec
<String
> = Vec
::new();
1872 let matches
= opts
.parse(&args
).unwrap();
1873 assert_eq
!(matches
.opt_defined("foo"), false);
1874 assert_eq
!(matches
.opt_defined("bar"), true);
1877 fn test_args_with_equals() {
1878 let mut opts
= Options
::new();
1879 opts
.optopt("o", "one", "One", "INFO");
1880 opts
.optopt("t", "two", "Two", "INFO");
1882 let args
= vec
!("--one".to_string(), "A=B".to_string(),
1883 "--two=C=D".to_string());
1884 let matches
= &match opts
.parse(&args
) {
1886 Err(e
) => panic
!("{}", e
)
1888 assert_eq
!(matches
.opts_str(&["o".to_string()]).unwrap(), "A=B");
1889 assert_eq
!(matches
.opts_str(&["t".to_string()]).unwrap(), "C=D");
1893 fn test_long_only_usage() {
1894 let mut opts
= Options
::new();
1895 opts
.long_only(true);
1896 opts
.optflag("k", "kiwi", "Description");
1897 opts
.optflag("a", "apple", "Description");
1903 -k, -kiwi Description
1904 -a, -apple Description
1907 let usage
= opts
.usage("Usage: fruits");
1909 debug
!("expected: <<{}>>", expected
);
1910 debug
!("generated: <<{}>>", usage
);
1911 assert
!(usage
== expected
)
1915 fn test_long_only_mode() {
1916 let mut opts
= Options
::new();
1917 opts
.long_only(true);
1918 opts
.optopt("a", "apple", "Description", "X");
1919 opts
.optopt("b", "banana", "Description", "X");
1920 opts
.optopt("c", "currant", "Description", "X");
1921 opts
.optopt("", "durian", "Description", "X");
1922 opts
.optopt("e", "", "Description", "X");
1923 opts
.optopt("", "fruit", "Description", "X");
1925 let args
= vec
!("-a", "A", "-b=B", "--c=C", "-durian", "D", "--e", "E",
1927 let matches
= &match opts
.parse(&args
) {
1929 Err(e
) => panic
!("{}", e
)
1931 assert_eq
!(matches
.opts_str(&["a".to_string()]).unwrap(), "A");
1932 assert_eq
!(matches
.opts_str(&["b".to_string()]).unwrap(), "B");
1933 assert_eq
!(matches
.opts_str(&["c".to_string()]).unwrap(), "C");
1934 assert_eq
!(matches
.opts_str(&["durian".to_string()]).unwrap(), "D");
1935 assert_eq
!(matches
.opts_str(&["e".to_string()]).unwrap(), "E");
1936 assert_eq
!(matches
.opts_str(&["fruit".to_string()]).unwrap(), "any");
1940 fn test_long_only_mode_no_short_parse() {
1941 let mut opts
= Options
::new();
1942 opts
.long_only(true);
1943 opts
.optflag("h", "help", "Description");
1944 opts
.optflag("i", "ignore", "Description");
1945 opts
.optflag("", "hi", "Description");
1947 let args
= vec
!("-hi");
1948 let matches
= &match opts
.parse(&args
) {
1950 Err(e
) => panic
!("{}", e
)
1952 assert
!(matches
.opt_present("hi"));
1953 assert
!(!matches
.opt_present("h"));
1954 assert
!(!matches
.opt_present("i"));
1958 fn test_normal_mode_no_long_parse() {
1959 // Like test_long_only_mode_no_short_parse, but we make sure
1960 // that long_only can be disabled, and the right thing
1962 let mut opts
= Options
::new();
1963 opts
.long_only(true);
1964 opts
.optflag("h", "help", "Description");
1965 opts
.optflag("i", "ignore", "Description");
1966 opts
.optflag("", "hi", "Description");
1967 opts
.long_only(false);
1969 let args
= vec
!("-hi");
1970 let matches
= &match opts
.parse(&args
) {
1972 Err(e
) => panic
!("{}", e
)
1974 assert
!(!matches
.opt_present("hi"));
1975 assert
!(matches
.opt_present("h"));
1976 assert
!(matches
.opt_present("i"));
1981 fn test_long_name_too_short() {
1982 let mut opts
= Options
::new();
1983 opts
.optflag("", "a", "Oops, long option too short");