Skip to content

Commit 74b2e2a

Browse files
committed
Ability to skip unrecognized token
And continue parsing.
1 parent cd272c3 commit 74b2e2a

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

src/main/java/org/apache/commons/cli/DefaultParser.java

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,24 @@ public Builder setStripLeadingAndTrailingQuotes(final Boolean stripLeadingAndTra
153153
}
154154
}
155155

156+
/**
157+
* The operation to execute when unrecognized token is found.
158+
*/
159+
public enum UnrecognizedTokensOperation {
160+
/**
161+
* Equivalent of old {@code stopAtNonOption = true}.
162+
*/
163+
STOP,
164+
/**
165+
* Unrecognized token is added to args list and parsing continues.
166+
*/
167+
SKIP,
168+
/**
169+
* Equivalent of old {@code stopAtNonOption = false}.
170+
*/
171+
THROW
172+
}
173+
156174
/**
157175
* Creates a new {@link Builder} to create an {@link DefaultParser} using descriptive
158176
* methods.
@@ -178,7 +196,7 @@ static int indexOfEqual(final String token) {
178196
* Flag indicating how unrecognized tokens are handled. {@code true} to stop the parsing and add the remaining
179197
* tokens to the args list. {@code false} to throw an exception.
180198
*/
181-
protected boolean stopAtNonOption;
199+
protected UnrecognizedTokensOperation unrecognizedTokensOperation = UnrecognizedTokensOperation.THROW;
182200

183201
/** The token currently processed. */
184202
protected String currentToken;
@@ -356,7 +374,7 @@ protected void handleConcatenatedOptions(final String token) throws ParseExcepti
356374
for (int i = 1; i < token.length(); i++) {
357375
final String ch = String.valueOf(token.charAt(i));
358376
if (!options.hasOption(ch)) {
359-
handleUnknownToken(stopAtNonOption && i > 1 ? token.substring(i) : token);
377+
handleUnknownToken(unrecognizedTokensOperation == UnrecognizedTokensOperation.STOP && i > 1 ? token.substring(i) : token);
360378
break;
361379
}
362380
handleOption(options.getOption(ch));
@@ -580,15 +598,16 @@ private void handleToken(final String token) throws ParseException {
580598
* Handles an unknown token. If the token starts with a dash an UnrecognizedOptionException is thrown. Otherwise the
581599
* token is added to the arguments of the command line. If the stopAtNonOption flag is set, this stops the parsing and
582600
* the remaining tokens are added as-is in the arguments of the command line.
601+
* <p>
583602
*
584603
* @param token the command line token to handle
585604
*/
586-
private void handleUnknownToken(final String token) throws ParseException {
587-
if (token.startsWith("-") && token.length() > 1 && !stopAtNonOption) {
605+
protected void handleUnknownToken(final String token) throws ParseException {
606+
if (token.startsWith("-") && token.length() > 1 && unrecognizedTokensOperation == UnrecognizedTokensOperation.THROW) {
588607
throw new UnrecognizedOptionException("Unrecognized option: " + token, token);
589608
}
590609
cmd.addArg(token);
591-
if (stopAtNonOption) {
610+
if (unrecognizedTokensOperation == UnrecognizedTokensOperation.STOP) {
592611
skipParsing = true;
593612
}
594613
}
@@ -678,14 +697,18 @@ private boolean isShortOption(final String token) {
678697

679698
@Override
680699
public CommandLine parse(final Options options, final String[] arguments) throws ParseException {
681-
return parse(options, arguments, null);
700+
return parse(options, arguments, (Properties) null);
682701
}
683702

684703
@Override
685704
public CommandLine parse(final Options options, final String[] arguments, final boolean stopAtNonOption) throws ParseException {
686705
return parse(options, arguments, null, stopAtNonOption);
687706
}
688707

708+
public CommandLine parse(final Options options, final String[] arguments, final UnrecognizedTokensOperation uto) throws ParseException {
709+
return parse(options, arguments, null, uto);
710+
}
711+
689712
/**
690713
* Parses the arguments according to the specified options and properties.
691714
*
@@ -713,9 +736,25 @@ public CommandLine parse(final Options options, final String[] arguments, final
713736
* @throws ParseException if there are any problems encountered while parsing the command line tokens.
714737
*/
715738
public CommandLine parse(final Options options, final String[] arguments, final Properties properties, final boolean stopAtNonOption)
739+
throws ParseException {
740+
return parse(options, arguments, properties, stopAtNonOption ? UnrecognizedTokensOperation.STOP : UnrecognizedTokensOperation.THROW);
741+
}
742+
743+
/**
744+
* Parses the arguments according to the specified options and properties.
745+
*
746+
* @param options the specified Options
747+
* @param arguments the command line arguments
748+
* @param properties command line option name-value pairs
749+
* @param uto The operation to perform when unrecognized token is found.
750+
*
751+
* @return the list of atomic option and value tokens
752+
* @throws ParseException if there are any problems encountered while parsing the command line tokens.
753+
*/
754+
public CommandLine parse(final Options options, final String[] arguments, final Properties properties, final UnrecognizedTokensOperation uto)
716755
throws ParseException {
717756
this.options = options;
718-
this.stopAtNonOption = stopAtNonOption;
757+
this.unrecognizedTokensOperation = uto;
719758
skipParsing = false;
720759
currentOption = null;
721760
expectedOpts = new ArrayList<>(options.getRequiredOptions());

src/test/java/org/apache/commons/cli/DefaultParserTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ Licensed to the Apache Software Foundation (ASF) under one or more
2121
import static org.junit.jupiter.api.Assertions.assertFalse;
2222
import static org.junit.jupiter.api.Assertions.assertTrue;
2323

24+
import java.util.Arrays;
2425
import java.util.HashSet;
26+
import java.util.List;
2527
import java.util.Set;
2628
import java.util.stream.Stream;
2729

@@ -157,6 +159,25 @@ public void setUp() {
157159
parser = new DefaultParser();
158160
}
159161

162+
@Test
163+
void testSkip() throws ParseException {
164+
final Options options = new Options();
165+
options.addOption(Option.builder("a").longOpt("first-letter").build());
166+
options.addOption(Option.builder("b").longOpt("second-letter").build());
167+
168+
final DefaultParser parser = DefaultParser.builder().get();
169+
final CommandLine commandLine = parser.parse(options, new String[] {"-a", "-b", "-c", "-d"}, DefaultParser.UnrecognizedTokensOperation.SKIP);
170+
assertTrue(commandLine.hasOption("a"));
171+
assertTrue(commandLine.hasOption("b"));
172+
assertFalse(commandLine.hasOption("c"));
173+
assertFalse(commandLine.hasOption("d"));
174+
175+
assertFalse(commandLine.getArgList().contains("-a"));
176+
assertFalse(commandLine.getArgList().contains("-b"));
177+
assertTrue(commandLine.getArgList().contains("-c"));
178+
assertTrue(commandLine.getArgList().contains("-d"));
179+
}
180+
160181
@Test
161182
void testBuilder() {
162183
// @formatter:off

0 commit comments

Comments
 (0)