This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new 2130068  Avoid throwing NullPointerException when calling 
CommandLineParser will null array elements
2130068 is described below

commit 21300689546875736fce627970842691da97bd07
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat May 11 10:03:37 2024 -0400

    Avoid throwing NullPointerException when calling CommandLineParser will
    null array elements
---
 src/changes/changes.xml                            |  1 +
 .../java/org/apache/commons/cli/DefaultParser.java | 34 ++++-----
 .../java/org/apache/commons/cli/GnuParser.java     | 56 ++++++++-------
 src/main/java/org/apache/commons/cli/Parser.java   | 61 ++++++++--------
 .../java/org/apache/commons/cli/PosixParser.java   | 83 ++++++++++------------
 .../apache/commons/cli/AbstractParserTestCase.java | 17 +++++
 6 files changed, 133 insertions(+), 119 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 746a4a7..ebc9d9f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,7 @@
   <body>
     <release version="1.7.1" date="YYYY-MM-DD" description="This release 
contains new features and bug fixes and requires Java 8 or above.">
       <action type="fix" issue="CLI-331" dev="ggregory" due-to="Claude Warren, 
Gary Gregory">Handle reporting of deprecated options when parameters are not 
String type. #270.</action>
+      <action type="fix" issue="CLI-331" dev="ggregory" due-to="Claude Warren, 
Gary Gregory">Avoid throwing NullPointerException when calling 
CommandLineParser will null array elements.</action>
     </release>
     <release version="1.7.0" date="2024-04-13" description="This release 
contains new features and bug fixes and requires Java 8 or above.">
       <!-- FIX -->
