Skip to content

Commit

Permalink
Merge pull request #100 from zdenek-crha/parse_args_end_position
Browse files Browse the repository at this point in the history
Add support for detecting args after double-dash
  • Loading branch information
KodrAus committed Jan 14, 2021
2 parents 6e5c619 + 1b52757 commit c11eb65
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 3 deletions.
51 changes: 50 additions & 1 deletion src/lib.rs
Expand Up @@ -433,6 +433,8 @@ impl Options {
.map(|_| Vec::new())
.collect::<Vec<Vec<(usize, Optval)>>>();
let mut free: Vec<String> = Vec::new();
let mut args_end = None;

let args = args
.into_iter()
.map(|i| {
Expand All @@ -455,6 +457,7 @@ impl Options {
}
}
} else if cur == "--" {
args_end = Some(free.len());
free.extend(args);
break;
} else {
Expand Down Expand Up @@ -557,7 +560,12 @@ impl Options {
return Err(OptionDuplicated(opt.name.to_string()));
}
}
Ok(Matches { opts, vals, free })

// Note that if "--" is last argument on command line, then index stored
// in option does not exist in `free` and must be replaced with `None`
args_end = args_end.filter(|pos| pos != &free.len());

Ok(Matches { opts, vals, free, args_end })
}

/// Derive a short one-line usage summary from a set of long options.
Expand Down Expand Up @@ -778,8 +786,12 @@ pub struct Matches {
opts: Vec<Opt>,
/// Values of the Options that matched and their positions
vals: Vec<Vec<(usize, Optval)>>,

/// Free string fragments
pub free: Vec<String>,

/// Index of first free fragment after "--" separator
args_end: Option<usize>,
}

/// The type returned when the command line does not conform to the
Expand Down Expand Up @@ -1104,6 +1116,43 @@ impl Matches {
None => Ok(def),
}
}

/// Returns index of first free argument after "--".
///
/// If double-dash separator is present and there are some args after it in
/// the argument list then the method returns index into `free` vector
/// indicating first argument after it.
/// behind it.
///
/// # Examples
///
/// ```
/// # use getopts::Options;
/// let mut opts = Options::new();
///
/// let matches = opts.parse(&vec!["arg1", "--", "arg2"]).unwrap();
/// let end_pos = matches.free_trailing_start().unwrap();
/// assert_eq!(end_pos, 1);
/// assert_eq!(matches.free[end_pos], "arg2".to_owned());
/// ```
///
/// If the double-dash is missing from argument list or if there are no
/// arguments after it:
///
/// ```
/// # use getopts::Options;
/// let mut opts = Options::new();
///
/// let matches = opts.parse(&vec!["arg1", "--"]).unwrap();
/// assert_eq!(matches.free_trailing_start(), None);
///
/// let matches = opts.parse(&vec!["arg1", "arg2"]).unwrap();
/// assert_eq!(matches.free_trailing_start(), None);
/// ```
///
pub fn free_trailing_start(&self) -> Option<usize> {
self.args_end
}
}

fn is_arg(arg: &str) -> bool {
Expand Down
29 changes: 27 additions & 2 deletions src/tests/mod.rs
Expand Up @@ -207,12 +207,24 @@ fn test_optflag_missing() {
}

#[test]
fn test_opt_end() {
fn test_free_trailing_missing() {
let args = vec![] as Vec<String>;
match Options::new().parse(&args) {
Ok(ref m) => {
assert_eq!(m.free_trailing_start(), None);
}
_ => panic!(),
}
}

#[test]
fn test_free_trailing() {
let args = vec!["--".to_owned(), "-t".to_owned()];
match Options::new().optflag("t", "test", "testing").parse(&args) {
Ok(ref m) => {
assert!(!m.opt_present("test"));
assert!(!m.opt_present("t"));
assert_eq!(m.free_trailing_start(), Some(0));
assert_eq!(m.free.len(), 1);
assert_eq!(m.free[0], "-t");
}
Expand All @@ -221,18 +233,31 @@ fn test_opt_end() {
}

#[test]
fn test_opt_only_end() {
fn test_free_trailing_only() {
let args = vec!["--".to_owned()];
match Options::new().optflag("t", "test", "testing").parse(&args) {
Ok(ref m) => {
assert!(!m.opt_present("test"));
assert!(!m.opt_present("t"));
assert_eq!(m.free_trailing_start(), None);
assert_eq!(m.free.len(), 0);
}
_ => panic!(),
}
}

#[test]
fn test_free_trailing_args() {
let args = vec!["pre".to_owned(), "--".to_owned(), "post".to_owned() ];
match Options::new().parse(&args) {
Ok(ref m) => {
assert_eq!(m.free_trailing_start(), Some(1));
assert_eq!(m.free.len(), 2);
}
_ => panic!(),
}
}

#[test]
fn test_optflag_long_arg() {
let args = vec!["--test=20".to_string()];
Expand Down

0 comments on commit c11eb65

Please sign in to comment.