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)
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()),