http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e2f9d5ed/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
new file mode 100644
index 0000000..615f097
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
@@ -0,0 +1,3900 @@
+/*
+ * 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.logging.log4j.core.tools.picocli;
+
+import java.awt.Point;
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.sql.Time;
+import java.text.BreakIterator;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi;
+import 
org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.IStyle;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Style;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text;
+
+import static java.util.Locale.ENGLISH;
+import static 
org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.SPAN;
+import static 
org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
+import static 
org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.WRAP;
+
+/**
+ * <p>
+ * CommandLine interpreter that uses reflection to initialize an annotated 
domain object with values obtained from the
+ * command line arguments.
+ * </p><h2>Example</h2>
+ * <pre>import static picocli.CommandLine.*;
+ *
+ * &#064;Command(header = "Encrypt FILE(s), or standard input, to standard 
output or to the output file.")
+ * public class Encrypt {
+ *
+ *     &#064;Parameters(type = File.class, description = "Any number of input 
files")
+ *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
+ *
+ *     &#064;Option(names = { "-o", "--out" }, description = "Output file 
(default: print to console)")
+ *     private File outputFile;
+ *
+ *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbosely 
list files processed")
+ *     private boolean verbose;
+ *
+ *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, help = true, 
description = "Display this help and exit")
+ *     private boolean help;
+ * }
+ * </pre>
+ * <p>
+ * Use {@code CommandLine} to initialize a domain object as follows:
+ * </p><pre>
+ * public static void main(String... args) {
+ *     try {
+ *         Encrypt encrypt = CommandLine.populateCommand(new Encrypt(), args);
+ *         if (encrypt.help) {
+ *             CommandLine.usage(encrypt, System.out);
+ *         } else {
+ *             runProgram(encrypt);
+ *         }
+ *     } catch (ParameterException ex) { // command line arguments could not 
be parsed
+ *         System.err.println(ex.getMessage());
+ *         CommandLine.usage(new Encrypt(), System.err);
+ *     }
+ * }
+ * </pre><p>
+ * Invoke the above program with some command line arguments. The below are 
all equivalent:
+ * </p>
+ * <pre>
+ * --verbose --out=outfile in1 in2
+ * --verbose --out outfile in1 in2
+ * -v --out=outfile in1 in2
+ * -v -o outfile in1 in2
+ * -v -o=outfile in1 in2
+ * -vo outfile in1 in2
+ * -vo=outfile in1 in2
+ * -v -ooutfile in1 in2
+ * -vooutfile in1 in2
+ * </pre>
+ *
+ * <p>
+ * Copied and modified from <a 
href="http://github.com/remkop/picocli/";>picocli</a>.
+ * </p>
+ *
+ * @since 2.9
+ */
+public class CommandLine {
+    /** This is picocli version {@value}. */
+    public static final String VERSION = "0.9.8";
+
+    private final Interpreter interpreter;
+    private boolean overwrittenOptionsAllowed = false;
+    private boolean unmatchedArgumentsAllowed = false;
+    private List<String> unmatchedArguments = new ArrayList<String>();
+    private CommandLine parent;
+    private boolean usageHelpRequested;
+    private boolean versionHelpRequested;
+    private List<String> versionLines = new ArrayList<String>();
+
+    /**
+     * Constructs a new {@code CommandLine} interpreter with the specified 
annotated object.
+     * When the {@link #parse(String...)} method is called, fields of the 
specified object that are annotated
+     * with {@code @Option} or {@code @Parameters} will be initialized based 
on command line arguments.
+     * @param command the object to initialize from the command line arguments
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public CommandLine(Object command) {
+        interpreter = new Interpreter(command);
+    }
+
+    /** Registers a subcommand with the specified name. For example:
+     * <pre>
+     * CommandLine commandLine = new CommandLine(new Git())
+     *         .addSubcommand("status",   new GitStatus())
+     *         .addSubcommand("commit",   new GitCommit();
+     *         .addSubcommand("add",      new GitAdd())
+     *         .addSubcommand("branch",   new GitBranch())
+     *         .addSubcommand("checkout", new GitCheckout())
+     *         //...
+     *         ;
+     * </pre>
+     *
+     * <p>The specified object can be an annotated object or a
+     * {@code CommandLine} instance with its own nested subcommands. For 
example:</p>
+     * <pre>
+     * CommandLine commandLine = new CommandLine(new MainCommand())
+     *         .addSubcommand("cmd1",                 new ChildCommand1()) // 
subcommand
+     *         .addSubcommand("cmd2",                 new ChildCommand2())
+     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // 
subcommand with nested sub-subcommands
+     *                 .addSubcommand("cmd3sub1",                 new 
GrandChild3Command1())
+     *                 .addSubcommand("cmd3sub2",                 new 
GrandChild3Command2())
+     *                 .addSubcommand("cmd3sub3", new CommandLine(new 
GrandChild3Command3()) // deeper nesting
+     *                         .addSubcommand("cmd3sub3sub1", new 
GreatGrandChild3Command3_1())
+     *                         .addSubcommand("cmd3sub3sub2", new 
GreatGrandChild3Command3_2())
+     *                 )
+     *         );
+     * </pre>
+     * <p>The default type converters are available on all subcommands and 
nested sub-subcommands, but custom type
+     * converters are registered only with the subcommand hierarchy as it 
existed when the custom type was registered.
+     * To ensure a custom type converter is available to all subcommands, 
register the type converter last, after
+     * adding subcommands.</p>
+     *
+     * @param name the string to recognize on the command line as a subcommand
+     * @param command the object to initialize with command line arguments 
following the subcommand name.
+     *          This may be a {@code CommandLine} instance with its own 
(nested) subcommands
+     * @return this CommandLine object, to allow method chaining
+     * @see #registerConverter(Class, ITypeConverter)
+     * @since 0.9.7
+     */
+    public CommandLine addSubcommand(String name, Object command) {
+        CommandLine commandLine = toCommandLine(command);
+        commandLine.parent = this;
+        interpreter.commands.put(name, commandLine);
+        return this;
+    }
+    /** Returns a map with the subcommands {@linkplain #addSubcommand(String, 
Object) registered} on this instance.
+     * @return a map with the registered subcommands
+     * @since 0.9.7
+     */
+    public Map<String, CommandLine> getSubcommands() {
+        return new LinkedHashMap<String, CommandLine>(interpreter.commands);
+    }
+    /**
+     * Returns the command that this is a subcommand of, or {@code null} if 
this is a top-level command.
+     * @return the command that this is a subcommand of, or {@code null} if 
this is a top-level command
+     * @see #addSubcommand(String, Object)
+     * @see Command#subcommands()
+     * @since 0.9.8
+     */
+    public CommandLine getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the annotated object that this {@code CommandLine} instance was 
constructed with.
+     * @return the annotated object that this {@code CommandLine} instance was 
constructed with
+     * @since 0.9.7
+     */
+    public Object getCommand() {
+        return interpreter.command;
+    }
+
+    /** Returns {@code true} if an option annotated with {@link 
Option#usageHelp()} was specified on the command line.
+     * @return whether the parser encountered an option annotated with {@link 
Option#usageHelp()}  */
+    public boolean isUsageHelpRequested() { return usageHelpRequested; }
+
+    /** Returns {@code true} if an option annotated with {@link 
Option#versionHelp()} was specified on the command line.
+     * @return whether the parser encountered an option annotated with {@link 
Option#versionHelp()}  */
+    public boolean isVersionHelpRequested() { return versionHelpRequested; }
+
+    /** Returns whether options for single-value fields can be specified 
multiple times on the command line.
+     * The default is {@code false} and a {@link OverwrittenOptionException} 
is thrown if this happens.
+     * When {@code true}, the last specified value is retained.
+     * @return {@code true} if options for single-value fields can be 
specified multiple times on the command line, {@code false} otherwise
+     * @since 0.9.7
+     */
+    public boolean isOverwrittenOptionsAllowed() {
+        return overwrittenOptionsAllowed;
+    }
+
+    /** Sets whether options for single-value fields can be specified multiple 
times on the command line without a {@link OverwrittenOptionException} being 
thrown.
+     * <p>The specified setting will be registered with this {@code 
CommandLine} and the full hierarchy of its
+     * subcommands and nested sub-subcommands <em>at the moment this method is 
called</em>. Subcommands added
+     * later will have the default setting. To ensure a setting is applied to 
all
+     * subcommands, call the setter last, after adding subcommands.</p>
+     * @param newValue the new setting
+     * @return this {@code CommandLine} object, to allow method chaining
+     * @since 0.9.7
+     */
+    public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
+        this.overwrittenOptionsAllowed = newValue;
+        for (CommandLine command : interpreter.commands.values()) {
+            command.setOverwrittenOptionsAllowed(newValue);
+        }
+        return this;
+    }
+
+    /** Returns whether the end user may specify arguments on the command line 
that are not matched to any option or parameter fields.
+     * The default is {@code false} and a {@link UnmatchedArgumentException} 
is thrown if this happens.
+     * When {@code true}, the last unmatched arguments are available via the 
{@link #getUnmatchedArguments()} method.
+     * @return {@code true} if the end use may specify unmatched arguments on 
the command line, {@code false} otherwise
+     * @see #getUnmatchedArguments()
+     * @since 0.9.7
+     */
+    public boolean isUnmatchedArgumentsAllowed() {
+        return unmatchedArgumentsAllowed;
+    }
+
+    /** Sets whether the end user may specify unmatched arguments on the 
command line without a {@link UnmatchedArgumentException} being thrown.
+     * <p>The specified setting will be registered with this {@code 
CommandLine} and the full hierarchy of its
+     * subcommands and nested sub-subcommands <em>at the moment this method is 
called</em>. Subcommands added
+     * later will have the default setting. To ensure a setting is applied to 
all
+     * subcommands, call the setter last, after adding subcommands.</p>
+     * @param newValue the new setting
+     * @return this {@code CommandLine} object, to allow method chaining
+     * @since 0.9.7
+     */
+    public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) {
+        this.unmatchedArgumentsAllowed = newValue;
+        for (CommandLine command : interpreter.commands.values()) {
+            command.setUnmatchedArgumentsAllowed(newValue);
+        }
+        return this;
+    }
+
+    /** Returns the list of unmatched command line arguments, if any.
+     * @return the list of unmatched command line arguments or an empty list
+     * @see #isUnmatchedArgumentsAllowed()
+     * @since 0.9.7
+     */
+    public List<String> getUnmatchedArguments() {
+        return unmatchedArguments;
+    }
+
+    /**
+     * <p>
+     * Convenience method that initializes the specified annotated object from 
the specified command line arguments.
+     * </p><p>
+     * This is equivalent to
+     * </p><pre>
+     * CommandLine cli = new CommandLine(command);
+     * cli.parse(args);
+     * return command;
+     * </pre>
+     *
+     * @param command the object to initialize. This object contains fields 
annotated with
+     *          {@code @Option} or {@code @Parameters}.
+     * @param args the command line arguments to parse
+     * @param <T> the type of the annotated object
+     * @return the specified annotated object
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     * @throws ParameterException if the specified command line arguments are 
invalid
+     * @since 0.9.7
+     */
+    public static <T> T populateCommand(T command, String... args) {
+        CommandLine cli = toCommandLine(command);
+        cli.parse(args);
+        return command;
+    }
+
+    /**
+     * <p>
+     * Initializes the annotated object that this {@code CommandLine} was 
constructed with as well as
+     * possibly any registered commands, based on the specified command line 
arguments,
+     * and returns a list of all commands and subcommands that were 
initialized by this method.
+     * </p>
+     *
+     * @param args the command line arguments to parse
+     * @return a list with all commands and subcommands initialized by this 
method
+     * @throws ParameterException if the specified command line arguments are 
invalid
+     */
+    public List<CommandLine> parse(String... args) {
+        return interpreter.parse(args);
+    }
+
+    /**
+     * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link 
#usage(PrintStream)} for details.
+     * @param command the object annotated with {@link Command}, {@link 
Option} and {@link Parameters}
+     * @param out the print stream to print the help message to
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public static void usage(Object command, PrintStream out) {
+        toCommandLine(command).usage(out);
+    }
+
+    /**
+     * Equivalent to {@code new CommandLine(command).usage(out, ansi)}.
+     * See {@link #usage(PrintStream, Help.Ansi)} for details.
+     * @param command the object annotated with {@link Command}, {@link 
Option} and {@link Parameters}
+     * @param out the print stream to print the help message to
+     * @param ansi whether the usage message should contain ANSI escape codes 
or not
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public static void usage(Object command, PrintStream out, Help.Ansi ansi) {
+        toCommandLine(command).usage(out, ansi);
+    }
+
+    /**
+     * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}.
+     * See {@link #usage(PrintStream, Help.ColorScheme)} for details.
+     * @param command the object annotated with {@link Command}, {@link 
Option} and {@link Parameters}
+     * @param out the print stream to print the help message to
+     * @param colorScheme the {@code ColorScheme} defining the styles for 
options, parameters and commands when ANSI is enabled
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public static void usage(Object command, PrintStream out, Help.ColorScheme 
colorScheme) {
+        toCommandLine(command).usage(out, colorScheme);
+    }
+
+    /**
+     * Delegates to {@link #usage(PrintStream, Help.Ansi)} with the 
{@linkplain Help.Ansi#AUTO platform default}.
+     * @param out the printStream to print to
+     * @see #usage(PrintStream, Help.ColorScheme)
+     */
+    public void usage(PrintStream out) {
+        usage(out, Help.Ansi.AUTO);
+    }
+
+    /**
+     * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the 
{@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color 
scheme}.
+     * @param out the printStream to print to
+     * @param ansi whether the usage message should include ANSI escape codes 
or not
+     * @see #usage(PrintStream, Help.ColorScheme)
+     */
+    public void usage(PrintStream out, Help.Ansi ansi) {
+        usage(out, Help.defaultColorScheme(ansi));
+    }
+    /**
+     * Prints a usage help message for the annotated command class to the 
specified {@code PrintStream}.
+     * Delegates construction of the usage help message to the {@link Help} 
inner class and is equivalent to:
+     * <pre>
+     * Help help = new Help(command).addAllSubcommands(getSubcommands());
+     * StringBuilder sb = new StringBuilder()
+     *         .append(help.headerHeading())
+     *         .append(help.header())
+     *         .append(help.synopsisHeading())      //e.g. Usage:
+     *         .append(help.synopsis())             //e.g. &lt;main class&gt; 
[OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
+     *         .append(help.descriptionHeading())   //e.g. %nDescription:%n%n
+     *         .append(help.description())          //e.g. {"Converts foos to 
bars.", "Use options to control conversion mode."}
+     *         .append(help.parameterListHeading()) //e.g. %nPositional 
parameters:%n%n
+     *         .append(help.parameterList())        //e.g. [FILE...] the files 
to convert
+     *         .append(help.optionListHeading())    //e.g. %nOptions:%n%n
+     *         .append(help.optionList())           //e.g. -h, --help   
displays this help and exits
+     *         .append(help.commandListHeading())   //e.g. %nCommands:%n%n
+     *         .append(help.commandList())          //e.g.    add       adds 
the frup to the frooble
+     *         .append(help.footerHeading())
+     *         .append(help.footer());
+     * out.print(sb);
+     * </pre>
+     * <p>Annotate your class with {@link Command} to control many aspects of 
the usage help message, including
+     * the program name, text of section headings and section contents, and 
some aspects of the auto-generated sections
+     * of the usage help message.
+     * <p>To customize the auto-generated sections of the usage help message, 
like how option details are displayed,
+     * instantiate a {@link Help} object and use a {@link Help.TextTable} with 
more of fewer columns, a custom
+     * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain 
Help.IOptionRenderer renderer}
+     * for ultimate control over which aspects of an Option or Field are 
displayed where.</p>
+     * @param out the {@code PrintStream} to print the usage help message to
+     * @param colorScheme the {@code ColorScheme} defining the styles for 
options, parameters and commands when ANSI is enabled
+     */
+    public void usage(PrintStream out, Help.ColorScheme colorScheme) {
+        Help help = new Help(interpreter.command, 
colorScheme).addAllSubcommands(getSubcommands());
+        StringBuilder sb = new StringBuilder()
+                .append(help.headerHeading())
+                .append(help.header())
+                .append(help.synopsisHeading())      //e.g. Usage:
+                .append(help.synopsis(help.synopsisHeadingLength())) //e.g. 
&lt;main class&gt; [OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
+                .append(help.descriptionHeading())   //e.g. %nDescription:%n%n
+                .append(help.description())          //e.g. {"Converts foos to 
bars.", "Use options to control conversion mode."}
+                .append(help.parameterListHeading()) //e.g. %nPositional 
parameters:%n%n
+                .append(help.parameterList())        //e.g. [FILE...] the 
files to convert
+                .append(help.optionListHeading())    //e.g. %nOptions:%n%n
+                .append(help.optionList())           //e.g. -h, --help   
displays this help and exits
+                .append(help.commandListHeading())   //e.g. %nCommands:%n%n
+                .append(help.commandList())          //e.g.    add       adds 
the frup to the frooble
+                .append(help.footerHeading())
+                .append(help.footer());
+        out.print(sb);
+    }
+
+    /**
+     * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the 
{@linkplain Help.Ansi#AUTO platform default}.
+     * @param out the printStream to print to
+     * @see #printVersionHelp(PrintStream, Help.Ansi)
+     */
+    public void printVersionHelp(PrintStream out) { printVersionHelp(out, 
Help.Ansi.AUTO); }
+
+    /**
+     * Prints version information from the {@link Command#version()} 
annotation to the specified {@code PrintStream}.
+     * Each element of the array of version strings is printed on a separate 
line. Version strings may contain
+     * <a 
href="http://picocli.info/#_usage_help_with_styles_and_colors";>markup for 
colors and style</a>.
+     * @param out the printStream to print to
+     * @param ansi whether the usage message should include ANSI escape codes 
or not
+     * @see Command#version()
+     * @see Option#versionHelp()
+     * @see #isVersionHelpRequested()
+     */
+    public void printVersionHelp(PrintStream out, Help.Ansi ansi) {
+        for (String versionInfo : versionLines) {
+            out.println(ansi.new Text(versionInfo));
+        }
+    }
+
+    /**
+     * Delegates to {@link #run(Runnable, PrintStream, Help.Ansi, String...)} 
with {@link Help.Ansi#AUTO}.
+     * @param command the command to run when {@linkplain 
#populateCommand(Object, String...) parsing} succeeds.
+     * @param out the printStream to print to
+     * @param args the command line arguments to parse
+     * @param <R> the annotated object must implement Runnable
+     * @see #run(Runnable, PrintStream, Help.Ansi, String...)
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public static <R extends Runnable> void run(R command, PrintStream out, 
String... args) {
+        run(command, out, Help.Ansi.AUTO, args);
+    }
+    /**
+     * Convenience method to allow command line application authors to avoid 
some boilerplate code in their application.
+     * The annotated object needs to implement {@link Runnable}. Calling this 
method is equivalent to:
+     * <pre>
+     * CommandLine cmd = new CommandLine(command);
+     * try {
+     *     cmd.parse(args);
+     * } catch (Exception ex) {
+     *     System.err.println(ex.getMessage());
+     *     cmd.usage(out, ansi);
+     *     return;
+     * }
+     * command.run();
+     * </pre>
+     * Note that this method is not suitable for commands with subcommands.
+     * @param command the command to run when {@linkplain 
#populateCommand(Object, String...) parsing} succeeds.
+     * @param out the printStream to print to
+     * @param ansi whether the usage message should include ANSI escape codes 
or not
+     * @param args the command line arguments to parse
+     * @param <R> the annotated object must implement Runnable
+     * @throws IllegalArgumentException if the specified command object does 
not have a {@link Command}, {@link Option} or {@link Parameters} annotation
+     */
+    public static <R extends Runnable> void run(R command, PrintStream out, 
Help.Ansi ansi, String... args) {
+        CommandLine cmd = new CommandLine(command); // validate command 
outside of try-catch
+        try {
+            cmd.parse(args);
+        } catch (Exception ex) {
+            out.println(ex.getMessage());
+            cmd.usage(out, ansi);
+            return;
+        }
+        command.run();
+    }
+
+    /**
+     * Registers the specified type converter for the specified class. When 
initializing fields annotated with
+     * {@link Option}, the field's type is used as a lookup key to find the 
associated type converter, and this
+     * type converter converts the original command line argument string value 
to the correct type.
+     * <p>
+     * Java 8 lambdas make it easy to register custom type converters:
+     * </p>
+     * <pre>
+     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; 
java.nio.file.Paths.get(s));
+     * commandLine.registerConverter(java.time.Duration.class, s -&gt; 
java.time.Duration.parse(s));</pre>
+     * <p>
+     * Built-in type converters are pre-registered for the following java 1.5 
types:
+     * </p>
+     * <ul>
+     *   <li>all primitive types</li>
+     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, 
Float, Integer, Long, Short</li>
+     *   <li>any enum</li>
+     *   <li>java.io.File</li>
+     *   <li>java.math.BigDecimal</li>
+     *   <li>java.math.BigInteger</li>
+     *   <li>java.net.InetAddress</li>
+     *   <li>java.net.URI</li>
+     *   <li>java.net.URL</li>
+     *   <li>java.nio.charset.Charset</li>
+     *   <li>java.sql.Time</li>
+     *   <li>java.util.Date</li>
+     *   <li>java.util.UUID</li>
+     *   <li>java.util.regex.Pattern</li>
+     *   <li>StringBuilder</li>
+     *   <li>CharSequence</li>
+     *   <li>String</li>
+     * </ul>
+     * <p>The specified converter will be registered with this {@code 
CommandLine} and the full hierarchy of its
+     * subcommands and nested sub-subcommands <em>at the moment the converter 
is registered</em>. Subcommands added
+     * later will not have this converter added automatically. To ensure a 
custom type converter is available to all
+     * subcommands, register the type converter last, after adding 
subcommands.</p>
+     *
+     * @param cls the target class to convert parameter string values to
+     * @param converter the class capable of converting string values to the 
specified target type
+     * @param <K> the target type
+     * @return this CommandLine object, to allow method chaining
+     * @see #addSubcommand(String, Object)
+     */
+    public <K> CommandLine registerConverter(Class<K> cls, ITypeConverter<K> 
converter) {
+        interpreter.converterRegistry.put(Assert.notNull(cls, "class"), 
Assert.notNull(converter, "converter"));
+        for (CommandLine command : interpreter.commands.values()) {
+            command.registerConverter(cls, converter);
+        }
+        return this;
+    }
+
+    /** Returns the String that separates option names from option values when 
parsing command line options. {@code '='} by default.
+     * @return the String the parser uses to separate option names from option 
values */
+    public String getSeparator() {
+        return interpreter.separator;
+    }
+
+    /** Sets the String the parser uses to separate option names from option 
values to the specified value.
+     * @param separator the String that separates option names from option 
values */
+    public void setSeparator(String separator) {
+        interpreter.separator = Assert.notNull(separator, "separator");
+    }
+    private static boolean empty(String str) { return str == null || 
str.trim().length() == 0; }
+    private static boolean empty(Object[] array) { return array == null || 
array.length == 0; }
+    private static boolean empty(Text txt) { return txt == null || 
txt.plain.toString().trim().length() == 0; }
+    private static String str(String[] arr, int i) { return (arr == null || 
arr.length == 0) ? "" : arr[i]; }
+    private static boolean isBoolean(Class<?> type) { return type == 
Boolean.class || type == Boolean.TYPE; }
+    private static CommandLine toCommandLine(Object obj) { return obj 
instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj);}
+    /**
+     * <p>
+     * Annotate fields in your class with {@code @Option} and picocli will 
initialize these fields when matching
+     * arguments are specified on the command line.
+     * </p><p>
+     * For example:
+     * </p>
+     * <pre>import static picocli.CommandLine.*;
+     *
+     * public class MyClass {
+     *     &#064;Parameters(type = File.class, description = "Any number of 
input files")
+     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
+     *
+     *     &#064;Option(names = { "-o", "--out" }, description = "Output file 
(default: print to console)")
+     *     private File outputFile;
+     *
+     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbosely 
list files processed")
+     *     private boolean verbose;
+     *
+     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, help = true, 
description = "Display this help and exit")
+     *     private boolean help;
+     *
+     *     &#064;Option(names = { "-V", "--version"}, help = true, description 
= "Display version information and exit")
+     *     private boolean version;
+     * }
+     * </pre>
+     * <p>
+     * A field cannot be annotated with both {@code @Parameters} and {@code 
@Option} or a
+     * {@code ParameterException} is thrown.
+     * </p>
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface Option {
+        /**
+         * One or more option names. At least one option name is required.
+         * <p>
+         * Different environments have different conventions for naming 
options, but usually options have a prefix
+         * that sets them apart from parameters.
+         * Picocli supports all of the below styles. The default separator is 
{@code '='}, but this can be configured.
+         * </p><p>
+         * <b>*nix</b>
+         * </p><p>
+         * In Unix and Linux, options have a short (single-character) name, a 
long name or both.
+         * Short options
+         * (<a 
href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02";>POSIX
+         * style</a> are single-character and are preceded by the {@code '-'} 
character, e.g., {@code `-v'}.
+         * <a 
href="https://www.gnu.org/software/tar/manual/html_node/Long-Options.html";>GNU-style</a>
 long
+         * (or <em>mnemonic</em>) options start with two dashes in a row, 
e.g., {@code `--file'}.
+         * </p><p>Picocli supports the POSIX convention that short options can 
be grouped, with the last option
+         * optionally taking a parameter, which may be attached to the option 
name or separated by a space or
+         * a {@code '='} character. The below examples are all equivalent:
+         * </p><pre>
+         * -xvfFILE
+         * -xvf FILE
+         * -xvf=FILE
+         * -xv --file FILE
+         * -xv --file=FILE
+         * -x -v --file FILE
+         * -x -v --file=FILE
+         * </pre><p>
+         * <b>DOS</b>
+         * </p><p>
+         * DOS options mostly have upper case single-character names and start 
with a single slash {@code '/'} character.
+         * Option parameters are separated by a {@code ':'} character. Options 
cannot be grouped together but
+         * must be specified separately. For example:
+         * </p><pre>
+         * DIR /S /A:D /T:C
+         * </pre><p>
+         * <b>PowerShell</b>
+         * </p><p>
+         * Windows PowerShell options generally are a word preceded by a 
single {@code '-'} character, e.g., {@code `-Help'}.
+         * Option parameters are separated by a space or by a {@code ':'} 
character.
+         * </p>
+         * @return one or more option names
+         */
+        String[] names();
+
+        /**
+         * Indicates whether this option is required. By default this is false.
+         * If an option is required, but a user invokes the program without 
specifying the required option,
+         * a {@link MissingParameterException} is thrown from the {@link 
#parse(String...)} method.
+         * @return whether this option is required
+         */
+        boolean required() default false;
+
+        /**
+         * Set {@code help=true} if this option should disable validation of 
the remaining arguments:
+         * If the {@code help} option is specified, no error message is 
generated for missing required options.
+         * <p>
+         * This attribute is useful for special options like help ({@code -h} 
and {@code --help} on unix,
+         * {@code -?} and {@code -Help} on Windows) or version ({@code -V} and 
{@code --version} on unix,
+         * {@code -Version} on Windows).
+         * </p>
+         * <p>
+         * Note that the {@link #parse(String...)} method will not print help 
documentation. It will only set
+         * the value of the annotated field. It is the responsibility of the 
caller to inspect the annotated fields
+         * and take the appropriate action.
+         * </p>
+         * @return whether this option disables validation of the other 
arguments
+         */
+        boolean help() default false;
+
+        /**
+         * Set {@code usageHelp=true} if this option allows the user to 
request usage help. If this option is
+         * specified on the command line, picocli will not validate the 
remaining arguments (so no "missing required
+         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} 
method will return {@code true}.
+         * <p>
+         * This attribute is useful for special options like help ({@code -h} 
and {@code --help} on unix,
+         * {@code -?} and {@code -Help} on Windows).
+         * </p>
+         * <p>
+         * Note that the {@link #parse(String...)} method will not print usage 
help documentation. It will only set
+         * the value of the annotated field. It is the responsibility of the 
caller to inspect the annotated fields
+         * and take the appropriate action.
+         * </p>
+         * @return whether this option allows the user to request usage help
+         */
+        boolean usageHelp() default false;
+
+        /**
+         * Set {@code versionHelp=true} if this option allows the user to 
request version information. If this option is
+         * specified on the command line, picocli will not validate the 
remaining arguments (so no "missing required
+         * option" errors) and the {@link 
CommandLine#isVersionHelpRequested()} method will return {@code true}.
+         * <p>
+         * This attribute is useful for special options like version ({@code 
-V} and {@code --version} on unix,
+         * {@code -Version} on Windows).
+         * </p>
+         * <p>
+         * Note that the {@link #parse(String...)} method will not print 
version information. It will only set
+         * the value of the annotated field. It is the responsibility of the 
caller to inspect the annotated fields
+         * and take the appropriate action.
+         * </p>
+         * @return whether this option allows the user to request version 
information
+         */
+        boolean versionHelp() default false;
+
+        /**
+         * Description of this option, used when generating the usage 
documentation.
+         * @return the description of this option
+         */
+        String[] description() default {};
+
+        /**
+         * Specifies the minimum number of required parameters and the maximum 
number of accepted parameters.
+         * If an option declares a positive arity, and the user specifies an 
insufficient number of parameters on the
+         * command line, a {@link MissingParameterException} is thrown by the 
{@link #parse(String...)} method.
+         * <p>
+         * In many cases picocli can deduce the number of required parameters 
from the field's type.
+         * By default, flags (boolean options) have arity zero,
+         * and single-valued type fields (String, int, Integer, double, 
Double, File, Date, etc) have arity one.
+         * Generally, fields with types that cannot hold multiple values can 
omit the {@code arity} attribute.
+         * </p><p>
+         * Fields used to capture options with arity two or higher should have 
a type that can hold multiple values,
+         * like arrays or Collections. See {@link #type()} for strongly-typed 
Collection fields.
+         * </p><p>
+         * For example, if an option has 2 required parameters and any number 
of optional parameters,
+         * specify {@code @Option(names = "-example", arity = "2..*")}.
+         * </p>
+         * <b>A note on boolean options</b>
+         * <p>
+         * By default picocli does not expect boolean options (also called 
"flags" or "switches") to have a parameter.
+         * You can make a boolean option take a required parameter by 
annotating your field with {@code arity="1"}.
+         * For example: </p>
+         * <pre>&#064;Option(names = "-v", arity = "1") boolean verbose;</pre>
+         * <p>
+         * Because this boolean field is defined with arity 1, the user must 
specify either {@code <program> -v false}
+         * or {@code <program> -v true}
+         * on the command line, or a {@link MissingParameterException} is 
thrown by the {@link #parse(String...)}
+         * method.
+         * </p><p>
+         * To make the boolean parameter possible but optional, define the 
field with {@code arity = "0..1"}.
+         * For example: </p>
+         * <pre>&#064;Option(names="-v", arity="0..1") boolean verbose;</pre>
+         * <p>This will accept any of the below without throwing an 
exception:</p>
+         * <pre>
+         * -v
+         * -v true
+         * -v false
+         * </pre>
+         * @return how many arguments this option requires
+         */
+        String arity() default "";
+
+        /**
+         * Specify a {@code paramLabel} for the option parameter to be used in 
the usage help message. If omitted,
+         * picocli uses the field name in fish brackets ({@code '<'} and 
{@code '>'}) by default. Example:
+         * <pre>class Example {
+         *     &#064;Option(names = {"-o", "--output"}, paramLabel="FILE", 
description="path of the output file")
+         *     private File out;
+         *     &#064;Option(names = {"-j", "--jobs"}, arity="0..1", 
description="Allow N jobs at once; infinite jobs with no arg.")
+         *     private int maxJobs = -1;
+         * }</pre>
+         * <p>By default, the above gives a usage help message like the 
following:</p><pre>
+         * Usage: &lt;main class&gt; [OPTIONS]
+         * -o, --output FILE       path of the output file
+         * -j, --jobs [&lt;maxJobs&gt;]  Allow N jobs at once; infinite jobs 
with no arg.
+         * </pre>
+         * @return name of the option parameter used in the usage help message
+         */
+        String paramLabel() default "";
+
+        /**
+         * <p>
+         * Specify a {@code type} if the annotated field is a {@code 
Collection} that should hold objects other than Strings.
+         * </p><p>
+         * If the field's type is a {@code Collection}, the generic type 
parameter of the collection is erased and
+         * cannot be determined at runtime. Specify a {@code type} attribute 
to store values other than String in
+         * the Collection. Picocli will use the {@link ITypeConverter}
+         * that is {@linkplain #registerConverter(Class, ITypeConverter) 
registered} for that type to convert
+         * the raw String values before they are added to the collection.
+         * </p><p>
+         * When the field's type is an array, the {@code type} attribute is 
ignored: the values will be converted
+         * to the array component type and the array will be replaced with a 
new instance containing both the old and
+         * the new values. </p>
+         * @return the type to convert the raw String values to before adding 
them to the Collection
+         */
+        Class<?> type() default String.class;
+
+        /**
+         * Specify a regular expression to use to split option parameter 
values before applying them to the field.
+         * All elements resulting from the split are added to the array or 
Collection. Ignored for single-value fields.
+         * @return a regular expression to split option parameter values or 
{@code ""} if the value should not be split
+         * @see String#split(String)
+         */
+        String split() default "";
+
+        /**
+         * Set {@code hidden=true} if this option should not be included in 
the usage documentation.
+         * @return whether this option should be excluded from the usage 
message
+         */
+        boolean hidden() default false;
+    }
+    /**
+     * <p>
+     * Fields annotated with {@code @Parameters} will be initialized with 
positional parameters. By specifying the
+     * {@link #index()} attribute you can pick which (or what range) of the 
positional parameters to apply. If no index
+     * is specified, the field will get all positional parameters (so it 
should be an array or a collection).
+     * </p><p>
+     * When parsing the command line arguments, picocli first tries to match 
arguments to {@link Option Options}.
+     * Positional parameters are the arguments that follow the options, or the 
arguments that follow a "--" (double
+     * dash) argument on the command line.
+     * </p><p>
+     * For example:
+     * </p>
+     * <pre>import static picocli.CommandLine.*;
+     *
+     * public class MyCalcParameters {
+     *     &#064;Parameters(type = BigDecimal.class, description = "Any number 
of input numbers")
+     *     private List&lt;BigDecimal&gt; files = new 
ArrayList&lt;BigDecimal&gt;();
+     *
+     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, help = true, 
description = "Display this help and exit")
+     *     private boolean help;
+     * }
+     * </pre><p>
+     * A field cannot be annotated with both {@code @Parameters} and {@code 
@Option} or a {@code ParameterException}
+     * is thrown.</p>
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface Parameters {
+        /** Specify an index ("0", or "1", etc.) to pick which of the command 
line arguments should be assigned to this
+         * field. For array or Collection fields, you can also specify an 
index range ("0..3", or "2..*", etc.) to assign
+         * a subset of the command line arguments to this field. The default 
is "*", meaning all command line arguments.
+         * @return an index or range specifying which of the command line 
arguments should be assigned to this field
+         */
+        String index() default "*";
+
+        /** Description of the parameter(s), used when generating the usage 
documentation.
+         * @return the description of the parameter(s)
+         */
+        String[] description() default {};
+
+        /**
+         * Specifies the minimum number of required parameters and the maximum 
number of accepted parameters. If a
+         * positive arity is declared, and the user specifies an insufficient 
number of parameters on the command line,
+         * {@link MissingParameterException} is thrown by the {@link 
#parse(String...)} method.
+         * <p>The default depends on the type of the parameter: booleans 
require no parameters, arrays and Collections
+         * accept zero to any number of parameters, and any other type accepts 
one parameter.</p>
+         * @return the range of minimum and maximum parameters accepted by 
this command
+         */
+        String arity() default "";
+
+        /**
+         * Specify a {@code paramLabel} for the parameter to be used in the 
usage help message. If omitted,
+         * picocli uses the field name in fish brackets ({@code '<'} and 
{@code '>'}) by default. Example:
+         * <pre>class Example {
+         *     &#064;Parameters(paramLabel="FILE", description="path of the 
input FILE(s)")
+         *     private File[] inputFiles;
+         * }</pre>
+         * <p>By default, the above gives a usage help message like the 
following:</p><pre>
+         * Usage: &lt;main class&gt; [FILE...]
+         * [FILE...]       path of the input FILE(s)
+         * </pre>
+         * @return name of the positional parameter used in the usage help 
message
+         */
+        String paramLabel() default "";
+
+        /**
+         * <p>
+         * Specify a {@code type} if the annotated field is a {@code 
Collection} that should hold objects other than Strings.
+         * </p><p>
+         * If the field's type is a {@code Collection}, the generic type 
parameter of the collection is erased and
+         * cannot be determined at runtime. Specify a {@code type} attribute 
to store values other than String in
+         * the Collection. Picocli will use the {@link ITypeConverter}
+         * that is {@linkplain #registerConverter(Class, ITypeConverter) 
registered} for that type to convert
+         * the raw String values before they are added to the collection.
+         * </p><p>
+         * When the field's type is an array, the {@code type} attribute is 
ignored: the values will be converted
+         * to the array component type and the array will be replaced with a 
new instance containing both the old and
+         * the new values. </p>
+         * @return the type to convert the raw String values to before adding 
them to the Collection
+         */
+        Class<?> type() default String.class;
+
+        /**
+         * Specify a regular expression to use to split positional parameter 
values before applying them to the field.
+         * All elements resulting from the split are added to the array or 
Collection. Ignored for single-value fields.
+         * @return a regular expression to split operand values or {@code ""} 
if the value should not be split
+         * @see String#split(String)
+         */
+        String split() default "";
+
+        /**
+         * Set {@code hidden=true} if this parameter should not be included in 
the usage message.
+         * @return whether this parameter should be excluded from the usage 
message
+         */
+        boolean hidden() default false;
+    }
+
+    /**
+     * <p>Annotate your class with {@code @Command} when you want more control 
over the format of the generated help
+     * message.
+     * </p><pre>
+     * &#064;Command(name      = "Encrypt",
+     *        description = "Encrypt FILE(s), or standard input, to standard 
output or to the output file.",
+     *        footer      = "Copyright (c) 2017")
+     * public class Encrypt {
+     *     &#064;Parameters(paramLabel = "FILE", type = File.class, 
description = "Any number of input files")
+     *     private List&lt;File&gt; files     = new ArrayList&lt;File&gt;();
+     *
+     *     &#064;Option(names = { "-o", "--out" }, description = "Output file 
(default: print to console)")
+     *     private File outputFile;
+     * }</pre>
+     * <p>
+     * The structure of a help message looks like this:
+     * </p><ul>
+     *   <li>[header]</li>
+     *   <li>[synopsis]: {@code Usage: <commandName> [OPTIONS] [FILE...]}</li>
+     *   <li>[description]</li>
+     *   <li>[parameter list]: {@code      [FILE...]   Any number of input 
files}</li>
+     *   <li>[option list]: {@code   -h, --help   prints this help message and 
exits}</li>
+     *   <li>[footer]</li>
+     * </ul> */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface Command {
+        /** Program name to show in the synopsis. If omitted, {@code "<main 
class>"} is used.
+         * For {@linkplain #subcommands() declaratively added} subcommands, 
this attribute is also used
+         * by the parser to recognize subcommands in the command line 
arguments.
+         * @return the program name to show in the synopsis
+         * @see Help#commandName */
+        String name() default "<main class>";
+
+        /** A list of classes to instantiate and register as subcommands. When 
registering subcommands declaratively
+         * like this, you don't need to call the {@link 
CommandLine#addSubcommand(String, Object)} method. For example, this:
+         * <pre>
+         * &#064;Command(subcommands = {
+         *         GitStatus.class,
+         *         GitCommit.class,
+         *         GitBranch.class })
+         * public class Git { ... }
+         *
+         * CommandLine commandLine = new CommandLine(new Git());
+         * </pre> is equivalent to this:
+         * <pre>
+         * // alternative: programmatically add subcommands.
+         * // NOTE: in this case there should be no `subcommands` attribute on 
the @Command annotation.
+         * &#064;Command public class Git { ... }
+         *
+         * CommandLine commandLine = new CommandLine(new Git())
+         *         .addSubcommand("status",   new GitStatus())
+         *         .addSubcommand("commit",   new GitCommit())
+         *         .addSubcommand("branch",   new GitBranch());
+         * </pre>
+         * @return the declaratively registered subcommands of this command, 
or an empty array if none
+         * @see CommandLine#addSubcommand(String, Object)
+         * @since 0.9.8
+         */
+        Class<?>[] subcommands() default {};
+
+        /** String that separates options from option parameters. Default is 
{@code "="}. Spaces are also accepted.
+         * @return the string that separates options from option parameters, 
used both when parsing and when generating usage help
+         * @see Help#separator
+         * @see CommandLine#setSeparator(String) */
+        String separator() default "=";
+
+        /** Version information for this command, to print to the console when 
the user specifies an
+         * {@linkplain Option#versionHelp() option} to request version help. 
This is not part of the usage help message.
+         *
+         * @return a string or an array of strings with version information 
about this command.
+         * @since 0.9.8
+         * @see CommandLine#printVersionHelp(PrintStream)
+         */
+        String[] version() default {};
+
+        /** Set the heading preceding the header section. May contain embedded 
{@linkplain java.util.Formatter format specifiers}.
+         * @return the heading preceding the header section
+         * @see Help#headerHeading(Object...)  */
+        String headerHeading() default "";
+
+        /** Optional summary description of the command, shown before the 
synopsis.
+         * @return summary description of the command
+         * @see Help#header
+         * @see Help#header(Object...)  */
+        String[] header() default {};
+
+        /** Set the heading preceding the synopsis text. May contain embedded
+         * {@linkplain java.util.Formatter format specifiers}. The default 
heading is {@code "Usage: "} (without a line
+         * break between the heading and the synopsis text).
+         * @return the heading preceding the synopsis text
+         * @see Help#synopsisHeading(Object...)  */
+        String synopsisHeading() default "Usage: ";
+
+        /** Specify {@code true} to generate an abbreviated synopsis like 
{@code "<main> [OPTIONS] [PARAMETERS...]"}.
+         * By default, a detailed synopsis with individual option names and 
parameters is generated.
+         * @return whether the synopsis should be abbreviated
+         * @see Help#abbreviateSynopsis
+         * @see Help#abbreviatedSynopsis()
+         * @see Help#detailedSynopsis(Comparator, boolean) */
+        boolean abbreviateSynopsis() default false;
+
+        /** Specify one or more custom synopsis lines to display instead of an 
auto-generated synopsis.
+         * @return custom synopsis text to replace the auto-generated synopsis
+         * @see Help#customSynopsis
+         * @see Help#customSynopsis(Object...) */
+        String[] customSynopsis() default {};
+
+        /** Set the heading preceding the description section. May contain 
embedded {@linkplain java.util.Formatter format specifiers}.
+         * @return the heading preceding the description section
+         * @see Help#descriptionHeading(Object...)  */
+        String descriptionHeading() default "";
+
+        /** Optional text to display between the synopsis line(s) and the list 
of options.
+         * @return description of this command
+         * @see Help#description
+         * @see Help#description(Object...) */
+        String[] description() default {};
+
+        /** Set the heading preceding the parameters list. May contain 
embedded {@linkplain java.util.Formatter format specifiers}.
+         * @return the heading preceding the parameters list
+         * @see Help#parameterListHeading(Object...)  */
+        String parameterListHeading() default "";
+
+        /** Set the heading preceding the options list. May contain embedded 
{@linkplain java.util.Formatter format specifiers}.
+         * @return the heading preceding the options list
+         * @see Help#optionListHeading(Object...)  */
+        String optionListHeading() default "";
+
+        /** Specify {@code false} to show Options in declaration order. The 
default is to sort alphabetically.
+         * @return whether options should be shown in alphabetic order.
+         * @see Help#sortOptions */
+        boolean sortOptions() default true;
+
+        /** Prefix required options with this character in the options list. 
The default is no marker: the synopsis
+         * indicates which options and parameters are required.
+         * @return the character to show in the options list to mark required 
options
+         * @see Help#requiredOptionMarker */
+        char requiredOptionMarker() default ' ';
+
+        /** Specify {@code true} to show default values in the description 
column of the options list (except for
+         * boolean options). False by default.
+         * @return whether the default values for options and parameters 
should be shown in the description column
+         * @see Help#showDefaultValues */
+        boolean showDefaultValues() default false;
+
+        /** Set the heading preceding the subcommands list. May contain 
embedded {@linkplain java.util.Formatter format specifiers}.
+         * The default heading is {@code "Commands:%n"} (with a line break at 
the end).
+         * @return the heading preceding the subcommands list
+         * @see Help#commandListHeading(Object...)  */
+        String commandListHeading() default "Commands:%n";
+
+        /** Set the heading preceding the footer section. May contain embedded 
{@linkplain java.util.Formatter format specifiers}.
+         * @return the heading preceding the footer section
+         * @see Help#footerHeading(Object...)  */
+        String footerHeading() default "";
+
+        /** Optional text to display after the list of options.
+         * @return text to display after the list of options
+         * @see Help#footer
+         * @see Help#footer(Object...) */
+        String[] footer() default {};
+    }
+    /**
+     * <p>
+     * When parsing command line arguments and initializing
+     * fields annotated with {@link Option @Option} or {@link Parameters 
@Parameters},
+     * String values can be converted to any type for which a {@code 
ITypeConverter} is registered.
+     * </p><p>
+     * This interface defines the contract for classes that know how to 
convert a String into some domain object.
+     * Custom converters can be registered with the {@link 
#registerConverter(Class, ITypeConverter)} method.
+     * </p><p>
+     * Java 8 lambdas make it easy to register custom type converters:
+     * </p>
+     * <pre>
+     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; 
java.nio.file.Paths.get(s));
+     * commandLine.registerConverter(java.time.Duration.class, s -&gt; 
java.time.Duration.parse(s));</pre>
+     * <p>
+     * Built-in type converters are pre-registered for the following java 1.5 
types:
+     * </p>
+     * <ul>
+     *   <li>all primitive types</li>
+     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, 
Float, Integer, Long, Short</li>
+     *   <li>any enum</li>
+     *   <li>java.io.File</li>
+     *   <li>java.math.BigDecimal</li>
+     *   <li>java.math.BigInteger</li>
+     *   <li>java.net.InetAddress</li>
+     *   <li>java.net.URI</li>
+     *   <li>java.net.URL</li>
+     *   <li>java.nio.charset.Charset</li>
+     *   <li>java.sql.Time</li>
+     *   <li>java.util.Date</li>
+     *   <li>java.util.UUID</li>
+     *   <li>java.util.regex.Pattern</li>
+     *   <li>StringBuilder</li>
+     *   <li>CharSequence</li>
+     *   <li>String</li>
+     * </ul>
+     * @param <K> the type of the object that is the result of the conversion
+     */
+    public interface ITypeConverter<K> {
+        /**
+         * Converts the specified command line argument value to some domain 
object.
+         * @param value the command line argument String value
+         * @return the resulting domain object
+         * @throws Exception an exception detailing what went wrong during the 
conversion
+         */
+        K convert(String value) throws Exception;
+    }
+    /** Describes the number of parameters required and accepted by an option 
or a positional parameter.
+     * @since 0.9.7
+     */
+    public static class Range implements Comparable<Range> {
+        /** Required number of parameters for an option or positional 
parameter. */
+        public final int min;
+        /** Maximum accepted number of parameters for an option or positional 
parameter. */
+        public final int max;
+        public final boolean isVariable;
+        private final boolean isUnspecified;
+        private final String originalValue;
+
+        /** Constructs a new Range object with the specified parameters.
+         * @param min minimum number of required parameters
+         * @param max maximum number of allowed parameters (or 
Integer.MAX_VALUE if variable)
+         * @param variable {@code true} if any number or parameters is 
allowed, {@code false} otherwise
+         * @param unspecified {@code true} if no arity was specified on the 
option/parameter (value is based on type)
+         * @param originalValue the original value that was specified on the 
option or parameter
+         */
+        public Range(int min, int max, boolean variable, boolean unspecified, 
String originalValue) {
+            this.min = min;
+            this.max = max;
+            this.isVariable = variable;
+            this.isUnspecified = unspecified;
+            this.originalValue = originalValue;
+        }
+        /** Returns a new {@code Range} based on the {@link Option#arity()} 
annotation on the specified field,
+         * or the field type's default arity if no arity was specified.
+         * @param field the field whose Option annotation to inspect
+         * @return a new {@code Range} based on the Option arity annotation on 
the specified field */
+        public static Range optionArity(Field field) {
+            return field.isAnnotationPresent(Option.class)
+                    ? 
adjustForType(Range.valueOf(field.getAnnotation(Option.class).arity()), field)
+                    : new Range(0, 0, false, true, "0");
+        }
+        /** Returns a new {@code Range} based on the {@link 
Parameters#arity()} annotation on the specified field,
+         * or the field type's default arity if no arity was specified.
+         * @param field the field whose Parameters annotation to inspect
+         * @return a new {@code Range} based on the Parameters arity 
annotation on the specified field */
+        public static Range parameterArity(Field field) {
+            return field.isAnnotationPresent(Parameters.class)
+                    ? 
adjustForType(Range.valueOf(field.getAnnotation(Parameters.class).arity()), 
field)
+                    : new Range(0, 0, false, true, "0");
+        }
+        /** Returns a new {@code Range} based on the {@link 
Parameters#index()} annotation on the specified field.
+         * @param field the field whose Parameters annotation to inspect
+         * @return a new {@code Range} based on the Parameters index 
annotation on the specified field */
+        public static Range parameterIndex(Field field) {
+            return field.isAnnotationPresent(Parameters.class)
+                    ? 
Range.valueOf(field.getAnnotation(Parameters.class).index())
+                    : new Range(0, 0, false, true, "0");
+        }
+        static Range adjustForType(Range result, Field field) {
+            return result.isUnspecified ? defaultArity(field.getType()) : 
result;
+        }
+        /** Returns a new {@code Range} based on the specified type: booleans 
have arity 0, arrays or Collections have
+         * arity "0..*", and other types have arity 1.
+         * @param type the type whose default arity to return
+         * @return a new {@code Range} indicating the default arity of the 
specified type */
+        public static Range defaultArity(Class<?> type) {
+            if (isBoolean(type)) {
+                return Range.valueOf("0");
+            } else if (type.isArray() || 
Collection.class.isAssignableFrom(type)) {
+                return Range.valueOf("0..*");
+            }
+            return Range.valueOf("1");// for single-valued fields
+        }
+        /** Leniently parses the specified String as an {@code Range} value 
and return the result. A range string can
+         * be a fixed integer value or a range of the form {@code MIN_VALUE + 
".." + MAX_VALUE}. If the
+         * {@code MIN_VALUE} string is not numeric, the minimum is zero. If 
the {@code MAX_VALUE} is not numeric, the
+         * range is taken to be variable and the maximum is {@code 
Integer.MAX_VALUE}.
+         * @param range the value range string to parse
+         * @return a new {@code Range} value */
+        public static Range valueOf(String range) {
+            range = range.trim();
+            boolean unspecified = range.length() == 0 || 
range.startsWith(".."); // || range.endsWith("..");
+            int min = -1, max = -1;
+            boolean variable = false;
+            int dots = -1;
+            if ((dots = range.indexOf("..")) >= 0) {
+                min = parseInt(range.substring(0, dots), 0);
+                max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE);
+                variable = max == Integer.MAX_VALUE;
+            } else {
+                max = parseInt(range, Integer.MAX_VALUE);
+                variable = max == Integer.MAX_VALUE;
+                min = variable ? 0 : max;
+            }
+            Range result = new Range(min, max, variable, unspecified, range);
+            return result;
+        }
+        private static int parseInt(String str, int defaultValue) {
+            try {
+                return Integer.parseInt(str);
+            } catch (Exception ex) {
+                return defaultValue;
+            }
+        }
+        /** Returns a new Range object with the {@code min} value replaced by 
the specified value.
+         * The {@code max} of the returned Range is guaranteed not to be less 
than the new {@code min} value.
+         * @param newMin the {@code min} value of the returned Range object
+         * @return a new Range object with the specified {@code min} value */
+        public Range min(int newMin) { return new Range(newMin, 
Math.max(newMin, max), isVariable, isUnspecified, originalValue); }
+
+        /** Returns a new Range object with the {@code max} value replaced by 
the specified value.
+         * The {@code min} of the returned Range is guaranteed not to be 
greater than the new {@code max} value.
+         * @param newMax the {@code max} value of the returned Range object
+         * @return a new Range object with the specified {@code max} value */
+        public Range max(int newMax) { return new Range(Math.min(min, newMax), 
newMax, isVariable, isUnspecified, originalValue); }
+
+        public boolean equals(Object object) {
+            if (!(object instanceof Range)) { return false; }
+            Range other = (Range) object;
+            return other.max == this.max && other.min == this.min && 
other.isVariable == this.isVariable;
+        }
+        public int hashCode() {
+            return ((17 * 37 + max) * 37 + min) * 37 + (isVariable ? 1 : 0);
+        }
+        public String toString() {
+            return min == max ? String.valueOf(min) : min + ".." + (isVariable 
? "*" : max);
+        }
+        public int compareTo(Range other) {
+            int result = min - other.min;
+            return (result == 0) ? max - other.max : result;
+        }
+    }
+    private static void init(Class<?> cls,
+                             List<Field> requiredFields,
+                             Map<String, Field> optionName2Field,
+                             Map<Character, Field> singleCharOption2Field,
+                             List<Field> positionalParametersFields) {
+        Field[] declaredFields = cls.getDeclaredFields();
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            if (field.isAnnotationPresent(Option.class)) {
+                Option option = field.getAnnotation(Option.class);
+                if (option.required()) {
+                    requiredFields.add(field);
+                }
+                for (String name : option.names()) { // cannot be null or empty
+                    Field existing = optionName2Field.put(name, field);
+                    if (existing != null && existing != field) {
+                        throw DuplicateOptionAnnotationsException.create(name, 
field, existing);
+                    }
+                    if (name.length() == 2 && name.startsWith("-")) {
+                        char flag = name.charAt(1);
+                        Field existing2 = singleCharOption2Field.put(flag, 
field);
+                        if (existing2 != null && existing2 != field) {
+                            throw 
DuplicateOptionAnnotationsException.create(name, field, existing2);
+                        }
+                    }
+                }
+            }
+            if (field.isAnnotationPresent(Parameters.class)) {
+                if (field.isAnnotationPresent(Option.class)) {
+                    throw new ParameterException("A field can be either 
@Option or @Parameters, but '"
+                            + field.getName() + "' is both.");
+                }
+                positionalParametersFields.add(field);
+                Range arity = Range.parameterArity(field);
+                if (arity.min > 0) {
+                    requiredFields.add(field);
+                }
+            }
+        }
+    }
+    static void validatePositionalParameters(List<Field> 
positionalParametersFields) {
+        int min = 0;
+        for (Field field : positionalParametersFields) {
+            Range index = Range.parameterIndex(field);
+            if (index.min > min) {
+                throw new ParameterIndexGapException("Missing field annotated 
with @Parameter(index=" + min +
+                        "). Nearest field '" + field.getName() + "' has 
index=" + index.min);
+            }
+            min = Math.max(min, index.max);
+            min = min == Integer.MAX_VALUE ? min : min + 1;
+        }
+    }
+    private static <T> Stack<T> reverse(Stack<T> stack) {
+        Collections.reverse(stack);
+        return stack;
+    }
+    /**
+     * Helper class responsible for processing command line arguments.
+     */
+    private class Interpreter {
+        private final Map<String, CommandLine> commands                  = new 
LinkedHashMap<String, CommandLine>();
+        private final Map<Class<?>, ITypeConverter<?>> converterRegistry = new 
HashMap<Class<?>, ITypeConverter<?>>();
+        private final Map<String, Field> optionName2Field                = new 
HashMap<String, Field>();
+        private final Map<Character, Field> singleCharOption2Field       = new 
HashMap<Character, Field>();
+        private final List<Field> requiredFields                         = new 
ArrayList<Field>();
+        private final List<Field> positionalParametersFields             = new 
ArrayList<Field>();
+        private final Object command;
+        private boolean isHelpRequested;
+        private String separator = "=";
+
+        Interpreter(Object command) {
+            converterRegistry.put(Path.class,          new 
BuiltIn.PathConverter());
+            converterRegistry.put(String.class,        new 
BuiltIn.StringConverter());
+            converterRegistry.put(StringBuilder.class, new 
BuiltIn.StringBuilderConverter());
+            converterRegistry.put(CharSequence.class,  new 
BuiltIn.CharSequenceConverter());
+            converterRegistry.put(Byte.class,          new 
BuiltIn.ByteConverter());
+            converterRegistry.put(Byte.TYPE,           new 
BuiltIn.ByteConverter());
+            converterRegistry.put(Boolean.class,       new 
BuiltIn.BooleanConverter());
+            converterRegistry.put(Boolean.TYPE,        new 
BuiltIn.BooleanConverter());
+            converterRegistry.put(Character.class,     new 
BuiltIn.CharacterConverter());
+            converterRegistry.put(Character.TYPE,      new 
BuiltIn.CharacterConverter());
+            converterRegistry.put(Short.class,         new 
BuiltIn.ShortConverter());
+            converterRegistry.put(Short.TYPE,          new 
BuiltIn.ShortConverter());
+            converterRegistry.put(Integer.class,       new 
BuiltIn.IntegerConverter());
+            converterRegistry.put(Integer.TYPE,        new 
BuiltIn.IntegerConverter());
+            converterRegistry.put(Long.class,          new 
BuiltIn.LongConverter());
+            converterRegistry.put(Long.TYPE,           new 
BuiltIn.LongConverter());
+            converterRegistry.put(Float.class,         new 
BuiltIn.FloatConverter());
+            converterRegistry.put(Float.TYPE,          new 
BuiltIn.FloatConverter());
+            converterRegistry.put(Double.class,        new 
BuiltIn.DoubleConverter());
+            converterRegistry.put(Double.TYPE,         new 
BuiltIn.DoubleConverter());
+            converterRegistry.put(File.class,          new 
BuiltIn.FileConverter());
+            converterRegistry.put(URI.class,           new 
BuiltIn.URIConverter());
+            converterRegistry.put(URL.class,           new 
BuiltIn.URLConverter());
+            converterRegistry.put(Date.class,          new 
BuiltIn.ISO8601DateConverter());
+            converterRegistry.put(Time.class,          new 
BuiltIn.ISO8601TimeConverter());
+            converterRegistry.put(BigDecimal.class,    new 
BuiltIn.BigDecimalConverter());
+            converterRegistry.put(BigInteger.class,    new 
BuiltIn.BigIntegerConverter());
+            converterRegistry.put(Charset.class,       new 
BuiltIn.CharsetConverter());
+            converterRegistry.put(InetAddress.class,   new 
BuiltIn.InetAddressConverter());
+            converterRegistry.put(Pattern.class,       new 
BuiltIn.PatternConverter());
+            converterRegistry.put(UUID.class,          new 
BuiltIn.UUIDConverter());
+
+            this.command             = Assert.notNull(command, "command");
+            Class<?> cls             = command.getClass();
+            String declaredSeparator = null;
+            boolean hasCommandAnnotation = false;
+            while (cls != null) {
+                init(cls, requiredFields, optionName2Field, 
singleCharOption2Field, positionalParametersFields);
+                if (cls.isAnnotationPresent(Command.class)) {
+                    hasCommandAnnotation = true;
+                    Command cmd = cls.getAnnotation(Command.class);
+                    declaredSeparator = (declaredSeparator == null) ? 
cmd.separator() : declaredSeparator;
+                    
CommandLine.this.versionLines.addAll(Arrays.asList(cmd.version()));
+
+                    for (Class<?> sub : cmd.subcommands()) {
+                        Command subCommand = sub.getAnnotation(Command.class);
+                        if (subCommand == null || 
Help.DEFAULT_COMMAND_NAME.equals(subCommand.name())) {
+                            throw new IllegalArgumentException("Subcommand " + 
sub.getName() +
+                                    " is missing the mandatory @Command 
annotation with a 'name' attribute");
+                        }
+                        try {
+                            Constructor<?> constructor = 
sub.getDeclaredConstructor();
+                            constructor.setAccessible(true);
+                            CommandLine commandLine = 
toCommandLine(constructor.newInstance());
+                            commandLine.parent = CommandLine.this;
+                            commands.put(subCommand.name(), commandLine);
+                        }
+                        catch (IllegalArgumentException ex) { throw ex; }
+                        catch (NoSuchMethodException ex) { throw new 
IllegalArgumentException("Cannot instantiate subcommand " +
+                                sub.getName() + ": the class has no 
constructor", ex); }
+                        catch (Exception ex) {
+                            throw new IllegalStateException("Could not 
instantiate and add subcommand " +
+                                    sub.getName() + ": " + ex, ex);
+                        }
+                    }
+                }
+                cls = cls.getSuperclass();
+            }
+            separator = declaredSeparator != null ? declaredSeparator : 
separator;
+            Collections.sort(positionalParametersFields, new 
PositionalParametersSorter());
+            validatePositionalParameters(positionalParametersFields);
+
+            if (positionalParametersFields.isEmpty() && 
optionName2Field.isEmpty() && !hasCommandAnnotation) {
+                throw new IllegalArgumentException(command + " (" + 
command.getClass() +
+                        ") is not a command: it has no @Command, @Option or 
@Parameters annotations");
+            }
+        }
+
+        /**
+         * Entry point into parsing command line arguments.
+         * @param args the command line arguments
+         * @return a list with all commands and subcommands initialized by 
this method
+         * @throws ParameterException if the specified command line arguments 
are invalid
+         */
+        List<CommandLine> parse(String... args) {
+            Assert.notNull(args, "argument array");
+            Stack<String> arguments = new Stack<String>();
+            for (int i = args.length - 1; i >= 0; i--) {
+                arguments.push(args[i]);
+            }
+            List<CommandLine> result = new ArrayList<CommandLine>();
+            parse(result, arguments, args);
+            return result;
+        }
+
+        private void parse(List<CommandLine> parsedCommands, Stack<String> 
argumentStack, String[] originalArgs) {
+            // first reset any state in case this CommandLine instance is 
being reused
+            isHelpRequested = false;
+            CommandLine.this.versionHelpRequested = false;
+            CommandLine.this.usageHelpRequested = false;
+
+            parsedCommands.add(CommandLine.this);
+            List<Field> required = new ArrayList<Field>(requiredFields);
+            Set<Field> initialized = new HashSet<Field>();
+            Collections.sort(required, new PositionalParametersSorter());
+            try {
+                processArguments(parsedCommands, argumentStack, required, 
initialized, originalArgs);
+            } catch (ParameterException ex) {
+                throw ex;
+            } catch (Exception ex) {
+                int offendingArgIndex = originalArgs.length - 
argumentStack.size();
+                String arg = offendingArgIndex >= 0 && offendingArgIndex < 
originalArgs.length ? originalArgs[offendingArgIndex] : "?";
+                throw ParameterException.create(ex, arg, argumentStack.size(), 
originalArgs);
+            }
+            if (!isAnyHelpRequested() && !required.isEmpty()) {
+                if (required.get(0).isAnnotationPresent(Option.class)) {
+                    throw MissingParameterException.create(required);
+                } else {
+                    try {
+                        processPositionalParameters0(required, true, new 
Stack<String>());
+                    } catch (ParameterException ex) { throw ex;
+                    } catch (Exception ex) { throw new 
IllegalStateException("Internal error: " + ex, ex); }
+                }
+            }
+        }
+
+        private void processArguments(List<CommandLine> parsedCommands,
+                                      Stack<String> args,
+                                      Collection<Field> required,
+                                      Set<Field> initialized,
+                                      String[] originalArgs) throws Exception {
+            // arg must be one of:
+            // 1. the "--" double dash separating options from positional 
arguments
+            // 1. a stand-alone flag, like "-v" or "--verbose": no value 
required, must map to boolean or Boolean field
+            // 2. a short option followed by an argument, like "-f file" or 
"-ffile": may map to any type of field
+            // 3. a long option followed by an argument, like "-file out.txt" 
or "-file=out.txt"
+            // 3. one or more remaining arguments without any associated 
options. Must be the last in the list.
+            // 4. a combination of stand-alone options, like "-vxr". 
Equivalent to "-v -x -r", "-v true -x true -r true"
+            // 5. a combination of stand-alone options and one option with an 
argument, like "-vxrffile"
+
+            while (!args.isEmpty()) {
+                String arg = args.pop();
+
+                // Double-dash separates options from positional arguments.
+                // If found, then interpret the remaining args as positional 
parameters.
+                if ("--".equals(arg)) {
+                    processPositionalParameters(required, args);
+                    return; // we are done
+                }
+
+                // if we find another command, we are done with the current 
command
+                if (commands.containsKey(arg)) {
+                    if (!isHelpRequested && !required.isEmpty()) { // ensure 
current command portion is valid
+                        throw MissingParameterException.create(required);
+                    }
+                    commands.get(arg).interpreter.parse(parsedCommands, args, 
originalArgs);
+                    return; // remainder done by the command
+                }
+
+                // First try to interpret the argument as a single option (as 
opposed to a compact group of options).
+                // A single option may be without option parameters, like "-v" 
or "--verbose" (a boolean value),
+                // or an option may have one or more option parameters.
+                // A parameter may be attached to the option.
+                boolean paramAttachedToOption = false;
+                int separatorIndex = arg.indexOf(separator);
+                if (separatorIndex > 0) {
+                    String key = arg.substring(0, separatorIndex);
+                    // be greedy. Consume the whole arg as an option if 
possible.
+                    if (optionName2Field.containsKey(key) && 
!optionName2Field.containsKey(arg)) {
+                        paramAttachedToOption = true;
+                        String optionParam = arg.substring(separatorIndex + 
separator.length());
+                        args.push(optionParam);
+                        arg = key;
+                    }
+                }
+                if (optionName2Field.containsKey(arg)) {
+                    processStandaloneOption(required, initialized, arg, args, 
paramAttachedToOption);
+                }
+                // Compact (single-letter) options can be grouped with other 
options or with an argument.
+                // only single-letter options can be combined with other 
options or with an argument
+                else if (arg.length() > 2 && arg.startsWith("-")) {
+                    processClusteredShortOptions(required, initialized, arg, 
args);
+                }
+                // The argument could not be interpreted as an option.
+                // We take this to mean that the remainder are positional 
arguments
+                else {
+                    args.push(arg);
+                    processPositionalParameters(required, args);
+                    return;
+                }
+            }
+        }
+
+        private void processPositionalParameters(Collection<Field> required, 
Stack<String> args) throws Exception {
+            processPositionalParameters0(required, false, args);
+            if (!args.empty()) {
+                handleUnmatchedArguments(args);
+                return;
+            };
+        }
+
+        private void handleUnmatchedArguments(Stack<String> args) {
+            if (!isUnmatchedArgumentsAllowed()) { throw new 
UnmatchedArgumentException(args); }
+            while (!args.isEmpty()) { unmatchedArguments.add(args.pop()); } // 
addAll would give args in reverse order
+        }
+
+        private void processPositionalParameters0(Collection<Field> required, 
boolean validateOnly, Stack<String> args) throws Exception {
+            int max = -1;
+            for (Field positionalParam : positionalParametersFields) {
+                Range indexRange = Range.parameterIndex(positionalParam);
+                max = Math.max(max, indexRange.max);
+                @SuppressWarnings("unchecked")
+                Stack<String> argsCopy = reverse((Stack<String>) args.clone());
+                if (!indexRange.isVariable) {
+                    for (int i = argsCopy.size() - 1; i > indexRange.max; i--) 
{
+                        argsCopy.removeElementAt(i);
+                    }
+                }
+                Collections.reverse(argsCopy);
+                for (int i = 0; i < indexRange.min && !argsCopy.isEmpty(); 
i++) { argsCopy.pop(); }
+                Range arity = Range.parameterArity(positionalParam);
+                assertNoMissingParameters(positionalParam, arity.min, 
argsCopy);
+                if (!validateOnly) {
+                    applyOption(positionalParam, Parameters.class, arity, 
false, argsCopy, null);
+                    required.remove(positionalParam);
+                }
+            }
+            // remove processed args from the stack
+            if (!validateOnly && !positionalParametersFields.isEmpty()) {
+                int processedArgCount = Math.min(args.size(), max < 
Integer.MAX_VALUE ? max + 1 : Integer.MAX_VALUE);
+                for (int i = 0; i < processedArgCount; i++) { args.pop(); }
+            }
+        }
+
+        private void processStandaloneOption(Collection<Field> required,
+                                             Set<Field> initialized,
+                                             String arg,
+                                             Stack<String> args,
+                                             boolean paramAttachedToKey) 
throws Exception {
+            Field field = optionName2Field.get(arg);
+            required.remove(field);
+            Range arity = Range.optionArity(field);
+            if (paramAttachedToKey) {
+                arity = arity.min(Math.max(1, arity.min)); // if key=value, 
minimum arity is at least 1
+            }
+            applyOption(field, Option.class, arity, paramAttachedToKey, args, 
initialized);
+        }
+
+        private void processClusteredShortOptions(Collection<Field> required,
+                                                  Set<Field> initialized,
+                                                  String arg,
+                                                  Stack<String> args)
+                throws Exception {
+            String prefix = arg.substring(0, 1);
+            String cluster = arg.substring(1);
+            boolean paramAttachedToOption = true;
+            do {
+                if (cluster.length() > 0 && 
singleCharOption2Field.containsKey(cluster.charAt(0))) {
+                    Field field = 
singleCharOption2Field.get(cluster.charAt(0));
+                    required.remove(field);
+                    cluster = cluster.length() > 0 ? cluster.substring(1) : "";
+                    paramAttachedToOption = cluster.length() > 0;
+                    Range arity = Range.optionArity(field);
+                    if (cluster.startsWith(separator)) {// attached with 
separator, like -f=FILE or -v=true
+                        cluster = cluster.substring(separator.length());
+                        arity = arity.min(Math.max(1, arity.min)); // if 
key=value, minimum arity is at least 1
+                    }
+                    args.push(cluster); // interpret remainder as option 
parameter (CAUTION: may be empty string!)
+                    // arity may be >= 1, or
+                    // arity <= 0 && !cluster.startsWith(separator)
+                    // e.g., boolean @Option("-v", arity=0, varargs=true); arg 
"-rvTRUE", remainder cluster="TRUE"
+                    int consumed = applyOption(field, Option.class, arity, 
paramAttachedToOption, args, initialized);
+                    // only return if cluster (and maybe more) was consumed, 
otherwise continue do-while loop
+                    if (consumed > 0) {
+                        return;
+                    }
+                    cluster = args.pop();
+                } else { // cluster is empty || cluster.charAt(0) is not a 
short option key
+                    if (cluster.length() == 0) { // we finished parsing a 
group of short options like -rxv
+                        return; // return normally and parse the next arg
+                    }
+                    // We get here when the remainder of the cluster group is 
neither an option,
+                    // nor a parameter that the last option could consume.
+                    if (arg.endsWith(cluster)) {
+                        // remainder was part of a clustered group that could 
not be completely parsed
+                        args.push(paramAttachedToOption ? prefix + cluster : 
cluster);
+                        handleUnmatchedArguments(args);
+                    }
+                    args.push(cluster);
+                    processPositionalParameters(required, args);
+                    return;
+                }
+            } while (true);
+        }
+
+        private int applyOption(Field field,
+                                Class<?> annotation,
+                                Range arity,
+                                boolean valueAttachedToOption,
+                                Stack<String> args,
+                                Set<Field> initialized) throws Exception {
+            updateHelpRequested(field);
+            if (!args.isEmpty() && args.peek().length(

<TRUNCATED>

Reply via email to