Author: oheger Date: Wed Jul 30 13:16:51 2008 New Revision: 681191 URL: http://svn.apache.org/viewvc?rev=681191&view=rev Log: CLI-150: Make WriteableCommandLineImpl.looksLikeOption() more intelligent, so that it does not misinterpret negative numbers passed to arguments as options.
Added: commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java (with props) Modified: commons/proper/cli/trunk/src/java/org/apache/commons/cli2/WriteableCommandLine.java commons/proper/cli/trunk/src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java commons/proper/cli/trunk/src/java/org/apache/commons/cli2/option/GroupImpl.java Modified: commons/proper/cli/trunk/src/java/org/apache/commons/cli2/WriteableCommandLine.java URL: http://svn.apache.org/viewvc/commons/proper/cli/trunk/src/java/org/apache/commons/cli2/WriteableCommandLine.java?rev=681191&r1=681190&r2=681191&view=diff ============================================================================== --- commons/proper/cli/trunk/src/java/org/apache/commons/cli2/WriteableCommandLine.java (original) +++ commons/proper/cli/trunk/src/java/org/apache/commons/cli2/WriteableCommandLine.java Wed Jul 30 13:16:51 2008 @@ -93,4 +93,20 @@ * @return true if the argument looks like an Option trigger */ boolean looksLikeOption(final String argument); + + /** + * Returns the option that is currently processed. + * + * @return the current option + */ + Option getCurrentOption(); + + /** + * Sets the current option. This method is called by concrete option + * implementations during command line processing. It enables the command + * line to keep track about the option that is currently processed. + * + * @param currentOption the new current option + */ + void setCurrentOption(Option currentOption); } Modified: commons/proper/cli/trunk/src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java URL: http://svn.apache.org/viewvc/commons/proper/cli/trunk/src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java?rev=681191&r1=681190&r2=681191&view=diff ============================================================================== --- commons/proper/cli/trunk/src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java (original) +++ commons/proper/cli/trunk/src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java Wed Jul 30 13:16:51 2008 @@ -48,6 +48,8 @@ private final Map defaultSwitches = new HashMap(); private final List normalised; private final Set prefixes; + private Option currentOption; + private String checkForOption; /** * Creates a new WriteableCommandLineImpl rooted on the specified Option, to @@ -60,6 +62,15 @@ final List arguments) { this.prefixes = rootOption.getPrefixes(); this.normalised = arguments; + setCurrentOption(rootOption); + } + + public Option getCurrentOption() { + return currentOption; + } + + public void setCurrentOption(Option currentOption) { + this.currentOption = currentOption; } public void addOption(Option option) { @@ -141,7 +152,7 @@ } } } - + return valueList == null ? Collections.EMPTY_LIST : valueList; } @@ -216,16 +227,48 @@ return getProperties(new PropertyOption()); } - public boolean looksLikeOption(final String trigger) { - for (final Iterator i = prefixes.iterator(); i.hasNext();) { - final String prefix = (String) i.next(); - - if (trigger.startsWith(prefix)) { - return true; + /** + * Tests whether the passed in trigger looks like an option. This + * implementation first checks whether the passed in string starts with a + * prefix that indicates an option. If this is the case, it is also checked + * whether an option of this name is known for the current option. (This can + * lead to reentrant invocations of this method, so care has to be taken + * about this.) + * + * @param trigger the command line element to test + * @return a flag whether this element seems to be an option + */ + public boolean looksLikeOption(final String trigger) + { + if (checkForOption != null) + { + // this is a reentrant call + return !checkForOption.equals(trigger); + } + + checkForOption = trigger; + try + { + for (final Iterator i = prefixes.iterator(); i.hasNext();) + { + final String prefix = (String) i.next(); + + if (trigger.startsWith(prefix)) + { + if (getCurrentOption().canProcess(this, trigger) + || getCurrentOption().findOption(trigger) != null) + { + return true; + } + } } - } - return false; + return false; + } + finally + { + checkForOption = null; + } } public String toString() { Modified: commons/proper/cli/trunk/src/java/org/apache/commons/cli2/option/GroupImpl.java URL: http://svn.apache.org/viewvc/commons/proper/cli/trunk/src/java/org/apache/commons/cli2/option/GroupImpl.java?rev=681191&r1=681190&r2=681191&view=diff ============================================================================== --- commons/proper/cli/trunk/src/java/org/apache/commons/cli2/option/GroupImpl.java (original) +++ commons/proper/cli/trunk/src/java/org/apache/commons/cli2/option/GroupImpl.java Wed Jul 30 13:16:51 2008 @@ -136,7 +136,7 @@ } } - if (commandLine.looksLikeOption(arg)) { + if (looksLikeOption(commandLine, arg)) { return false; } @@ -188,7 +188,7 @@ else { // it might be an anonymous argument continue search // [START argument may be anonymous - if (commandLine.looksLikeOption(arg)) { + if (looksLikeOption(commandLine, arg)) { // narrow the search final Collection values = optionMap.tailMap(arg).values(); @@ -498,6 +498,26 @@ option.defaults(commandLine); } } + + /** + * Helper method for testing whether an element of the command line looks + * like an option. This method queries the command line, but sets the + * current option first. + * + * @param commandLine the command line + * @param trigger the trigger to be checked + * @return a flag whether this element looks like an option + */ + private boolean looksLikeOption(final WriteableCommandLine commandLine, + final String trigger) { + Option oldOption = commandLine.getCurrentOption(); + try { + commandLine.setCurrentOption(this); + return commandLine.looksLikeOption(trigger); + } finally { + commandLine.setCurrentOption(oldOption); + } + } } Added: commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java URL: http://svn.apache.org/viewvc/commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java?rev=681191&view=auto ============================================================================== --- commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java (added) +++ commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java Wed Jul 30 13:16:51 2008 @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.cli2.bug; + +import junit.framework.TestCase; + +import org.apache.commons.cli2.Argument; +import org.apache.commons.cli2.CommandLine; +import org.apache.commons.cli2.Group; +import org.apache.commons.cli2.Option; +import org.apache.commons.cli2.OptionException; +import org.apache.commons.cli2.builder.ArgumentBuilder; +import org.apache.commons.cli2.builder.DefaultOptionBuilder; +import org.apache.commons.cli2.builder.GroupBuilder; +import org.apache.commons.cli2.commandline.Parser; +import org.apache.commons.cli2.validation.NumberValidator; + +/** + * An argument whose value is a negative number is mistaken as an option. + * + * @author Oliver Heger + * @version $Id$ + */ +public class BugCLI150Test extends TestCase +{ + public void testNegativeNumber() throws OptionException + { + final DefaultOptionBuilder oBuilder = new DefaultOptionBuilder(); + final ArgumentBuilder aBuilder = new ArgumentBuilder(); + final GroupBuilder gBuilder = new GroupBuilder(); + + final Argument numArg = aBuilder.withValidator( + NumberValidator.getNumberInstance()).withMinimum(1) + .withMaximum(1).create(); + final Option numOpt = oBuilder.withLongName("num").withArgument(numArg) + .create(); + final Group options = gBuilder.withOption(numOpt).create(); + + final Parser parser = new Parser(); + parser.setGroup(options); + + CommandLine cl = parser.parse(new String[] { + "--num", "-42" + }); + Number num = (Number) cl.getValue(numOpt); + assertEquals("Wrong option value", -42, num.intValue()); + } +} Propchange: commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: commons/proper/cli/trunk/src/test/org/apache/commons/cli2/bug/BugCLI150Test.java ------------------------------------------------------------------------------ svn:mime-type = text/plain