Skip to content

Commit b92abb2

Browse files
author
Robert James Oxspring
committed
Fixed second bug where infinite loops could occur. This
time it was over eager processing of anonymous arguments in a group. Test case included. Reported by Steve Alberty git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/cli/trunk@190821 13f79535-47bb-0310-9956-ffa450edef68
1 parent 0c5f405 commit b92abb2

3 files changed

Lines changed: 59 additions & 3 deletions

File tree

src/java/org/apache/commons/cli2/commandline/Parser.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import java.io.IOException;
1919
import java.util.ArrayList;
20-
import java.util.Arrays;
2120
import java.util.LinkedList;
2221
import java.util.List;
2322
import java.util.ListIterator;
@@ -56,7 +55,18 @@ public class Parser {
5655
public CommandLine parse(final String[] arguments) throws OptionException {
5756

5857
// build a mutable list for the arguments
59-
final List argumentList = new LinkedList(Arrays.asList(arguments));
58+
final List argumentList = new LinkedList();
59+
60+
// copy the arguments into the new list
61+
for (int i = 0; i < arguments.length; i++) {
62+
final String argument = arguments[i];
63+
64+
// ensure non intern'd strings are used
65+
// so that == comparisons work as expected
66+
argumentList.add(new String(argument));
67+
}
68+
69+
// wet up a command line for this group
6070
final WriteableCommandLine commandLine =
6171
new WriteableCommandLineImpl(group, new ArrayList());
6272

@@ -65,7 +75,21 @@ public CommandLine parse(final String[] arguments) throws OptionException {
6575

6676
// process the options as far as possible
6777
final ListIterator iterator = argumentList.listIterator();
78+
Object previous = null;
6879
while (group.canProcess(commandLine, iterator)) {
80+
81+
// peek at the next item and backtrack
82+
final Object next = iterator.next();
83+
iterator.previous();
84+
85+
// if we have just tried to process this instance
86+
if(next==previous) {
87+
// abort
88+
break;
89+
}
90+
// remember previous
91+
previous = next;
92+
6993
group.process(commandLine, iterator);
7094
}
7195

src/java/org/apache/commons/cli2/option/GroupImpl.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,24 @@ public void process(
160160
final WriteableCommandLine commandLine,
161161
final ListIterator arguments)
162162
throws OptionException {
163+
164+
String previous = null;
163165

164166
// [START process each command line token
165167
while (arguments.hasNext()) {
166-
168+
169+
// grab the next argument
167170
final String arg = (String)arguments.next();
171+
172+
// if we have just tried to process this instance
173+
if(arg==previous) {
174+
// rollback and abort
175+
arguments.previous();
176+
break;
177+
}
178+
// remember last processed instance
179+
previous = arg;
180+
168181
final Option opt = (Option)optionMap.get(arg);
169182

170183
// option found

src/test/org/apache/commons/cli2/bug/BugLoopingOptionLookAlikeTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717

1818
import junit.framework.TestCase;
1919

20+
import org.apache.commons.cli2.Argument;
2021
import org.apache.commons.cli2.Group;
2122
import org.apache.commons.cli2.OptionException;
2223
import org.apache.commons.cli2.builder.ArgumentBuilder;
2324
import org.apache.commons.cli2.builder.DefaultOptionBuilder;
2425
import org.apache.commons.cli2.builder.GroupBuilder;
2526
import org.apache.commons.cli2.commandline.Parser;
27+
import org.apache.commons.cli2.option.SourceDestArgument;
2628

2729
/**
2830
* The first is a loop in Parser.parse() if I set a non-declared option. This
@@ -54,4 +56,21 @@ public void testLoopingOptionLookAlike() {
5456
assertEquals("Unexpected -abcdef while processing ant",e.getMessage());
5557
}
5658
}
59+
60+
public void testLoopingOptionLookAlike2() {
61+
final ArgumentBuilder abuilder = new ArgumentBuilder();
62+
final GroupBuilder gbuilder = new GroupBuilder();
63+
final Argument inputfile_opt = abuilder.withName("input").withMinimum(1).withMaximum(1).create();
64+
final Argument outputfile_opt = abuilder.withName("output").withMinimum(1).withMaximum(1).create();
65+
final Argument targets = new SourceDestArgument(inputfile_opt, outputfile_opt);
66+
final Group options = gbuilder.withOption(targets).create();
67+
final Parser parser = new Parser();
68+
parser.setGroup(options);
69+
try {
70+
parser.parse(new String[] { "testfile.txt", "testfile.txt", "testfile.txt", "testfile.txt" });
71+
fail("OptionException");
72+
} catch (OptionException e) {
73+
assertEquals("Unexpected testfile.txt while processing ", e.getMessage());
74+
}
75+
}
5776
}

0 commit comments

Comments
 (0)