diff --git a/src/main/java/org/apache/commons/cli/DefaultParser.java 
b/src/main/java/org/apache/commons/cli/DefaultParser.java
index a39ce4b..7dd9bfd 100644
--- a/src/main/java/org/apache/commons/cli/DefaultParser.java
+++ b/src/main/java/org/apache/commons/cli/DefaultParser.java
@@ -541,22 +541,24 @@ public class DefaultParser implements CommandLineParser {
      * @throws ParseException
      */
     private void handleToken(final String token) throws ParseException {
-        currentToken = token;
-        if (skipParsing) {
-            cmd.addArg(token);
-        } else if ("--".equals(token)) {
-            skipParsing = true;
-        } else if (currentOption != null && currentOption.acceptsArg() && 
isArgument(token)) {
-            
currentOption.processValue(stripLeadingAndTrailingQuotesDefaultOn(token));
-        } else if (token.startsWith("--")) {
-            handleLongOption(token);
-        } else if (token.startsWith("-") && !"-".equals(token)) {
-            handleShortAndLongOption(token);
-        } else {
-            handleUnknownToken(token);
-        }
-        if (currentOption != null && !currentOption.acceptsArg()) {
-            currentOption = null;
+        if (token != null) {
+            currentToken = token;
+            if (skipParsing) {
+                cmd.addArg(token);
+            } else if ("--".equals(token)) {
+                skipParsing = true;
+            } else if (currentOption != null && currentOption.acceptsArg() && 
isArgument(token)) {
+                
currentOption.processValue(stripLeadingAndTrailingQuotesDefaultOn(token));
+            } else if (token.startsWith("--")) {
+                handleLongOption(token);
+            } else if (token.startsWith("-") && !"-".equals(token)) {
+                handleShortAndLongOption(token);
+            } else {
+                handleUnknownToken(token);
+            }
+            if (currentOption != null && !currentOption.acceptsArg()) {
+                currentOption = null;
+            }
         }
     }
 
diff --git a/src/main/java/org/apache/commons/cli/GnuParser.java 
b/src/main/java/org/apache/commons/cli/GnuParser.java
index 20b4df3..a5f6c51 100644
--- a/src/main/java/org/apache/commons/cli/GnuParser.java
+++ b/src/main/java/org/apache/commons/cli/GnuParser.java
@@ -48,37 +48,39 @@ public class GnuParser extends Parser {
         boolean eatTheRest = false;
         for (int i = 0; i < arguments.length; i++) {
             final String arg = arguments[i];
-            if ("--".equals(arg)) {
-                eatTheRest = true;
-                tokens.add("--");
-            } else if ("-".equals(arg)) {
-                tokens.add("-");
-            } else if (arg.startsWith("-")) {
-                final String opt = Util.stripLeadingHyphens(arg);
-                if (options.hasOption(opt)) {
-                    tokens.add(arg);
-                } else {
-                    final int equalPos = DefaultParser.indexOfEqual(opt);
-                    if (equalPos != -1 && options.hasOption(opt.substring(0, 
equalPos))) {
-                        // the format is --foo=value or -foo=value
-                        tokens.add(arg.substring(0, arg.indexOf(Char.EQUAL))); 
// --foo
-                        tokens.add(arg.substring(arg.indexOf(Char.EQUAL) + 
1)); // value
-                    } else if (options.hasOption(arg.substring(0, 2))) {
-                        // the format is a special properties option 
(-Dproperty=value)
-                        tokens.add(arg.substring(0, 2)); // -D
-                        tokens.add(arg.substring(2)); // property=value
-                    } else {
-                        eatTheRest = stopAtNonOption;
+            if (arg != null) {
+                if ("--".equals(arg)) {
+                    eatTheRest = true;
+                    tokens.add("--");
+                } else if ("-".equals(arg)) {
+                    tokens.add("-");
+                } else if (arg.startsWith("-")) {
+                    final String opt = Util.stripLeadingHyphens(arg);
+                    if (options.hasOption(opt)) {
                         tokens.add(arg);
+                    } else {
+                        final int equalPos = DefaultParser.indexOfEqual(opt);
+                        if (equalPos != -1 && 
options.hasOption(opt.substring(0, equalPos))) {
+                            // the format is --foo=value or -foo=value
+                            tokens.add(arg.substring(0, 
arg.indexOf(Char.EQUAL))); // --foo
+                            tokens.add(arg.substring(arg.indexOf(Char.EQUAL) + 
1)); // value
+                        } else if (options.hasOption(arg.substring(0, 2))) {
+                            // the format is a special properties option 
(-Dproperty=value)
+                            tokens.add(arg.substring(0, 2)); // -D
+                            tokens.add(arg.substring(2)); // property=value
+                        } else {
+                            eatTheRest = stopAtNonOption;
+                            tokens.add(arg);
+                        }
                     }
+                } else {
+                    tokens.add(arg);
                 }
-            } else {
-                tokens.add(arg);
-            }
 
-            if (eatTheRest) {
-                for (i++; i < arguments.length; i++) { // NOPMD
-                    tokens.add(arguments[i]);
+                if (eatTheRest) {
+                    for (i++; i < arguments.length; i++) { // NOPMD
+                        tokens.add(arguments[i]);
+                    }
                 }
             }
         }
diff --git a/src/main/java/org/apache/commons/cli/Parser.java 
b/src/main/java/org/apache/commons/cli/Parser.java
index 8f6ab86..fcd574b 100644
--- a/src/main/java/org/apache/commons/cli/Parser.java
+++ b/src/main/java/org/apache/commons/cli/Parser.java
@@ -156,41 +156,40 @@ public abstract class Parser implements CommandLineParser 
{
         // process each flattened token
         while (iterator.hasNext()) {
             final String token = iterator.next();
-            // the value is the double-dash
-            if ("--".equals(token)) {
-                eatTheRest = true;
-            }
-            // the value is a single dash
-            else if ("-".equals(token)) {
-                if (stopAtNonOption) {
+            if (token != null) {
+                // the value is the double-dash
+                if ("--".equals(token)) {
                     eatTheRest = true;
+                } else if ("-".equals(token)) {
+                    // the value is a single dash
+                    if (stopAtNonOption) {
+                        eatTheRest = true;
+                    } else {
+                        cmd.addArg(token);
+                    }
+                } else if (token.startsWith("-")) {
+                    // the value is an option
+                    if (stopAtNonOption && !getOptions().hasOption(token)) {
+                        eatTheRest = true;
+                        cmd.addArg(token);
+                    } else {
+                        processOption(token, iterator);
+                    }
                 } else {
+                    // the value is an argument
                     cmd.addArg(token);
+                    if (stopAtNonOption) {
+                        eatTheRest = true;
+                    }
                 }
-            }
-            // the value is an option
-            else if (token.startsWith("-")) {
-                if (stopAtNonOption && !getOptions().hasOption(token)) {
-                    eatTheRest = true;
-                    cmd.addArg(token);
-                } else {
-                    processOption(token, iterator);
-                }
-            }
-            // the value is an argument
-            else {
-                cmd.addArg(token);
-                if (stopAtNonOption) {
-                    eatTheRest = true;
-                }
-            }
-            // eat the remaining tokens
-            if (eatTheRest) {
-                while (iterator.hasNext()) {
-                    final String str = iterator.next();
-                    // ensure only one double-dash is added
-                    if (!"--".equals(str)) {
-                        cmd.addArg(str);
+                // eat the remaining tokens
+                if (eatTheRest) {
+                    while (iterator.hasNext()) {
+                        final String str = iterator.next();
+                        // ensure only one double-dash is added
+                        if (!"--".equals(str)) {
+                            cmd.addArg(str);
+                        }
                     }
                 }
             }
diff --git a/src/main/java/org/apache/commons/cli/PosixParser.java 
b/src/main/java/org/apache/commons/cli/PosixParser.java
index 0071929..18a826f 100644
--- a/src/main/java/org/apache/commons/cli/PosixParser.java
+++ b/src/main/java/org/apache/commons/cli/PosixParser.java
@@ -119,63 +119,56 @@ public class PosixParser extends Parser {
     protected String[] flatten(final Options options, final String[] 
arguments, final boolean stopAtNonOption) throws ParseException {
         init();
         this.options = options;
-
         // an iterator for the command line tokens
         final Iterator<String> iter = Arrays.asList(arguments).iterator();
-
         // process each command line token
         while (iter.hasNext()) {
             // get the next command line token
             final String token = iter.next();
-
-            // single or double hyphen
-            if ("-".equals(token) || "--".equals(token)) {
-                tokens.add(token);
-            }
-
-            // handle long option --foo or --foo=bar
-            else if (token.startsWith("--")) {
-                final int pos = DefaultParser.indexOfEqual(token);
-                final String opt = pos == -1 ? token : token.substring(0, 
pos); // --foo
-
-                final List<String> matchingOpts = 
options.getMatchingOptions(opt);
-
-                if (matchingOpts.isEmpty()) {
-                    processNonOptionToken(token, stopAtNonOption);
-                } else if (matchingOpts.size() > 1) {
-                    throw new AmbiguousOptionException(opt, matchingOpts);
-                } else {
-                    currentOption = options.getOption(matchingOpts.get(0));
-
-                    tokens.add("--" + currentOption.getLongOpt());
-                    if (pos != -1) {
-                        tokens.add(token.substring(pos + 1));
+            if (token != null) {
+                // single or double hyphen
+                if ("-".equals(token) || "--".equals(token)) {
+                    tokens.add(token);
+                } else if (token.startsWith("--")) {
+                    // handle long option --foo or --foo=bar
+                    final int pos = DefaultParser.indexOfEqual(token);
+                    final String opt = pos == -1 ? token : token.substring(0, 
pos); // --foo
+
+                    final List<String> matchingOpts = 
options.getMatchingOptions(opt);
+
+                    if (matchingOpts.isEmpty()) {
+                        processNonOptionToken(token, stopAtNonOption);
+                    } else if (matchingOpts.size() > 1) {
+                        throw new AmbiguousOptionException(opt, matchingOpts);
+                    } else {
+                        currentOption = options.getOption(matchingOpts.get(0));
+
+                        tokens.add("--" + currentOption.getLongOpt());
+                        if (pos != -1) {
+                            tokens.add(token.substring(pos + 1));
+                        }
                     }
-                }
-            }
-
-            else if (token.startsWith("-")) {
-                if (token.length() == 2 || options.hasOption(token)) {
-                    processOptionToken(token, stopAtNonOption);
-                } else if (!options.getMatchingOptions(token).isEmpty()) {
-                    final List<String> matchingOpts = 
options.getMatchingOptions(token);
-                    if (matchingOpts.size() > 1) {
-                        throw new AmbiguousOptionException(token, 
matchingOpts);
+                } else if (token.startsWith("-")) {
+                    if (token.length() == 2 || options.hasOption(token)) {
+                        processOptionToken(token, stopAtNonOption);
+                    } else if (!options.getMatchingOptions(token).isEmpty()) {
+                        final List<String> matchingOpts = 
options.getMatchingOptions(token);
+                        if (matchingOpts.size() > 1) {
+                            throw new AmbiguousOptionException(token, 
matchingOpts);
+                        }
+                        final Option opt = 
options.getOption(matchingOpts.get(0));
+                        processOptionToken("-" + opt.getLongOpt(), 
stopAtNonOption);
                     }
-                    final Option opt = options.getOption(matchingOpts.get(0));
-                    processOptionToken("-" + opt.getLongOpt(), 
stopAtNonOption);
-                }
-                // requires bursting
-                else {
-                    burstToken(token, stopAtNonOption);
+                    // requires bursting
+                    else {
+                        burstToken(token, stopAtNonOption);
+                    }
+                } else {
+                    processNonOptionToken(token, stopAtNonOption);
                 }
-            } else {
-                processNonOptionToken(token, stopAtNonOption);
             }
-
             gobble(iter);
         }
-
         return tokens.toArray(Util.EMPTY_STRING_ARRAY);
     }
 
diff --git a/src/test/java/org/apache/commons/cli/AbstractParserTestCase.java 
b/src/test/java/org/apache/commons/cli/AbstractParserTestCase.java
index 8c33fdd..69c61e4 100644
--- a/src/test/java/org/apache/commons/cli/AbstractParserTestCase.java
+++ b/src/test/java/org/apache/commons/cli/AbstractParserTestCase.java
@@ -420,6 +420,23 @@ public abstract class AbstractParserTestCase {
         assertEquals("foobar", cl.getArgList().get(0), "Confirm  value of 
extra arg: " + cl.getArgList().get(0));
     }
 
+    @Test
+    public void testMultipleWithNull() throws Exception {
+        final String[] args = { null, "-c", null, "foobar", null, "-b", null, 
"toast", null };
+
+        CommandLine cl = parser.parse(options, args, true);
+        assertTrue(cl.hasOption("c"), "Confirm -c is set");
+        assertEquals(3, cl.getArgList().size(), "Confirm  3 extra args: " + 
cl.getArgList().size());
+
+        cl = parser.parse(options, cl.getArgs());
+
+        assertFalse(cl.hasOption("c"), "Confirm -c is not set");
+        assertTrue(cl.hasOption("b"), "Confirm -b is set");
+        assertEquals("toast", cl.getOptionValue("b"), "Confirm arg of -b");
+        assertEquals(1, cl.getArgList().size(), "Confirm  1 extra arg: " + 
cl.getArgList().size());
+        assertEquals("foobar", cl.getArgList().get(0), "Confirm  value of 
extra arg: " + cl.getArgList().get(0));
+    }
+
     @Test
     public void testMultipleWithLong() throws Exception {
         final String[] args = { "--copt", "foobar", "--bfile", "toast" };

Reply via email to