about summary refs log tree commit diff
diff options
context:
space:
mode:
authorwickerwaka <martin.donlon@gmail.com>2014-08-14 21:44:55 -0700
committerwickerwaka <martin.donlon@gmail.com>2014-08-15 06:34:24 -0700
commit08d7fc76cf6b2fac291cecd7185af818940092e4 (patch)
tree49a057339ce16e4469332142e9f85564eea9eedc
parent1d12b6d444ec083466020777be5bb9f19e9a6d3a (diff)
downloadrust-08d7fc76cf6b2fac291cecd7185af818940092e4.tar.gz
rust-08d7fc76cf6b2fac291cecd7185af818940092e4.zip
Change how libgetopts handles options grouped together
As soon as an option is found that takes an argument, consume the rest
of the string and store it into i_arg. Previously this would only happen
if the character after the option was not a recognized option.

Addresses issue #16348
-rw-r--r--src/libgetopts/lib.rs55
1 files changed, 33 insertions, 22 deletions
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index 6339dc58446..d0c06f8e6ba 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -567,7 +567,6 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
                 }
             } else {
                 let mut j = 1;
-                let mut last_valid_opt_id = None;
                 names = Vec::new();
                 while j < curlen {
                     let range = cur.as_slice().char_range_at(j);
@@ -580,27 +579,24 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
                        interpreted correctly
                     */
 
-                    match find_opt(opts.as_slice(), opt.clone()) {
-                      Some(id) => last_valid_opt_id = Some(id),
-                      None => {
-                        let arg_follows =
-                            last_valid_opt_id.is_some() &&
-                            match opts[last_valid_opt_id.unwrap()]
-                              .hasarg {
-
-                              Yes | Maybe => true,
-                              No => false
-                            };
-                        if arg_follows && j < curlen {
-                            i_arg = Some(cur.as_slice()
-                                            .slice(j, curlen).to_string());
-                            break;
-                        } else {
-                            last_valid_opt_id = None;
-                        }
-                      }
-                    }
+                    let opt_id = match find_opt(opts.as_slice(), opt.clone()) {
+                      Some(id) => id,
+                      None => return Err(UnrecognizedOption(opt.to_string()))
+                    };
+
                     names.push(opt);
+
+                    let arg_follows = match opts[opt_id].hasarg {
+                        Yes | Maybe => true,
+                        No => false
+                    };
+
+                    if arg_follows && range.next < curlen {
+                        i_arg = Some(cur.as_slice()
+                                        .slice(range.next, curlen).to_string());
+                        break;
+                    }
+
                     j = range.next;
                 }
             }
@@ -613,7 +609,7 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
                 };
                 match opts[optid].hasarg {
                   No => {
-                    if !i_arg.is_none() {
+                    if name_pos == names.len() && !i_arg.is_none() {
                         return Err(UnexpectedArgument(nm.to_string()));
                     }
                     vals.get_mut(optid).push(Given);
@@ -1438,6 +1434,21 @@ mod tests {
     }
 
     #[test]
+    fn test_nospace_conflict() {
+        let args = vec!("-vvLverbose".to_string(), "-v".to_string() );
+        let opts = vec!(optmulti("L", "", "library directory", "LIB"),
+                     optflagmulti("v", "verbose", "Verbose"));
+        let matches = &match getopts(args.as_slice(), opts.as_slice()) {
+          result::Ok(m) => m,
+          result::Err(e) => fail!( "{}", e )
+        };
+        assert!(matches.opts_present(["L".to_string()]));
+        assert_eq!(matches.opts_str(["L".to_string()]).unwrap(), "verbose".to_string());
+        assert!(matches.opts_present(["v".to_string()]));
+        assert_eq!(3, matches.opt_count("v"));
+    }
+
+    #[test]
     fn test_long_to_short() {
         let mut short = Opt {
             name: Long("banana".to_string()),