/*
The MIT License
Copyright (c) 2004-2015 Paul R. Holser, Jr.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package joptsimple;
import java.io.
IOException;
import java.io.
OutputStream;
import java.io.
OutputStreamWriter;
import java.io.
Writer;
import java.util.*;
import joptsimple.internal.
AbbreviationMap;
import joptsimple.internal.
SimpleOptionNameMap;
import joptsimple.internal.
OptionNameMap;
import joptsimple.util.
KeyValuePair;
import static java.util.
Collections.*;
import static joptsimple.
OptionException.*;
import static joptsimple.
OptionParserState.*;
import static joptsimple.
ParserRules.*;
/**
* <p>Parses command line arguments, using a syntax that attempts to take from the best of POSIX {@code getopt()}
* and GNU {@code getopt_long()}.</p>
*
* <p>This parser supports short options and long options.</p>
*
* <ul>
* <li><dfn>Short options</dfn> begin with a single hyphen ("{@code -}") followed by a single letter or digit,
* or question mark ("{@code ?}"), or dot ("{@code .}"), or underscore ("{@code _}").</li>
*
* <li>Short options can accept single arguments. The argument can be made required or optional. The option's
* argument can occur:
* <ul>
* <li>in the slot after the option, as in {@code -d /tmp}</li>
* <li>right up against the option, as in {@code -d/tmp}</li>
* <li>right up against the option separated by an equals sign ({@code "="}), as in {@code -d=/tmp}</li>
* </ul>
* To specify <em>n</em> arguments for an option, specify the option <em>n</em> times, once for each argument,
* as in {@code -d /tmp -d /var -d /opt}; or, when using the
* {@linkplain ArgumentAcceptingOptionSpec#withValuesSeparatedBy(char) "separated values"} clause of the "fluent
* interface" (see below), give multiple values separated by a given character as a single argument to the
* option.</li>
*
* <li>Short options can be clustered, so that {@code -abc} is treated as {@code -a -b -c}. If a short option
* in the cluster can accept an argument, the remaining characters are interpreted as the argument for that
* option.</li>
*
* <li>An argument consisting only of two hyphens ({@code "--"}) signals that the remaining arguments are to be
* treated as non-options.</li>
*
* <li>An argument consisting only of a single hyphen is considered a non-option argument (though it can be an
* argument of an option). Many Unix programs treat single hyphens as stand-ins for the standard input or standard
* output streams.</li>
*
* <li><dfn>Long options</dfn> begin with two hyphens ({@code "--"}), followed by multiple letters, digits,
* hyphens, question marks, or dots. A hyphen cannot be the first character of a long option specification when
* configuring the parser.</li>
*
* <li>You can abbreviate long options, so long as the abbreviation is unique. Suppress this behavior if
* you wish using {@linkplain OptionParser#OptionParser(boolean) this constructor}.</li>
*
* <li>Long options can accept single arguments. The argument can be made required or optional. The option's
* argument can occur:
* <ul>
* <li>in the slot after the option, as in {@code --directory /tmp}</li>
* <li>right up against the option separated by an equals sign ({@code "="}), as in
* {@code --directory=/tmp}
* </ul>
* Specify multiple arguments for a long option in the same manner as for short options (see above).</li>
*
* <li>You can use a single hyphen ({@code "-"}) instead of a double hyphen ({@code "--"}) for a long
* option.</li>
*
* <li>The option {@code -W} is reserved. If you tell the parser to {@linkplain
* #recognizeAlternativeLongOptions(boolean) recognize alternative long options}, then it will treat, for example,
* {@code -W foo=bar} as the long option {@code foo} with argument {@code bar}, as though you had written
* {@code --foo=bar}.</li>
*
* <li>You can specify {@code -W} as a valid short option, or use it as an abbreviation for a long option, but
* {@linkplain #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will always supersede
* this behavior.</li>
*
* <li>You can specify a given short or long option multiple times on a single command line. The parser collects
* any arguments specified for those options as a list.</li>
*
* <li>If the parser detects an option whose argument is optional, and the next argument "looks like" an option,
* that argument is not treated as the argument to the option, but as a potentially valid option. If, on the other
* hand, the optional argument is typed as a derivative of {@link Number}, then that argument is treated as the
* negative number argument of the option, even if the parser recognizes the corresponding numeric option.
* For example:
* <pre><code>
* OptionParser parser = new OptionParser();
* parser.accepts( "a" ).withOptionalArg().ofType( Integer.class );
* parser.accepts( "2" );
* OptionSet options = parser.parse( "-a", "-2" );
* </code></pre>
* In this case, the option set contains {@code "a"} with argument {@code -2}, not both {@code "a"} and
* {@code "2"}. Swapping the elements in the <em>args</em> array gives the latter.</li>
* </ul>
*
* <p>There are two ways to tell the parser what options to recognize:</p>
*
* <ol>
* <li>A "fluent interface"-style API for specifying options, available since version 2. Sentences in this fluent
* interface language begin with a call to {@link #accepts(String) accepts} or {@link #acceptsAll(List)
* acceptsAll} methods; calls on the ensuing chain of objects describe whether the options can take an argument,
* whether the argument is required or optional, to what type arguments of the options should be converted if any,
* etc. Since version 3, these calls return an instance of {@link OptionSpec}, which can subsequently be used to
* retrieve the arguments of the associated option in a type-safe manner.</li>
*
* <li>Since version 1, a more concise way of specifying short options has been to use the special {@linkplain
* #OptionParser(String) constructor}. Arguments of options specified in this manner will be of type {@link String}.
* Here are the rules for the format of the specification strings this constructor accepts:
*
* <ul>
* <li>Any letter or digit is treated as an option character.</li>
*
* <li>An option character can be immediately followed by an asterisk ({@code *)} to indicate that
* the option is a "help" option.</li>
*
* <li>If an option character (with possible trailing asterisk) is followed by a single colon ({@code ":"}),
* then the option requires an argument.</li>
*
* <li>If an option character (with possible trailing asterisk) is followed by two colons ({@code "::"}),
* then the option accepts an optional argument.</li>
*
* <li>Otherwise, the option character accepts no argument.</li>
*
* <li>If the option specification string begins with a plus sign ({@code "+" }), the parser will behave
* "POSIX-ly correct".</li>
*
* <li>If the option specification string contains the sequence {@code "W;"} (capital W followed by a
* semicolon), the parser will recognize the alternative form of long options.</li>
* </ul>
* </li>
* </ol>
*
* <p>Each of the options in a list of options given to {@link #acceptsAll(List) acceptsAll} is treated as a
* synonym of the others. For example:</p>
* <pre>
* <code>
* OptionParser parser = new OptionParser();
* parser.acceptsAll( asList( "w", "interactive", "confirmation" ) );
* OptionSet options = parser.parse( "-w" );
* </code>
* </pre>
* <p>In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer {@code true} when given arguments
* {@code "w"}, {@code "interactive"}, and {@code "confirmation"}. The {@link OptionSet} would give the same
* responses to these arguments for its other methods as well.</p>
*
* <p>By default, as with GNU {@code getopt()}, the parser allows intermixing of options and non-options. If, however,
* the parser has been created to be "POSIX-ly correct", then the first argument that does not look lexically like an
* option, and is not a required argument of a preceding option, signals the end of options. You can still bind
* optional arguments to their options using the abutting (for short options) or {@code =} syntax.</p>
*
* <p>Unlike GNU {@code getopt()}, this parser does not honor the environment variable {@code POSIXLY_CORRECT}.
* "POSIX-ly correct" parsers are configured by either:</p>
*
* <ol>
* <li>using the method {@link #posixlyCorrect(boolean)}, or</li>
*
* <li>using the {@linkplain #OptionParser(String) constructor} with an argument whose first character is a plus sign
* ({@code "+"})</li>
* </ol>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @see <a href="http://www.gnu.org/software/libc/manual">The GNU C Library</a>
*/
public class
OptionParser implements
OptionDeclarer {
private final
OptionNameMap<
AbstractOptionSpec<?>>
recognizedOptions;
private final
ArrayList<
AbstractOptionSpec<?>>
trainingOrder;
private final
Map<
List<
String>,
Set<
OptionSpec<?>>>
requiredIf;
private final
Map<
List<
String>,
Set<
OptionSpec<?>>>
requiredUnless;
private final
Map<
List<
String>,
Set<
OptionSpec<?>>>
availableIf;
private final
Map<
List<
String>,
Set<
OptionSpec<?>>>
availableUnless;
private
OptionParserState state;
private boolean
posixlyCorrect;
private boolean
allowsUnrecognizedOptions;
private
HelpFormatter helpFormatter = new
BuiltinHelpFormatter();
/**
* Creates an option parser that initially recognizes no options, and does not exhibit "POSIX-ly correct"
* behavior.
*/
public
OptionParser() {
this(true);
}
/**
* Creates an option parser that initially recognizes no options, and does not exhibit "POSIX-ly correct"
* behavior.
*
* @param allowAbbreviations whether unambiguous abbreviations of long options should be recognized
* by the parser
*/
public
OptionParser( boolean
allowAbbreviations ) {
trainingOrder = new
ArrayList<>();
requiredIf = new
HashMap<>();
requiredUnless = new
HashMap<>();
availableIf = new
HashMap<>();
availableUnless = new
HashMap<>();
state =
moreOptions( false );
recognizedOptions =
allowAbbreviations
? new
AbbreviationMap<
AbstractOptionSpec<?>>()
: new
SimpleOptionNameMap<
AbstractOptionSpec<?>>();
recognize( new
NonOptionArgumentSpec<
String>() );
}
/**
* Creates an option parser and configures it to recognize the short options specified in the given string.
*
* Arguments of options specified this way will be of type {@link String}.
*
* @param optionSpecification an option specification
* @throws NullPointerException if {@code optionSpecification} is {@code null}
* @throws OptionException if the option specification contains illegal characters or otherwise cannot be
* recognized
*/
public
OptionParser(
String optionSpecification ) {
this();
new
OptionSpecTokenizer(
optionSpecification ).
configure( this );
}
public
OptionSpecBuilder accepts(
String option ) {
return
acceptsAll(
singletonList(
option ) );
}
public
OptionSpecBuilder accepts(
String option,
String description ) {
return
acceptsAll(
singletonList(
option ),
description );
}
public
OptionSpecBuilder acceptsAll(
List<
String>
options ) {
return
acceptsAll(
options, "" );
}
public
OptionSpecBuilder acceptsAll(
List<
String>
options,
String description ) {
if (
options.
isEmpty() )
throw new
IllegalArgumentException( "need at least one option" );
ensureLegalOptions(
options );
return new
OptionSpecBuilder( this,
options,
description );
}
public
NonOptionArgumentSpec<
String>
nonOptions() {
NonOptionArgumentSpec<
String>
spec = new
NonOptionArgumentSpec<>();
recognize(
spec );
return
spec;
}
public
NonOptionArgumentSpec<
String>
nonOptions(
String description ) {
NonOptionArgumentSpec<
String>
spec = new
NonOptionArgumentSpec<>(
description );
recognize(
spec );
return
spec;
}
public void
posixlyCorrect( boolean
setting ) {
posixlyCorrect =
setting;
state =
moreOptions(
setting );
}
boolean
posixlyCorrect() {
return
posixlyCorrect;
}
public void
allowsUnrecognizedOptions() {
allowsUnrecognizedOptions = true;
}
boolean
doesAllowsUnrecognizedOptions() {
return
allowsUnrecognizedOptions;
}
public void
recognizeAlternativeLongOptions( boolean
recognize ) {
if (
recognize )
recognize( new
AlternativeLongOptionSpec() );
else
recognizedOptions.
remove(
String.
valueOf(
RESERVED_FOR_EXTENSIONS ) );
}
void
recognize(
AbstractOptionSpec<?>
spec ) {
recognizedOptions.
putAll(
spec.
options(),
spec );
trainingOrder.
add(
spec );
}
/**
* Writes information about the options this parser recognizes to the given output sink.
*
* The output sink is flushed, but not closed.
*
* @param sink the sink to write information to
* @throws IOException if there is a problem writing to the sink
* @throws NullPointerException if {@code sink} is {@code null}
* @see #printHelpOn(Writer)
*/
public void
printHelpOn(
OutputStream sink ) throws
IOException {
printHelpOn( new
OutputStreamWriter(
sink ) );
}
/**
* Writes information about the options this parser recognizes to the given output sink.
*
* The output sink is flushed, but not closed.
*
* @param sink the sink to write information to
* @throws IOException if there is a problem writing to the sink
* @throws NullPointerException if {@code sink} is {@code null}
* @see #printHelpOn(OutputStream)
*/
public void
printHelpOn(
Writer sink ) throws
IOException {
sink.
write(
helpFormatter.
format(
_recognizedOptions() ) );
sink.
flush();
}
/**
* Tells the parser to use the given formatter when asked to {@linkplain #printHelpOn(java.io.Writer) print help}.
*
* @param formatter the formatter to use for printing help
* @throws NullPointerException if the formatter is {@code null}
*/
public void
formatHelpWith(
HelpFormatter formatter ) {
if (
formatter == null )
throw new
NullPointerException();
helpFormatter =
formatter;
}
/**
* Retrieves all options-spec pairings which have been configured for the parser in the same order as declared
* during training. Option flags for specs are alphabetized by {@link OptionSpec#options()}; only the order of the
* specs is preserved.
*
* (Note: prior to 4.7 the order was alphabetical across all options regardless of spec.)
*
* @return a map containing all the configured options and their corresponding {@link OptionSpec}
* @since 4.6
*/
public
Map<
String,
OptionSpec<?>>
recognizedOptions() {
return new
LinkedHashMap<
String,
OptionSpec<?>>(
_recognizedOptions() );
}
private
Map<
String,
AbstractOptionSpec<?>>
_recognizedOptions() {
Map<
String,
AbstractOptionSpec<?>>
options = new
LinkedHashMap<>();
for (
AbstractOptionSpec<?>
spec :
trainingOrder ) {
for (
String option :
spec.
options() )
options.
put(
option,
spec );
}
return
options;
}
/**
* Parses the given command line arguments according to the option specifications given to the parser.
*
* @param arguments arguments to parse
* @return an {@link OptionSet} describing the parsed options, their arguments, and any non-option arguments found
* @throws OptionException if problems are detected while parsing
* @throws NullPointerException if the argument list is {@code null}
*/
public
OptionSet parse(
String...
arguments ) {
ArgumentList argumentList = new
ArgumentList(
arguments );
OptionSet detected = new
OptionSet(
recognizedOptions.
toJavaUtilMap() );
detected.
add(
recognizedOptions.
get(
NonOptionArgumentSpec.
NAME ) );
while (
argumentList.
hasMore() )
state.
handleArgument( this,
argumentList,
detected );
reset();
ensureRequiredOptions(
detected );
ensureAllowedOptions(
detected );
return
detected;
}
/**
* Mandates mutual exclusiveness for the options built by the specified builders.
*
* @param specs descriptors for options that should be mutually exclusive on a command line.
* @throws NullPointerException if {@code specs} is {@code null}
*/
public void
mutuallyExclusive(
OptionSpecBuilder...
specs ) {
for ( int
i = 0;
i <
specs.length;
i++ ) {
for ( int
j = 0;
j <
specs.length;
j++ ) {
if (
i !=
j )
specs[
i].
availableUnless(
specs[
j] );
}
}
}
private void
ensureRequiredOptions(
OptionSet options ) {
List<
AbstractOptionSpec<?>>
missingRequiredOptions =
missingRequiredOptions(
options);
boolean
helpOptionPresent =
isHelpOptionPresent(
options );
if ( !
missingRequiredOptions.
isEmpty() && !
helpOptionPresent )
throw new
MissingRequiredOptionsException(
missingRequiredOptions );
}
private void
ensureAllowedOptions(
OptionSet options ) {
List<
AbstractOptionSpec<?>>
forbiddenOptions =
unavailableOptions(
options );
boolean
helpOptionPresent =
isHelpOptionPresent(
options );
if ( !
forbiddenOptions.
isEmpty() && !
helpOptionPresent )
throw new
UnavailableOptionException(
forbiddenOptions );
}
private
List<
AbstractOptionSpec<?>>
missingRequiredOptions(
OptionSet options ) {
List<
AbstractOptionSpec<?>>
missingRequiredOptions = new
ArrayList<>();
for (
AbstractOptionSpec<?>
each :
recognizedOptions.
toJavaUtilMap().
values() ) {
if (
each.
isRequired() && !
options.
has(
each ) )
missingRequiredOptions.
add(
each);
}
for (
Map.
Entry<
List<
String>,
Set<
OptionSpec<?>>>
each :
requiredIf.
entrySet() ) {
AbstractOptionSpec<?>
required =
specFor(
each.
getKey().
iterator().
next() );
if (
optionsHasAnyOf(
options,
each.
getValue() ) && !
options.
has(
required ) )
missingRequiredOptions.
add(
required );
}
for (
Map.
Entry<
List<
String>,
Set<
OptionSpec<?>>>
each :
requiredUnless.
entrySet() ) {
AbstractOptionSpec<?>
required =
specFor(
each.
getKey().
iterator().
next());
if ( !
optionsHasAnyOf(
options,
each.
getValue() ) && !
options.
has(
required ) )
missingRequiredOptions.
add(
required );
}
return
missingRequiredOptions;
}
private
List<
AbstractOptionSpec<?>>
unavailableOptions(
OptionSet options) {
List<
AbstractOptionSpec<?>>
unavailableOptions = new
ArrayList<>();
for (
Map.
Entry<
List<
String>,
Set<
OptionSpec<?>>>
eachEntry :
availableIf.
entrySet() ) {
AbstractOptionSpec<?>
forbidden =
specFor(
eachEntry.
getKey().
iterator().
next() );
if ( !
optionsHasAnyOf(
options,
eachEntry.
getValue() ) &&
options.
has(
forbidden ) ) {
unavailableOptions.
add(
forbidden);
}
}
for (
Map.
Entry<
List<
String>,
Set<
OptionSpec<?>>>
eachEntry :
availableUnless.
entrySet() ) {
AbstractOptionSpec<?>
forbidden =
specFor(
eachEntry.
getKey().
iterator().
next() );
if (
optionsHasAnyOf(
options,
eachEntry.
getValue() ) &&
options.
has(
forbidden ) ) {
unavailableOptions.
add(
forbidden);
}
}
return
unavailableOptions;
}
private boolean
optionsHasAnyOf(
OptionSet options,
Collection<
OptionSpec<?>>
specs ) {
for (
OptionSpec<?>
each :
specs ) {
if (
options.
has(
each ) )
return true;
}
return false;
}
private boolean
isHelpOptionPresent(
OptionSet options ) {
boolean
helpOptionPresent = false;
for (
AbstractOptionSpec<?>
each :
recognizedOptions.
toJavaUtilMap().
values() ) {
if (
each.
isForHelp() &&
options.
has(
each ) ) {
helpOptionPresent = true;
break;
}
}
return
helpOptionPresent;
}
void
handleLongOptionToken(
String candidate,
ArgumentList arguments,
OptionSet detected ) {
KeyValuePair optionAndArgument =
parseLongOptionWithArgument(
candidate );
if ( !
isRecognized(
optionAndArgument.
key ) )
throw
unrecognizedOption(
optionAndArgument.
key );
AbstractOptionSpec<?>
optionSpec =
specFor(
optionAndArgument.
key );
optionSpec.
handleOption( this,
arguments,
detected,
optionAndArgument.
value );
}
void
handleShortOptionToken(
String candidate,
ArgumentList arguments,
OptionSet detected ) {
KeyValuePair optionAndArgument =
parseShortOptionWithArgument(
candidate );
if (
isRecognized(
optionAndArgument.
key ) ) {
specFor(
optionAndArgument.
key ).
handleOption( this,
arguments,
detected,
optionAndArgument.
value );
}
else
handleShortOptionCluster(
candidate,
arguments,
detected );
}
private void
handleShortOptionCluster(
String candidate,
ArgumentList arguments,
OptionSet detected ) {
char[]
options =
extractShortOptionsFrom(
candidate );
validateOptionCharacters(
options );
for ( int
i = 0;
i <
options.length;
i++ ) {
AbstractOptionSpec<?>
optionSpec =
specFor(
options[
i ] );
if (
optionSpec.
acceptsArguments() &&
options.length >
i + 1 ) {
String detectedArgument =
String.
valueOf(
options,
i + 1,
options.length - 1 -
i );
optionSpec.
handleOption( this,
arguments,
detected,
detectedArgument );
break;
}
optionSpec.
handleOption( this,
arguments,
detected, null );
}
}
void
handleNonOptionArgument(
String candidate,
ArgumentList arguments,
OptionSet detectedOptions ) {
specFor(
NonOptionArgumentSpec.
NAME ).
handleOption( this,
arguments,
detectedOptions,
candidate );
}
void
noMoreOptions() {
state =
OptionParserState.
noMoreOptions();
}
boolean
looksLikeAnOption(
String argument ) {
return
isShortOptionToken(
argument ) ||
isLongOptionToken(
argument );
}
boolean
isRecognized(
String option ) {
return
recognizedOptions.
contains(
option );
}
void
requiredIf(
List<
String>
precedentSynonyms,
String required ) {
requiredIf(
precedentSynonyms,
specFor(
required ) );
}
void
requiredIf(
List<
String>
precedentSynonyms,
OptionSpec<?>
required ) {
putDependentOption(
precedentSynonyms,
required,
requiredIf );
}
void
requiredUnless(
List<
String>
precedentSynonyms,
String required ) {
requiredUnless(
precedentSynonyms,
specFor(
required ) );
}
void
requiredUnless(
List<
String>
precedentSynonyms,
OptionSpec<?>
required ) {
putDependentOption(
precedentSynonyms,
required,
requiredUnless );
}
void
availableIf(
List<
String>
precedentSynonyms,
String available ) {
availableIf(
precedentSynonyms,
specFor(
available ) );
}
void
availableIf(
List<
String>
precedentSynonyms,
OptionSpec<?>
available) {
putDependentOption(
precedentSynonyms,
available,
availableIf );
}
void
availableUnless(
List<
String>
precedentSynonyms,
String available ) {
availableUnless(
precedentSynonyms,
specFor(
available ) );
}
void
availableUnless(
List<
String>
precedentSynonyms,
OptionSpec<?>
available ) {
putDependentOption(
precedentSynonyms,
available,
availableUnless );
}
private void
putDependentOption(
List<
String>
precedentSynonyms,
OptionSpec<?>
required,
Map<
List<
String>,
Set<
OptionSpec<?>>>
target ) {
for (
String each :
precedentSynonyms ) {
AbstractOptionSpec<?>
spec =
specFor(
each );
if (
spec == null )
throw new
UnconfiguredOptionException(
precedentSynonyms );
}
Set<
OptionSpec<?>>
associated =
target.
get(
precedentSynonyms );
if (
associated == null ) {
associated = new
HashSet<>();
target.
put(
precedentSynonyms,
associated );
}
associated.
add(
required );
}
private
AbstractOptionSpec<?>
specFor( char
option ) {
return
specFor(
String.
valueOf(
option ) );
}
private
AbstractOptionSpec<?>
specFor(
String option ) {
return
recognizedOptions.
get(
option );
}
private void
reset() {
state =
moreOptions(
posixlyCorrect );
}
private static char[]
extractShortOptionsFrom(
String argument ) {
char[]
options = new char[
argument.
length() - 1 ];
argument.
getChars( 1,
argument.
length(),
options, 0 );
return
options;
}
private void
validateOptionCharacters( char[]
options ) {
for ( char
each :
options ) {
String option =
String.
valueOf(
each );
if ( !
isRecognized(
option ) )
throw
unrecognizedOption(
option );
if (
specFor(
option ).
acceptsArguments() )
return;
}
}
private static
KeyValuePair parseLongOptionWithArgument(
String argument ) {
return
KeyValuePair.
valueOf(
argument.
substring( 2 ) );
}
private static
KeyValuePair parseShortOptionWithArgument(
String argument ) {
return
KeyValuePair.
valueOf(
argument.
substring( 1 ) );
}
}