diff options
Diffstat (limited to 'third_party/java/jopt-simple/src/main/java')
50 files changed, 5769 insertions, 0 deletions
diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/AbstractOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/AbstractOptionSpec.java new file mode 100644 index 0000000000..2c045bd500 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/AbstractOptionSpec.java @@ -0,0 +1,148 @@ +/* + 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.util.ArrayList; +import java.util.List; + +import static java.util.Collections.*; + +import joptsimple.internal.Reflection; +import joptsimple.internal.ReflectionException; + +import static joptsimple.internal.Strings.*; + +/** + * @param <V> represents the type of the arguments this option accepts + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor { + private final List<String> options = new ArrayList<>(); + private final String description; + private boolean forHelp; + + AbstractOptionSpec( String option ) { + this( singletonList( option ), EMPTY ); + } + + AbstractOptionSpec( List<String> options, String description ) { + arrangeOptions( options ); + + this.description = description; + } + + public final List<String> options() { + return unmodifiableList( options ); + } + + public final List<V> values( OptionSet detectedOptions ) { + return detectedOptions.valuesOf( this ); + } + + public final V value( OptionSet detectedOptions ) { + return detectedOptions.valueOf( this ); + } + + public String description() { + return description; + } + + public final AbstractOptionSpec<V> forHelp() { + forHelp = true; + return this; + } + + public final boolean isForHelp() { + return forHelp; + } + + public boolean representsNonOptions() { + return false; + } + + protected abstract V convert( String argument ); + + protected V convertWith( ValueConverter<V> converter, String argument ) { + try { + return Reflection.convertWith( converter, argument ); + } catch ( ReflectionException | ValueConversionException ex ) { + throw new OptionArgumentConversionException( this, argument, ex ); + } + } + + protected String argumentTypeIndicatorFrom( ValueConverter<V> converter ) { + if ( converter == null ) + return null; + + String pattern = converter.valuePattern(); + return pattern == null ? converter.valueType().getName() : pattern; + } + + abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ); + + private void arrangeOptions( List<String> unarranged ) { + if ( unarranged.size() == 1 ) { + options.addAll( unarranged ); + return; + } + + List<String> shortOptions = new ArrayList<>(); + List<String> longOptions = new ArrayList<>(); + + for ( String each : unarranged ) { + if ( each.length() == 1 ) + shortOptions.add( each ); + else + longOptions.add( each ); + } + + sort( shortOptions ); + sort( longOptions ); + + options.addAll( shortOptions ); + options.addAll( longOptions ); + } + + @Override + public boolean equals( Object that ) { + if ( !( that instanceof AbstractOptionSpec<?> ) ) + return false; + + AbstractOptionSpec<?> other = (AbstractOptionSpec<?>) that; + return options.equals( other.options ); + } + + @Override + public int hashCode() { + return options.hashCode(); + } + + @Override + public String toString() { + return options.toString(); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/AlternativeLongOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/AlternativeLongOptionSpec.java new file mode 100644 index 0000000000..a3108c1da4 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/AlternativeLongOptionSpec.java @@ -0,0 +1,65 @@ +/* + 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 joptsimple.internal.Messages; + +import java.util.Locale; + +import static java.util.Collections.*; + +import static joptsimple.ParserRules.*; + +/** + * Represents the {@code "-W"} form of long option specification. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec<String> { + AlternativeLongOptionSpec() { + super( singletonList( RESERVED_FOR_EXTENSIONS ), + true, + Messages.message( + Locale.getDefault(), + "joptsimple.HelpFormatterMessages", + AlternativeLongOptionSpec.class, + "description" ) ); + + describedAs( Messages.message( + Locale.getDefault(), + "joptsimple.HelpFormatterMessages", + AlternativeLongOptionSpec.class, + "arg.description" ) ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( !arguments.hasMore() ) + throw new OptionMissingRequiredArgumentException( this ); + + arguments.treatNextAsLongOption(); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentAcceptingOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentAcceptingOptionSpec.java new file mode 100644 index 0000000000..ca4c59f0b0 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentAcceptingOptionSpec.java @@ -0,0 +1,329 @@ +/* + 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.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import static java.util.Collections.*; +import static java.util.Objects.*; + +import static joptsimple.internal.Reflection.*; +import static joptsimple.internal.Strings.*; + +/** + * <p>Specification of an option that accepts an argument.</p> + * + * <p>Instances are returned from {@link OptionSpecBuilder} methods to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:</p> + * + * <pre> + * <code> + * OptionParser parser = new OptionParser(); + * parser.accepts( "c" ).withRequiredArg().<strong>ofType( Integer.class )</strong>; + * </code> + * </pre> + * + * <p>If no methods are invoked on an instance of this class, then that instance's option will treat its argument as + * a {@link String}.</p> + * + * @param <V> represents the type of the arguments this option accepts + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<V> { + private static final char NIL_VALUE_SEPARATOR = '\u0000'; + + private final boolean argumentRequired; + private final List<V> defaultValues = new ArrayList<>(); + + private boolean optionRequired; + private ValueConverter<V> converter; + private String argumentDescription = ""; + private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR ); + + ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) { + super( option ); + + this.argumentRequired = argumentRequired; + } + + ArgumentAcceptingOptionSpec( List<String> options, boolean argumentRequired, String description ) { + super( options, description ); + + this.argumentRequired = argumentRequired; + } + + /** + * <p>Specifies a type to which arguments of this spec's option are to be converted.</p> + * + * <p>JOpt Simple accepts types that have either:</p> + * + * <ol> + * <li>a public static method called {@code valueOf} which accepts a single argument of type {@link String} + * and whose return type is the same as the class on which the method is declared. The {@code java.lang} + * primitive wrapper classes have such methods.</li> + * + * <li>a public constructor which accepts a single argument of type {@link String}.</li> + * </ol> + * + * <p>This class converts arguments using those methods in that order; that is, {@code valueOf} would be invoked + * before a one-{@link String}-arg constructor would.</p> + * + * <p>Invoking this method will trump any previous calls to this method or to + * {@link #withValuesConvertedBy(ValueConverter)}.</p> + * + * @param <T> represents the runtime class of the desired option argument type + * @param argumentType desired type of arguments to this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the type is {@code null} + * @throws IllegalArgumentException if the type does not have the standard conversion methods + */ + public final <T> ArgumentAcceptingOptionSpec<T> ofType( Class<T> argumentType ) { + return withValuesConvertedBy( findConverter( argumentType ) ); + } + + /** + * <p>Specifies a converter to use to translate arguments of this spec's option into Java objects. This is useful + * when converting to types that do not have the requisite factory method or constructor for + * {@link #ofType(Class)}.</p> + * + * <p>Invoking this method will trump any previous calls to this method or to {@link #ofType(Class)}. + * + * @param <T> represents the runtime class of the desired option argument type + * @param aConverter the converter to use + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the converter is {@code null} + */ + @SuppressWarnings( "unchecked" ) + public final <T> ArgumentAcceptingOptionSpec<T> withValuesConvertedBy( ValueConverter<T> aConverter ) { + if ( aConverter == null ) + throw new NullPointerException( "illegal null converter" ); + + converter = (ValueConverter<V>) aConverter; + return (ArgumentAcceptingOptionSpec<T>) this; + } + + /** + * <p>Specifies a description for the argument of the option that this spec represents. This description is used + * when generating help information about the parser.</p> + * + * @param description describes the nature of the argument of this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public final ArgumentAcceptingOptionSpec<V> describedAs( String description ) { + argumentDescription = description; + return this; + } + + /** + * <p>Specifies a value separator for the argument of the option that this spec represents. This allows a single + * option argument to represent multiple values for the option. For example:</p> + * + * <pre> + * <code> + * parser.accepts( "z" ).withRequiredArg() + * .<strong>withValuesSeparatedBy( ',' )</strong>; + * OptionSet options = parser.parse( new String[] { "-z", "foo,bar,baz", "-z", + * "fizz", "-z", "buzz" } ); + * </code> + * </pre> + * + * <p>Then <code>options.valuesOf( "z" )</code> would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p> + * + * <p>You cannot use Unicode U+0000 as the separator.</p> + * + * @param separator a character separator + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws IllegalArgumentException if the separator is Unicode U+0000 + */ + public final ArgumentAcceptingOptionSpec<V> withValuesSeparatedBy( char separator ) { + if ( separator == NIL_VALUE_SEPARATOR ) + throw new IllegalArgumentException( "cannot use U+0000 as separator" ); + + valueSeparator = String.valueOf( separator ); + return this; + } + + /** + * <p>Specifies a value separator for the argument of the option that this spec represents. This allows a single + * option argument to represent multiple values for the option. For example:</p> + * + * <pre> + * <code> + * parser.accepts( "z" ).withRequiredArg() + * .<strong>withValuesSeparatedBy( ":::" )</strong>; + * OptionSet options = parser.parse( new String[] { "-z", "foo:::bar:::baz", "-z", + * "fizz", "-z", "buzz" } ); + * </code> + * </pre> + * + * <p>Then <code>options.valuesOf( "z" )</code> would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p> + * + * <p>You cannot use Unicode U+0000 in the separator.</p> + * + * @param separator a string separator + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws IllegalArgumentException if the separator contains Unicode U+0000 + */ + public final ArgumentAcceptingOptionSpec<V> withValuesSeparatedBy( String separator ) { + if ( separator.indexOf( NIL_VALUE_SEPARATOR ) != -1 ) + throw new IllegalArgumentException( "cannot use U+0000 in separator" ); + + valueSeparator = separator; + return this; + } + + /** + * Specifies a set of default values for the argument of the option that this spec represents. + * + * @param value the first in the set of default argument values for this spec's option + * @param values the (optional) remainder of the set of default argument values for this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are + * {@code null} + */ + @SafeVarargs + public final ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) { + addDefaultValue( value ); + defaultsTo( values ); + + return this; + } + + /** + * Specifies a set of default values for the argument of the option that this spec represents. + * + * @param values the set of default argument values for this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if {@code values} or any elements of {@code values} are {@code null} + */ + public ArgumentAcceptingOptionSpec<V> defaultsTo( V[] values ) { + for ( V each : values ) + addDefaultValue( each ); + + return this; + } + + /** + * Marks this option as required. An {@link OptionException} will be thrown when + * {@link OptionParser#parse(java.lang.String...)} is called, if an option is marked as required and not specified + * on the command line. + * + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public ArgumentAcceptingOptionSpec<V> required() { + optionRequired = true; + return this; + } + + public boolean isRequired() { + return optionRequired; + } + + private void addDefaultValue( V value ) { + requireNonNull( value ); + defaultValues.add( value ); + } + + @Override + final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + if ( isNullOrEmpty( detectedArgument ) ) + detectOptionArgument( parser, arguments, detectedOptions ); + else + addArguments( detectedOptions, detectedArgument ); + } + + protected void addArguments( OptionSet detectedOptions, String detectedArgument ) { + StringTokenizer lexer = new StringTokenizer( detectedArgument, valueSeparator ); + if ( !lexer.hasMoreTokens() ) + detectedOptions.addWithArgument( this, detectedArgument ); + else { + while ( lexer.hasMoreTokens() ) + detectedOptions.addWithArgument( this, lexer.nextToken() ); + } + } + + protected abstract void detectOptionArgument( OptionParser parser, ArgumentList arguments, + OptionSet detectedOptions ); + + @Override + protected final V convert( String argument ) { + return convertWith( converter, argument ); + } + + protected boolean canConvertArgument( String argument ) { + StringTokenizer lexer = new StringTokenizer( argument, valueSeparator ); + + try { + while ( lexer.hasMoreTokens() ) + convert( lexer.nextToken() ); + return true; + } catch ( OptionException ignored ) { + return false; + } + } + + protected boolean isArgumentOfNumberType() { + return converter != null && Number.class.isAssignableFrom( converter.valueType() ); + } + + public boolean acceptsArguments() { + return true; + } + + public boolean requiresArgument() { + return argumentRequired; + } + + public String argumentDescription() { + return argumentDescription; + } + + public String argumentTypeIndicator() { + return argumentTypeIndicatorFrom( converter ); + } + + public List<V> defaultValues() { + return unmodifiableList( defaultValues ); + } + + @Override + public boolean equals( Object that ) { + if ( !super.equals( that ) ) + return false; + + ArgumentAcceptingOptionSpec<?> other = (ArgumentAcceptingOptionSpec<?>) that; + return requiresArgument() == other.requiresArgument(); + } + + @Override + public int hashCode() { + return super.hashCode() ^ ( argumentRequired ? 0 : 1 ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentList.java b/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentList.java new file mode 100644 index 0000000000..744f31aa21 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/ArgumentList.java @@ -0,0 +1,59 @@ +/* + 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 static joptsimple.ParserRules.*; + +/** + * <p>Wrapper for an array of command line arguments.</p> + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class ArgumentList { + private final String[] arguments; + private int currentIndex; + + ArgumentList( String... arguments ) { + this.arguments = arguments.clone(); + } + + boolean hasMore() { + return currentIndex < arguments.length; + } + + String next() { + return arguments[ currentIndex++ ]; + } + + String peek() { + return arguments[ currentIndex ]; + } + + void treatNextAsLongOption() { + if ( HYPHEN_CHAR != arguments[ currentIndex ].charAt( 0 ) ) + arguments[ currentIndex ] = DOUBLE_HYPHEN + arguments[ currentIndex ]; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java new file mode 100644 index 0000000000..51ec603e6f --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java @@ -0,0 +1,565 @@ +/* + 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.util.*; + +import joptsimple.internal.Messages; +import joptsimple.internal.Rows; +import joptsimple.internal.Strings; + +import static joptsimple.ParserRules.*; +import static joptsimple.internal.Classes.*; +import static joptsimple.internal.Strings.*; + +/** + * <p>A help formatter that allows configuration of overall row width and column separator width.</p> + * + * <p>The formatter produces output in two sections: one for the options, and one for non-option arguments.</p> + * + * <p>The options section has two columns: the left column for the options, and the right column for their + * descriptions. The formatter will allow as much space as possible for the descriptions, by minimizing the option + * column's width, no greater than slightly less than half the overall desired width.</p> + * + * <p>The non-option arguments section is one column, occupying as much width as it can.</p> + * + * <p>Subclasses are free to override bits of this implementation as they see fit. Inspect the code + * carefully to understand the flow of control that this implementation guarantees.</p> + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class BuiltinHelpFormatter implements HelpFormatter { + private final Rows nonOptionRows; + private final Rows optionRows; + + /** + * Makes a formatter with a pre-configured overall row width and column separator width. + */ + BuiltinHelpFormatter() { + this( 80, 2 ); + } + + /** + * Makes a formatter with a given overall row width and column separator width. + * + * @param desiredOverallWidth how many characters wide to make the overall help display + * @param desiredColumnSeparatorWidth how many characters wide to make the separation between option column and + * description column + */ + public BuiltinHelpFormatter( int desiredOverallWidth, int desiredColumnSeparatorWidth ) { + nonOptionRows = new Rows( desiredOverallWidth * 2, 0 ); + optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth ); + } + + /** + * {@inheritDoc} + * + * <p>This implementation:</p> + * <ul> + * <li>Sorts the given descriptors by their first elements of {@link OptionDescriptor#options()}</li> + * <li>Passes the resulting sorted set to {@link #addRows(java.util.Collection)}</li> + * <li>Returns the result of {@link #formattedHelpOutput()}</li> + * </ul> + */ + public String format( Map<String, ? extends OptionDescriptor> options ) { + optionRows.reset(); + nonOptionRows.reset(); + + Comparator<OptionDescriptor> comparator = + new Comparator<OptionDescriptor>() { + public int compare( OptionDescriptor first, OptionDescriptor second ) { + return first.options().iterator().next().compareTo( second.options().iterator().next() ); + } + }; + + Set<OptionDescriptor> sorted = new TreeSet<>( comparator ); + sorted.addAll( options.values() ); + + addRows( sorted ); + + return formattedHelpOutput(); + } + + /** + * Adds a row of option help output in the left column, with empty space in the right column. + * + * @param single text to put in the left column + */ + protected void addOptionRow( String single ) { + addOptionRow( single, "" ); + } + + /** + * Adds a row of option help output in the left and right columns. + * + * @param left text to put in the left column + * @param right text to put in the right column + */ + protected void addOptionRow( String left, String right ) { + optionRows.add( left, right ); + } + + /** + * Adds a single row of non-option argument help. + * + * @param single single row of non-option argument help text + */ + protected void addNonOptionRow( String single ) { + nonOptionRows.add( single, "" ); + } + + /** + * Resizes the columns of all the rows to be no wider than the widest element in that column. + */ + protected void fitRowsToWidth() { + nonOptionRows.fitToWidth(); + optionRows.fitToWidth(); + } + + /** + * Produces non-option argument help. + * + * @return non-option argument help + */ + protected String nonOptionOutput() { + return nonOptionRows.render(); + } + + /** + * Produces help for options and their descriptions. + * + * @return option help + */ + protected String optionOutput() { + return optionRows.render(); + } + + /** + * <p>Produces help output for an entire set of options and non-option arguments.</p> + * + * <p>This implementation concatenates:</p> + * <ul> + * <li>the result of {@link #nonOptionOutput()}</li> + * <li>if there is non-option output, a line separator</li> + * <li>the result of {@link #optionOutput()}</li> + * </ul> + * + * @return help output for entire set of options and non-option arguments + */ + protected String formattedHelpOutput() { + StringBuilder formatted = new StringBuilder(); + String nonOptionDisplay = nonOptionOutput(); + if ( !Strings.isNullOrEmpty( nonOptionDisplay ) ) + formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR ); + formatted.append( optionOutput() ); + + return formatted.toString(); + } + + /** + * <p>Adds rows of help output for the given options.</p> + * + * <p>This implementation:</p> + * <ul> + * <li>Calls {@link #addNonOptionsDescription(java.util.Collection)} with the options as the argument</li> + * <li>If there are no options, calls {@link #addOptionRow(String)} with an argument that indicates + * that no options are specified.</li> + * <li>Otherwise, calls {@link #addHeaders(java.util.Collection)} with the options as the argument, + * followed by {@link #addOptions(java.util.Collection)} with the options as the argument.</li> + * <li>Calls {@link #fitRowsToWidth()}.</li> + * </ul> + * + * @param options descriptors for the configured options of a parser + */ + protected void addRows( Collection<? extends OptionDescriptor> options ) { + addNonOptionsDescription( options ); + + if ( options.isEmpty() ) + addOptionRow( message( "no.options.specified" ) ); + else { + addHeaders( options ); + addOptions( options ); + } + + fitRowsToWidth(); + } + + /** + * <p>Adds non-option arguments descriptions to the help output.</p> + * + * <p>This implementation:</p> + * <ul> + * <li>{@linkplain #findAndRemoveNonOptionsSpec(java.util.Collection) Finds and removes the non-option + * arguments descriptor}</li> + * <li>{@linkplain #shouldShowNonOptionArgumentDisplay(OptionDescriptor) Decides whether there is + * anything to show for non-option arguments}</li> + * <li>If there is, {@linkplain #addNonOptionRow(String) adds a header row} and + * {@linkplain #addNonOptionRow(String) adds a} + * {@linkplain #createNonOptionArgumentsDisplay(OptionDescriptor) non-option arguments description} </li> + * </ul> + * + * @param options descriptors for the configured options of a parser + */ + protected void addNonOptionsDescription( Collection<? extends OptionDescriptor> options ) { + OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options ); + if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) { + addNonOptionRow( message( "non.option.arguments.header" ) ); + addNonOptionRow( createNonOptionArgumentsDisplay( nonOptions ) ); + } + } + + /** + * <p>Decides whether or not to show a non-option arguments help.</p> + * + * <p>This implementation responds with {@code true} if the non-option descriptor has a non-{@code null}, + * non-empty value for any of {@link OptionDescriptor#description()}, + * {@link OptionDescriptor#argumentTypeIndicator()}, or {@link OptionDescriptor#argumentDescription()}.</p> + * + * @param nonOptionDescriptor non-option argument descriptor + * @return {@code true} if non-options argument help should be shown + */ + protected boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptionDescriptor ) { + return !Strings.isNullOrEmpty( nonOptionDescriptor.description() ) + || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentTypeIndicator() ) + || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentDescription() ); + } + + /** + * <p>Creates a non-options argument help string.</p> + * + * <p>This implementation creates an empty string buffer and calls + * {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)} + * and {@link #maybeAppendNonOptionsDescription(StringBuilder, OptionDescriptor)}, passing them the + * buffer and the non-option arguments descriptor.</p> + * + * @param nonOptionDescriptor non-option argument descriptor + * @return help string for non-options + */ + protected String createNonOptionArgumentsDisplay( OptionDescriptor nonOptionDescriptor ) { + StringBuilder buffer = new StringBuilder(); + maybeAppendOptionInfo( buffer, nonOptionDescriptor ); + maybeAppendNonOptionsDescription( buffer, nonOptionDescriptor ); + + return buffer.toString(); + } + + /** + * <p>Appends help for the given non-option arguments descriptor to the given buffer.</p> + * + * <p>This implementation appends {@code " -- "} if the buffer has text in it and the non-option arguments + * descriptor has a {@link OptionDescriptor#description()}; followed by the + * {@link OptionDescriptor#description()}.</p> + * + * @param buffer string buffer + * @param nonOptions non-option arguments descriptor + */ + protected void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) { + buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" ) + .append( nonOptions.description() ); + } + + /** + * Finds the non-option arguments descriptor in the given collection, removes it, and returns it. + * + * @param options descriptors for the configured options of a parser + * @return the non-option arguments descriptor + */ + protected OptionDescriptor findAndRemoveNonOptionsSpec( Collection<? extends OptionDescriptor> options ) { + for ( Iterator<? extends OptionDescriptor> it = options.iterator(); it.hasNext(); ) { + OptionDescriptor next = it.next(); + if ( next.representsNonOptions() ) { + it.remove(); + return next; + } + } + + throw new AssertionError( "no non-options argument spec" ); + } + + /** + * <p>Adds help row headers for option help columns.</p> + * + * <p>This implementation uses the headers {@code "Option"} and {@code "Description"}. If the options contain + * a "required" option, the {@code "Option"} header looks like {@code "Option (* = required)}. Both headers + * are "underlined" using {@code "-"}.</p> + * + * @param options descriptors for the configured options of a parser + */ + protected void addHeaders( Collection<? extends OptionDescriptor> options ) { + if ( hasRequiredOption( options ) ) { + addOptionRow( message( "option.header.with.required.indicator" ), message( "description.header" ) ); + addOptionRow( message( "option.divider.with.required.indicator" ), message( "description.divider" ) ); + } else { + addOptionRow( message( "option.header" ), message( "description.header" ) ); + addOptionRow( message( "option.divider" ), message( "description.divider" ) ); + } + } + + /** + * Tells whether the given option descriptors contain a "required" option. + * + * @param options descriptors for the configured options of a parser + * @return {@code true} if at least one of the options is "required" + */ + protected final boolean hasRequiredOption( Collection<? extends OptionDescriptor> options ) { + for ( OptionDescriptor each : options ) { + if ( each.isRequired() ) + return true; + } + + return false; + } + + /** + * <p>Adds help rows for the given options.</p> + * + * <p>This implementation loops over the given options, and for each, calls {@link #addOptionRow(String, String)} + * using the results of {@link #createOptionDisplay(OptionDescriptor)} and + * {@link #createDescriptionDisplay(OptionDescriptor)}, respectively, as arguments.</p> + * + * @param options descriptors for the configured options of a parser + */ + protected void addOptions( Collection<? extends OptionDescriptor> options ) { + for ( OptionDescriptor each : options ) { + if ( !each.representsNonOptions() ) + addOptionRow( createOptionDisplay( each ), createDescriptionDisplay( each ) ); + } + } + + /** + * <p>Creates a string for how the given option descriptor is to be represented in help.</p> + * + * <p>This implementation gives a string consisting of the concatenation of:</p> + * <ul> + * <li>{@code "* "} for "required" options, otherwise {@code ""}</li> + * <li>For each of the {@link OptionDescriptor#options()} of the descriptor, separated by {@code ", "}: + * <ul> + * <li>{@link #optionLeader(String)} of the option</li> + * <li>the option</li> + * </ul> + * </li> + * <li>the result of {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}</li> + * </ul> + * + * @param descriptor a descriptor for a configured option of a parser + * @return help string + */ + protected String createOptionDisplay( OptionDescriptor descriptor ) { + StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" ); + + for ( Iterator<String> i = descriptor.options().iterator(); i.hasNext(); ) { + String option = i.next(); + buffer.append( optionLeader( option ) ); + buffer.append( option ); + + if ( i.hasNext() ) + buffer.append( ", " ); + } + + maybeAppendOptionInfo( buffer, descriptor ); + + return buffer.toString(); + } + + /** + * <p>Gives a string that represents the given option's "option leader" in help.</p> + * + * <p>This implementation answers with {@code "--"} for options of length greater than one; otherwise answers + * with {@code "-"}.</p> + * + * @param option a string option + * @return an "option leader" string + */ + protected String optionLeader( String option ) { + return option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN; + } + + /** + * <p>Appends additional info about the given option to the given buffer.</p> + * + * <p>This implementation:</p> + * <ul> + * <li>calls {@link #extractTypeIndicator(OptionDescriptor)} for the descriptor</li> + * <li>calls {@link joptsimple.OptionDescriptor#argumentDescription()} for the descriptor</li> + * <li>if either of the above is present, calls + * {@link #appendOptionHelp(StringBuilder, String, String, boolean)}</li> + * </ul> + * + * @param buffer string buffer + * @param descriptor a descriptor for a configured option of a parser + */ + protected void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) { + String indicator = extractTypeIndicator( descriptor ); + String description = descriptor.argumentDescription(); + if ( descriptor.acceptsArguments() + || !isNullOrEmpty( description ) + || descriptor.representsNonOptions() ) { + + appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() ); + } + } + + /** + * <p>Gives an indicator of the type of arguments of the option described by the given descriptor, + * for use in help.</p> + * + * <p>This implementation asks for the {@link OptionDescriptor#argumentTypeIndicator()} of the given + * descriptor, and if it is present and not {@code "java.lang.String"}, parses it as a fully qualified + * class name and returns the base name of that class; otherwise returns {@code "String"}.</p> + * + * @param descriptor a descriptor for a configured option of a parser + * @return type indicator text + */ + protected String extractTypeIndicator( OptionDescriptor descriptor ) { + String indicator = descriptor.argumentTypeIndicator(); + + if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) ) + return shortNameOf( indicator ); + + return "String"; + } + + /** + * <p>Appends info about an option's argument to the given buffer.</p> + * + * <p>This implementation calls {@link #appendTypeIndicator(StringBuilder, String, String, char, char)} with + * the surrounding characters {@code '<'} and {@code '>'} for options with {@code required} arguments, and + * with the surrounding characters {@code '['} and {@code ']'} for options with optional arguments.</p> + * + * @param buffer string buffer + * @param typeIndicator type indicator + * @param description type description + * @param required indicator of "required"-ness of the argument of the option + */ + protected void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, + boolean required ) { + if ( required ) + appendTypeIndicator( buffer, typeIndicator, description, '<', '>' ); + else + appendTypeIndicator( buffer, typeIndicator, description, '[', ']' ); + } + + /** + * <p>Appends a type indicator for an option's argument to the given buffer.</p> + * + * <p>This implementation appends, in order:</p> + * <ul> + * <li>{@code ' '}</li> + * <li>{@code start}</li> + * <li>the type indicator, if not {@code null}</li> + * <li>if the description is present, then {@code ": "} plus the description if the type indicator is + * present; otherwise the description only</li> + * <li>{@code end}</li> + * </ul> + * + * @param buffer string buffer + * @param typeIndicator type indicator + * @param description type description + * @param start starting character + * @param end ending character + */ + protected void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description, + char start, char end ) { + buffer.append( ' ' ).append( start ); + if ( typeIndicator != null ) + buffer.append( typeIndicator ); + + if ( !Strings.isNullOrEmpty( description ) ) { + if ( typeIndicator != null ) + buffer.append( ": " ); + + buffer.append( description ); + } + + buffer.append( end ); + } + + /** + * <p>Gives a string representing a description of the option with the given descriptor.</p> + * + * <p>This implementation:</p> + * <ul> + * <li>Asks for the descriptor's {@link OptionDescriptor#defaultValues()}</li> + * <li>If they're not present, answers the descriptor's {@link OptionDescriptor#description()}.</li> + * <li>If they are present, concatenates and returns: + * <ul> + * <li>the descriptor's {@link OptionDescriptor#description()}</li> + * <li>{@code ' '}</li> + * <li>{@code "default: "} plus the result of {@link #createDefaultValuesDisplay(java.util.List)}, + * surrounded by parentheses</li> + * </ul> + * </li> + * </ul> + * + * @param descriptor a descriptor for a configured option of a parser + * @return display text for the option's description + */ + protected String createDescriptionDisplay( OptionDescriptor descriptor ) { + List<?> defaultValues = descriptor.defaultValues(); + if ( defaultValues.isEmpty() ) + return descriptor.description(); + + String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues ); + return ( descriptor.description() + + ' ' + + surround( message( "default.value.header" ) + ' ' + defaultValuesDisplay, '(', ')' ) + ).trim(); + } + + /** + * <p>Gives a display string for the default values of an option's argument.</p> + * + * <p>This implementation gives the {@link Object#toString()} of the first value if there is only one value, + * otherwise gives the {@link Object#toString()} of the whole list.</p> + * + * @param defaultValues some default values for a given option's argument + * @return a display string for those default values + */ + protected String createDefaultValuesDisplay( List<?> defaultValues ) { + return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString(); + } + + /** + * <p>Looks up and gives a resource bundle message.</p> + * + * <p>This implementation looks in the bundle {@code "joptsimple.HelpFormatterMessages"} in the default + * locale, using a key that is the concatenation of this class's fully qualified name, {@code '.'}, + * and the given key suffix, formats the corresponding value using the given arguments, and returns + * the result.</p> + * + * @param keySuffix suffix to use when looking up the bundle message + * @param args arguments to fill in the message template with + * @return a formatted localized message + */ + protected String message( String keySuffix, Object... args ) { + return Messages.message( + Locale.getDefault(), + "joptsimple.HelpFormatterMessages", + BuiltinHelpFormatter.class, + keySuffix, + args ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/HelpFormatter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/HelpFormatter.java new file mode 100644 index 0000000000..d178d70c09 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/HelpFormatter.java @@ -0,0 +1,45 @@ +/* + 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.util.Map; + +/** + * <p>Represents objects charged with taking a set of option descriptions and producing some help text from them.</p> + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public interface HelpFormatter { + /** + * Produces help text, given a set of option descriptors. + * + * @param options descriptors for the configured options of a parser + * @return text to be used as help + * @see OptionParser#printHelpOn(java.io.Writer) + * @see OptionParser#formatHelpWith(HelpFormatter) + */ + String format( Map<String, ? extends OptionDescriptor> options ); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/IllegalOptionSpecificationException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/IllegalOptionSpecificationException.java new file mode 100644 index 0000000000..214791544c --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/IllegalOptionSpecificationException.java @@ -0,0 +1,46 @@ +/* + 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 static java.util.Collections.*; + +/** + * Thrown when the option parser is asked to recognize an option with illegal characters in it. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class IllegalOptionSpecificationException extends OptionException { + private static final long serialVersionUID = -1L; + + IllegalOptionSpecificationException( String option ) { + super( singletonList( option ) ); + } + + @Override + Object[] messageArguments() { + return new Object[] { singleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/MissingRequiredOptionsException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/MissingRequiredOptionsException.java new file mode 100644 index 0000000000..dcb829f342 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/MissingRequiredOptionsException.java @@ -0,0 +1,46 @@ +/* + 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.util.List; + +/** + * Thrown when options marked as required are not specified on the command line. + * + * @author <a href="https://github.com/TC1">Emils Solmanis</a> + */ +class MissingRequiredOptionsException extends OptionException { + private static final long serialVersionUID = -1L; + + protected MissingRequiredOptionsException( List<? extends OptionSpec<?>> missingRequiredOptions ) { + super( missingRequiredOptions ); + } + + @Override + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/MultipleArgumentsForOptionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/MultipleArgumentsForOptionException.java new file mode 100644 index 0000000000..12d1485a39 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/MultipleArgumentsForOptionException.java @@ -0,0 +1,46 @@ +/* + 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 static java.util.Collections.*; + +/** + * Thrown when asking an {@link OptionSet} for a single argument of an option when many have been specified. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class MultipleArgumentsForOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + MultipleArgumentsForOptionException( OptionSpec<?> options ) { + super( singleton( options ) ); + } + + @Override + Object[] messageArguments() { + return new Object[] { singleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/NoArgumentOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/NoArgumentOptionSpec.java new file mode 100644 index 0000000000..82ac521772 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/NoArgumentOptionSpec.java @@ -0,0 +1,81 @@ +/* + 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.util.List; + +import static java.util.Collections.*; + +/** + * A specification for an option that does not accept arguments. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class NoArgumentOptionSpec extends AbstractOptionSpec<Void> { + NoArgumentOptionSpec( String option ) { + this( singletonList( option ), "" ); + } + + NoArgumentOptionSpec( List<String> options, String description ) { + super( options, description ); + } + + @Override + void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + detectedOptions.add( this ); + } + + public boolean acceptsArguments() { + return false; + } + + public boolean requiresArgument() { + return false; + } + + public boolean isRequired() { + return false; + } + + public String argumentDescription() { + return ""; + } + + public String argumentTypeIndicator() { + return ""; + } + + @Override + protected Void convert( String argument ) { + return null; + } + + public List<Void> defaultValues() { + return emptyList(); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/NonOptionArgumentSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/NonOptionArgumentSpec.java new file mode 100644 index 0000000000..7343d42c2a --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/NonOptionArgumentSpec.java @@ -0,0 +1,170 @@ +/* + 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.util.List; + +import static java.util.Arrays.*; +import static java.util.Collections.*; +import static joptsimple.internal.Reflection.*; + +/** + * <p>Specification of a command line's non-option arguments.</p> + * + * <p>Instances are returned from {@link OptionParser} methods to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:</p> + * + * <pre> + * <code> + * OptionParser parser = new OptionParser(); + * parser.nonOptions( "files to be processed" ).<strong>ofType( File.class )</strong>; + * </code> + * </pre> + * + * <p>If no methods are invoked on an instance of this class, then that instance's option will treat the non-option + * arguments as {@link String}s.</p> + * + * @param <V> represents the type of the non-option arguments + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class NonOptionArgumentSpec<V> extends AbstractOptionSpec<V> { + static final String NAME = "[arguments]"; + + private ValueConverter<V> converter; + private String argumentDescription = ""; + + NonOptionArgumentSpec() { + this( "" ); + } + + NonOptionArgumentSpec( String description ) { + super( asList( NAME ), description ); + } + + /** + * <p>Specifies a type to which the non-option arguments are to be converted.</p> + * + * <p>JOpt Simple accepts types that have either:</p> + * + * <ol> + * <li>a public static method called {@code valueOf} which accepts a single argument of type {@link String} + * and whose return type is the same as the class on which the method is declared. The {@code java.lang} + * primitive wrapper classes have such methods.</li> + * + * <li>a public constructor which accepts a single argument of type {@link String}.</li> + * </ol> + * + * <p>This class converts arguments using those methods in that order; that is, {@code valueOf} would be invoked + * before a one-{@link String}-arg constructor would.</p> + * + * <p>Invoking this method will trump any previous calls to this method or to + * {@link #withValuesConvertedBy(ValueConverter)}.</p> + * + * @param <T> represents the runtime class of the desired option argument type + * @param argumentType desired type of arguments to this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the type is {@code null} + * @throws IllegalArgumentException if the type does not have the standard conversion methods + */ + @SuppressWarnings( "unchecked" ) + public <T> NonOptionArgumentSpec<T> ofType( Class<T> argumentType ) { + converter = (ValueConverter<V>) findConverter( argumentType ); + return (NonOptionArgumentSpec<T>) this; + } + + /** + * <p>Specifies a converter to use to translate non-option arguments into Java objects. This is useful + * when converting to types that do not have the requisite factory method or constructor for + * {@link #ofType(Class)}.</p> + * + * <p>Invoking this method will trump any previous calls to this method or to {@link #ofType(Class)}. + * + * @param <T> represents the runtime class of the desired non-option argument type + * @param aConverter the converter to use + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the converter is {@code null} + */ + @SuppressWarnings( "unchecked" ) + public final <T> NonOptionArgumentSpec<T> withValuesConvertedBy( ValueConverter<T> aConverter ) { + if ( aConverter == null ) + throw new NullPointerException( "illegal null converter" ); + + converter = (ValueConverter<V>) aConverter; + return (NonOptionArgumentSpec<T>) this; + } + + /** + * <p>Specifies a description for the non-option arguments that this spec represents. This description is used + * when generating help information about the parser.</p> + * + * @param description describes the nature of the argument of this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public NonOptionArgumentSpec<V> describedAs( String description ) { + argumentDescription = description; + return this; + } + + @Override + protected final V convert( String argument ) { + return convertWith( converter, argument ); + } + + @Override + void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + detectedOptions.addWithArgument( this, detectedArgument ); + } + + public List<?> defaultValues() { + return emptyList(); + } + + public boolean isRequired() { + return false; + } + + public boolean acceptsArguments() { + return false; + } + + public boolean requiresArgument() { + return false; + } + + public String argumentDescription() { + return argumentDescription; + } + + public String argumentTypeIndicator() { + return argumentTypeIndicatorFrom( converter ); + } + + public boolean representsNonOptions() { + return true; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionArgumentConversionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionArgumentConversionException.java new file mode 100644 index 0000000000..193557d8fa --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionArgumentConversionException.java @@ -0,0 +1,50 @@ +/* + 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 static java.util.Collections.*; + +/** + * Thrown when a problem occurs converting an argument of an option from {@link String} to another type. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class OptionArgumentConversionException extends OptionException { + private static final long serialVersionUID = -1L; + + private final String argument; + + OptionArgumentConversionException( OptionSpec<?> options, String argument, Throwable cause ) { + super( singleton( options ), cause ); + + this.argument = argument; + } + + @Override + Object[] messageArguments() { + return new Object[] { argument, singleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDeclarer.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDeclarer.java new file mode 100644 index 0000000000..7d54653443 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDeclarer.java @@ -0,0 +1,116 @@ +package joptsimple; + +import java.util.List; + +/** + * Trains the option parser. This interface aids integration that disposes declaration of options but not actual + * command-line parsing. + * + * Typical use is for another class to implement {@code OptionDeclarer} as a facade, forwarding calls to an + * {@code OptionParser} instance. + * + * Note that although this is an interface, the returned values of calls are concrete jopt-simple classes. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + * @see OptionParser + * @since 4.6 + */ +public interface OptionDeclarer { + /** + * Tells the parser to recognize the given option. + * + * <p>This method returns an instance of {@link OptionSpecBuilder} to allow the formation of parser directives + * as sentences in a fluent interface language. For example:</p> + * + * <pre><code> + * OptionDeclarer parser = new OptionParser(); + * parser.<strong>accepts( "c" )</strong>.withRequiredArg().ofType( Integer.class ); + * </code></pre> + * + * <p>If no methods are invoked on the returned {@link OptionSpecBuilder}, then the parser treats the option as + * accepting no argument.</p> + * + * @param option the option to recognize + * @return an object that can be used to flesh out more detail about the option + * @throws OptionException if the option contains illegal characters + * @throws NullPointerException if the option is {@code null} + */ + OptionSpecBuilder accepts( String option ); + + /** + * Tells the parser to recognize the given option. + * + * @see #accepts(String) + * @param option the option to recognize + * @param description a string that describes the purpose of the option. This is used when generating help + * information about the parser. + * @return an object that can be used to flesh out more detail about the option + * @throws OptionException if the option contains illegal characters + * @throws NullPointerException if the option is {@code null} + */ + OptionSpecBuilder accepts( String option, String description ); + + /** + * Tells the parser to recognize the given options, and treat them as synonymous. + * + * @see #accepts(String) + * @param options the options to recognize and treat as synonymous + * @return an object that can be used to flesh out more detail about the options + * @throws OptionException if any of the options contain illegal characters + * @throws NullPointerException if the option list or any of its elements are {@code null} + */ + OptionSpecBuilder acceptsAll( List<String> options ); + + /** + * Tells the parser to recognize the given options, and treat them as synonymous. + * + * @see #acceptsAll(List) + * @param options the options to recognize and treat as synonymous + * @param description a string that describes the purpose of the option. This is used when generating help + * information about the parser. + * @return an object that can be used to flesh out more detail about the options + * @throws OptionException if any of the options contain illegal characters + * @throws NullPointerException if the option list or any of its elements are {@code null} + * @throws IllegalArgumentException if the option list is empty + */ + OptionSpecBuilder acceptsAll( List<String> options, String description ); + + /** + * Gives an object that represents an access point for non-option arguments on a command line. + * + * @return an object that can be used to flesh out more detail about the non-option arguments + */ + NonOptionArgumentSpec<String> nonOptions(); + + /** + * Gives an object that represents an access point for non-option arguments on a command line. + * + * @see #nonOptions() + * @param description a string that describes the purpose of the non-option arguments. This is used when generating + * help information about the parser. + * @return an object that can be used to flesh out more detail about the non-option arguments + */ + NonOptionArgumentSpec<String> nonOptions( String description ); + + /** + * Tells the parser whether or not to behave "POSIX-ly correct"-ly. + * + * @param setting {@code true} if the parser should behave "POSIX-ly correct"-ly + */ + void posixlyCorrect( boolean setting ); + + /** + * <p>Tells the parser to treat unrecognized options as non-option arguments.</p> + * + * <p>If not called, then the parser raises an {@link OptionException} when it encounters an unrecognized + * option.</p> + */ + void allowsUnrecognizedOptions(); + + /** + * Tells the parser either to recognize or ignore {@code -W}-style long options. + * + * @param recognize {@code true} if the parser is to recognize the special style of long options + */ + void recognizeAlternativeLongOptions( boolean recognize ); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDescriptor.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDescriptor.java new file mode 100644 index 0000000000..f77c775223 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionDescriptor.java @@ -0,0 +1,100 @@ +/* + 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.util.List; + +/** + * Describes options that an option parser recognizes, in ways that might be useful to {@linkplain HelpFormatter + * help screens}. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public interface OptionDescriptor { + /** + * A set of options that are mutually synonymous. + * + * @return synonymous options + */ + List<String> options(); + + /** + * Description of this option's purpose. + * + * @return a description for the option + */ + String description(); + + /** + * What values will the option take if none are specified on the command line? + * + * @return any default values for the option + */ + List<?> defaultValues(); + + /** + * Is this option {@linkplain ArgumentAcceptingOptionSpec#required() required} on a command line? + * + * @return whether the option is required + */ + boolean isRequired(); + + /** + * Does this option {@linkplain ArgumentAcceptingOptionSpec accept arguments}? + * + * @return whether the option accepts arguments + */ + boolean acceptsArguments(); + + /** + * Does this option {@linkplain OptionSpecBuilder#withRequiredArg() require an argument}? + * + * @return whether the option requires an argument + */ + boolean requiresArgument(); + + /** + * Gives a short {@linkplain ArgumentAcceptingOptionSpec#describedAs(String) description} of the option's argument. + * + * @return a description for the option's argument + */ + String argumentDescription(); + + /** + * Gives an indication of the {@linkplain ArgumentAcceptingOptionSpec#ofType(Class) expected type} of the option's + * argument. + * + * @return a description for the option's argument type + */ + String argumentTypeIndicator(); + + /** + * Tells whether this object represents the non-option arguments of a command line. + * + * @return {@code true} if this represents non-option arguments + */ + boolean representsNonOptions(); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionException.java new file mode 100644 index 0000000000..88e7e43f2e --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionException.java @@ -0,0 +1,125 @@ +/* + 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.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import joptsimple.internal.Strings; + +import static java.util.Collections.*; +import static joptsimple.internal.Messages.*; + +/** + * Thrown when a problem occurs during option parsing. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public abstract class OptionException extends RuntimeException { + private static final long serialVersionUID = -1L; + + private final List<String> options = new ArrayList<>(); + + protected OptionException( List<String> options ) { + this.options.addAll( options ); + } + + protected OptionException( Collection<? extends OptionSpec<?>> options ) { + this.options.addAll( specsToStrings( options ) ); + } + + protected OptionException( Collection<? extends OptionSpec<?>> options, Throwable cause ) { + super( cause ); + this.options.addAll( specsToStrings( options ) ); + } + + private List<String> specsToStrings( Collection<? extends OptionSpec<?>> options ) { + List<String> strings = new ArrayList<>(); + for ( OptionSpec<?> each : options ) + strings.add( specToString( each ) ); + return strings; + } + + private String specToString( OptionSpec<?> option ) { + return Strings.join( new ArrayList<>( option.options() ), "/" ); + } + + /** + * Gives the option being considered when the exception was created. + * + * @return the option being considered when the exception was created + */ + public List<String> options() { + return unmodifiableList( options ); + } + + protected final String singleOptionString() { + return singleOptionString( options.get( 0 ) ); + } + + protected final String singleOptionString( String option ) { + return option; + } + + protected final String multipleOptionString() { + StringBuilder buffer = new StringBuilder( "[" ); + + Set<String> asSet = new LinkedHashSet<String>( options ); + for ( Iterator<String> iter = asSet.iterator(); iter.hasNext(); ) { + buffer.append( singleOptionString(iter.next()) ); + if ( iter.hasNext() ) + buffer.append( ", " ); + } + + buffer.append( ']' ); + + return buffer.toString(); + } + + static OptionException unrecognizedOption( String option ) { + return new UnrecognizedOptionException( option ); + } + + @Override + public final String getMessage() { + return localizedMessage( Locale.getDefault() ); + } + + final String localizedMessage( Locale locale ) { + return formattedMessage( locale ); + } + + private String formattedMessage( Locale locale ) { + return message( locale, "joptsimple.ExceptionMessages", getClass(), "message", messageArguments() ); + } + + abstract Object[] messageArguments(); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionMissingRequiredArgumentException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionMissingRequiredArgumentException.java new file mode 100644 index 0000000000..9c69f12369 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionMissingRequiredArgumentException.java @@ -0,0 +1,46 @@ +/* + 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 static java.util.Arrays.*; + +/** + * Thrown when the option parser discovers options that require an argument, but are missing an argument. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class OptionMissingRequiredArgumentException extends OptionException { + private static final long serialVersionUID = -1L; + + OptionMissingRequiredArgumentException( OptionSpec<?> option ) { + super( asList( option ) ); + } + + @Override + Object[] messageArguments() { + return new Object[] { singleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParser.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParser.java new file mode 100644 index 0000000000..d141f623c0 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParser.java @@ -0,0 +1,647 @@ +/* + 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 ) ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParserState.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParserState.java new file mode 100644 index 0000000000..fe1000c263 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionParserState.java @@ -0,0 +1,76 @@ +/* + 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 static joptsimple.ParserRules.*; + +/** + * Abstraction of parser state; mostly serves to model how a parser behaves depending on whether end-of-options + * has been detected. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +abstract class OptionParserState { + static OptionParserState noMoreOptions() { + return new OptionParserState() { + @Override + protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + parser.handleNonOptionArgument( arguments.next(), arguments, detectedOptions ); + } + }; + } + + static OptionParserState moreOptions( final boolean posixlyCorrect ) { + return new OptionParserState() { + @Override + protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + String candidate = arguments.next(); + try { + if ( isOptionTerminator( candidate ) ) { + parser.noMoreOptions(); + return; + } else if ( isLongOptionToken( candidate ) ) { + parser.handleLongOptionToken( candidate, arguments, detectedOptions ); + return; + } else if ( isShortOptionToken( candidate ) ) { + parser.handleShortOptionToken( candidate, arguments, detectedOptions ); + return; + } + } catch ( UnrecognizedOptionException e ) { + if ( !parser.doesAllowsUnrecognizedOptions() ) + throw e; + } + + if ( posixlyCorrect ) + parser.noMoreOptions(); + + parser.handleNonOptionArgument( candidate, arguments, detectedOptions ); + } + }; + } + + protected abstract void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSet.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSet.java new file mode 100644 index 0000000000..e67363fd2e --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSet.java @@ -0,0 +1,325 @@ +/* + 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.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.*; +import static java.util.Objects.*; + +/** + * Representation of a group of detected command line options, their arguments, and non-option arguments. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class OptionSet { + private final List<OptionSpec<?>> detectedSpecs; + private final Map<String, AbstractOptionSpec<?>> detectedOptions; + private final Map<AbstractOptionSpec<?>, List<String>> optionsToArguments; + private final Map<String, AbstractOptionSpec<?>> recognizedSpecs; + private final Map<String, List<?>> defaultValues; + + /* + * Package-private because clients don't create these. + */ + OptionSet( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) { + detectedSpecs = new ArrayList<>(); + detectedOptions = new HashMap<>(); + optionsToArguments = new IdentityHashMap<>(); + defaultValues = defaultValues( recognizedSpecs ); + this.recognizedSpecs = recognizedSpecs; + } + + /** + * Tells whether any options were detected. + * + * @return {@code true} if any options were detected + */ + public boolean hasOptions() { + return !( detectedOptions.size() == 1 && detectedOptions.values().iterator().next().representsNonOptions() ); + } + + /** + * Tells whether the given option was detected. + * + * @param option the option to search for + * @return {@code true} if the option was detected + * @see #has(OptionSpec) + */ + public boolean has( String option ) { + return detectedOptions.containsKey( option ); + } + + /** + * Tells whether the given option was detected. + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[])} default argument value} + * for an option does not cause this method to return {@code true} if the option was not detected on the command + * line.</p> + * + * @param option the option to search for + * @return {@code true} if the option was detected + * @see #has(String) + */ + public boolean has( OptionSpec<?> option ) { + return optionsToArguments.containsKey( option ); + } + + /** + * Tells whether there are any arguments associated with the given option. + * + * @param option the option to search for + * @return {@code true} if the option was detected and at least one argument was detected for the option + * @see #hasArgument(OptionSpec) + */ + public boolean hasArgument( String option ) { + AbstractOptionSpec<?> spec = detectedOptions.get( option ); + return spec != null && hasArgument( spec ); + } + + /** + * Tells whether there are any arguments associated with the given option. + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for an option does not cause this method to return {@code true} if the option was not detected on the command + * line, or if the option can take an optional argument but did not have one on the command line.</p> + * + * @param option the option to search for + * @return {@code true} if the option was detected and at least one argument was detected for the option + * @throws NullPointerException if {@code option} is {@code null} + * @see #hasArgument(String) + */ + public boolean hasArgument( OptionSpec<?> option ) { + requireNonNull( option ); + + List<String> values = optionsToArguments.get( option ); + return values != null && !values.isEmpty(); + } + + /** + * Gives the argument associated with the given option. If the option was given an argument type, the argument + * will take on that type; otherwise, it will be a {@link String}. + * + * <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for an option will cause this method to return that default value even if the option was not detected on the + * command line, or if the option can take an optional argument but did not have one on the command line.</p> + * + * @param option the option to search for + * @return the argument of the given option; {@code null} if no argument is present, or that option was not + * detected + * @throws NullPointerException if {@code option} is {@code null} + * @throws OptionException if more than one argument was detected for the option + */ + public Object valueOf( String option ) { + requireNonNull( option ); + + AbstractOptionSpec<?> spec = detectedOptions.get( option ); + if ( spec == null ) { + List<?> defaults = defaultValuesFor( option ); + return defaults.isEmpty() ? null : defaults.get( 0 ); + } + + return valueOf( spec ); + } + + /** + * Gives the argument associated with the given option. + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param <V> represents the type of the arguments the given option accepts + * @param option the option to search for + * @return the argument of the given option; {@code null} if no argument is present, or that option was not + * detected + * @throws OptionException if more than one argument was detected for the option + * @throws NullPointerException if {@code option} is {@code null} + * @throws ClassCastException if the arguments of this option are not of the expected type + */ + public <V> V valueOf( OptionSpec<V> option ) { + requireNonNull( option ); + + List<V> values = valuesOf( option ); + switch ( values.size() ) { + case 0: + return null; + case 1: + return values.get( 0 ); + default: + throw new MultipleArgumentsForOptionException( option ); + } + } + + /** + * <p>Gives any arguments associated with the given option. If the option was given an argument type, the + * arguments will take on that type; otherwise, they will be {@link String}s.</p> + * + * @param option the option to search for + * @return the arguments associated with the option, as a list of objects of the type given to the arguments; an + * empty list if no such arguments are present, or if the option was not detected + * @throws NullPointerException if {@code option} is {@code null} + */ + public List<?> valuesOf( String option ) { + requireNonNull( option ); + + AbstractOptionSpec<?> spec = detectedOptions.get( option ); + return spec == null ? defaultValuesFor( option ) : valuesOf( spec ); + } + + /** + * <p>Gives any arguments associated with the given option. If the option was given an argument type, the + * arguments will take on that type; otherwise, they will be {@link String}s.</p> + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param <V> represents the type of the arguments the given option accepts + * @param option the option to search for + * @return the arguments associated with the option; an empty list if no such arguments are present, or if the + * option was not detected + * @throws NullPointerException if {@code option} is {@code null} + * @throws OptionException if there is a problem converting the option's arguments to the desired type; for + * example, if the type does not implement a correct conversion constructor or method + */ + public <V> List<V> valuesOf( OptionSpec<V> option ) { + requireNonNull( option ); + + List<String> values = optionsToArguments.get( option ); + if ( values == null || values.isEmpty() ) + return defaultValueFor( option ); + + AbstractOptionSpec<V> spec = (AbstractOptionSpec<V>) option; + List<V> convertedValues = new ArrayList<>(); + for ( String each : values ) + convertedValues.add( spec.convert( each ) ); + + return unmodifiableList( convertedValues ); + } + + /** + * Gives the set of options that were detected, in the form of {@linkplain OptionSpec}s, in the order in which the + * options were found on the command line. + * + * @return the set of detected command line options + */ + public List<OptionSpec<?>> specs() { + List<OptionSpec<?>> specs = detectedSpecs; + specs.removeAll( singletonList( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) ); + + return unmodifiableList( specs ); + } + + /** + * Gives all declared options as a map of string to {@linkplain OptionSpec}. + * + * @return the declared options as a map + */ + public Map<OptionSpec<?>, List<?>> asMap() { + Map<OptionSpec<?>, List<?>> map = new HashMap<>(); + + for ( AbstractOptionSpec<?> spec : recognizedSpecs.values() ) { + if ( !spec.representsNonOptions() ) + map.put( spec, valuesOf( spec ) ); + } + + return unmodifiableMap( map ); + } + + /** + * @return the detected non-option arguments + */ + public List<?> nonOptionArguments() { + AbstractOptionSpec<?> spec = detectedOptions.get( NonOptionArgumentSpec.NAME ); + return valuesOf( spec ); + } + + void add( AbstractOptionSpec<?> spec ) { + addWithArgument( spec, null ); + } + + void addWithArgument( AbstractOptionSpec<?> spec, String argument ) { + detectedSpecs.add( spec ); + + for ( String each : spec.options() ) + detectedOptions.put( each, spec ); + + List<String> optionArguments = optionsToArguments.get( spec ); + + if ( optionArguments == null ) { + optionArguments = new ArrayList<>(); + optionsToArguments.put( spec, optionArguments ); + } + + if ( argument != null ) + optionArguments.add( argument ); + } + + @Override + public boolean equals( Object that ) { + if ( this == that ) + return true; + + if ( that == null || !getClass().equals( that.getClass() ) ) + return false; + + OptionSet other = (OptionSet) that; + Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments ); + Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments = new HashMap<>( other.optionsToArguments ); + return detectedOptions.equals( other.detectedOptions ) + && thisOptionsToArguments.equals( otherOptionsToArguments ); + } + + @Override + public int hashCode() { + Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments ); + return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode(); + } + + @SuppressWarnings( "unchecked" ) + private <V> List<V> defaultValuesFor( String option ) { + if ( defaultValues.containsKey( option ) ) + return unmodifiableList( (List<V>) defaultValues.get( option ) ); + + return emptyList(); + } + + private <V> List<V> defaultValueFor( OptionSpec<V> option ) { + return defaultValuesFor( option.options().iterator().next() ); + } + + private static Map<String, List<?>> defaultValues( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) { + Map<String, List<?>> defaults = new HashMap<>(); + for ( Map.Entry<String, AbstractOptionSpec<?>> each : recognizedSpecs.entrySet() ) + defaults.put( each.getKey(), each.getValue().defaultValues() ); + return defaults; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpec.java new file mode 100644 index 0000000000..70d2d43072 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpec.java @@ -0,0 +1,97 @@ +/* + 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.util.List; + +/** + * Describes options that an option parser recognizes. + * + * <p>Instances of this interface are returned by the "fluent interface" methods to allow retrieval of option arguments + * in a type-safe manner. Here's an example:</p> + * + * <pre><code> + * OptionParser parser = new OptionParser(); + * <strong>OptionSpec<Integer></strong> count = + * parser.accepts( "count" ).withRequiredArg().ofType( Integer.class ); + * OptionSet options = parser.parse( "--count", "2" ); + * assert options.has( count ); + * int countValue = options.valueOf( count ); + * assert countValue == count.value( options ); + * List<Integer> countValues = options.valuesOf( count ); + * assert countValues.equals( count.values( options ) ); + * </code></pre> + * + * @param <V> represents the type of the arguments this option accepts + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public interface OptionSpec<V> { + /** + * Gives any arguments associated with the given option in the given set of detected options. + * + * <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for this option will cause this method to return that default value even if this option was not detected on the + * command line, or if this option can take an optional argument but did not have one on the command line.</p> + * + * @param detectedOptions the detected options to search in + * @return the arguments associated with this option; an empty list if no such arguments are present, or if this + * option was not detected + * @throws OptionException if there is a problem converting this option's arguments to the desired type; for + * example, if the type does not implement a correct conversion constructor or method + * @throws NullPointerException if {@code detectedOptions} is {@code null} + * @see OptionSet#valuesOf(OptionSpec) + */ + List<V> values( OptionSet detectedOptions ); + + /** + * Gives the argument associated with the given option in the given set of detected options. + * + * <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for this option will cause this method to return that default value even if this option was not detected on the + * command line, or if this option can take an optional argument but did not have one on the command line.</p> + * + * @param detectedOptions the detected options to search in + * @return the argument of the this option; {@code null} if no argument is present, or that option was not detected + * @throws OptionException if more than one argument was detected for the option + * @throws NullPointerException if {@code detectedOptions} is {@code null} + * @throws ClassCastException if the arguments of this option are not of the expected type + * @see OptionSet#valueOf(OptionSpec) + */ + V value( OptionSet detectedOptions ); + + /** + * @return the string representations of this option + */ + List<String> options(); + + /** + * Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line + * means that missing "required" options will not cause parsing to fail. + * + * @return whether this option is designated as a "help" option + */ + boolean isForHelp(); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecBuilder.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecBuilder.java new file mode 100644 index 0000000000..fd5a15a1d6 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecBuilder.java @@ -0,0 +1,275 @@ +/* + 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.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Allows callers to specify whether a given option accepts arguments (required or optional). + * + * <p>Instances are returned from {@link OptionParser#accepts(String)} to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:</p> + * + * <pre><code> + * OptionParser parser = new OptionParser(); + * parser.accepts( "c" ).<strong>withRequiredArg()</strong>.ofType( Integer.class ); + * </code></pre> + * + * <p>If no methods are invoked on an instance of this class, then that instance's option will accept no argument.</p> + * + * <p>Note that you should not use the fluent interface clauses in a way that would defeat the typing of option + * arguments:</p> + * + * <pre><code> + * OptionParser parser = new OptionParser(); + * ArgumentAcceptingOptionSpec<String> optionC = + * parser.accepts( "c" ).withRequiredArg(); + * <strong>optionC.ofType( Integer.class ); // DON'T THROW AWAY THE TYPE!</strong> + * + * String value = parser.parse( "-c", "2" ).valueOf( optionC ); // ClassCastException + * </code></pre> + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class OptionSpecBuilder extends NoArgumentOptionSpec { + private final OptionParser parser; + + OptionSpecBuilder( OptionParser parser, List<String> options, String description ) { + super( options, description ); + + this.parser = parser; + attachToParser(); + } + + private void attachToParser() { + parser.recognize( this ); + } + + /** + * Informs an option parser that this builder's option requires an argument. + * + * @return a specification for the option + */ + public ArgumentAcceptingOptionSpec<String> withRequiredArg() { + ArgumentAcceptingOptionSpec<String> newSpec = new RequiredArgumentOptionSpec<>( options(), description() ); + parser.recognize( newSpec ); + + return newSpec; + } + + /** + * Informs an option parser that this builder's option accepts an optional argument. + * + * @return a specification for the option + */ + public ArgumentAcceptingOptionSpec<String> withOptionalArg() { + ArgumentAcceptingOptionSpec<String> newSpec = + new OptionalArgumentOptionSpec<>( options(), description() ); + parser.recognize( newSpec ); + + return newSpec; + } + + /** + * <p>Informs an option parser that this builder's option is required if the given option is present on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #requiredUnless(String, String...) + * requiredUnless} to avoid conflicts.</p> + * + * @param dependent an option whose presence on a command line makes this builder's option required + * @param otherDependents other options whose presence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) { + List<String> dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) + parser.requiredIf( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is required if the given option is present on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #requiredUnless(OptionSpec, OptionSpec[]) + * requiredUnless} to avoid conflicts.</p> + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param dependent the option whose presence on a command line makes this builder's option required + * @param otherDependents other options whose presence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder requiredIf( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) { + parser.requiredIf( options(), dependent ); + for ( OptionSpec<?> each : otherDependents ) + parser.requiredIf( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is required if the given option is absent on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #requiredIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.</p> + * + * @param dependent an option whose absence on a command line makes this builder's option required + * @param otherDependents other options whose absence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder requiredUnless( String dependent, String... otherDependents ) { + List<String> dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) { + parser.requiredUnless( options(), each ); + } + return this; + } + + /** + * <p>Informs an option parser that this builder's option is required if the given option is absent on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #requiredIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.</p> + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param dependent the option whose absence on a command line makes this builder's option required + * @param otherDependents other options whose absence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder requiredUnless( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) { + parser.requiredUnless( options(), dependent ); + for ( OptionSpec<?> each : otherDependents ) + parser.requiredUnless( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is allowed if the given option is present on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #availableUnless(String, String...) + * availableUnless} to avoid conflicts.</p> + * + * @param dependent an option whose presence on a command line makes this builder's option allowed + * @param otherDependents other options whose presence on a command line makes this builder's option allowed + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder availableIf( String dependent, String... otherDependents ) { + List<String> dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) + parser.availableIf( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is allowed if the given option is present on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #availableUnless(OptionSpec, OptionSpec[]) + * requiredUnless} to avoid conflicts.</p> + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param dependent the option whose presence on a command line makes this builder's option allowed + * @param otherDependents other options whose presence on a command line makes this builder's option allowed + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder availableIf( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) { + parser.availableIf( options(), dependent ); + + for ( OptionSpec<?> each : otherDependents ) + parser.availableIf( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is allowed if the given option is absent on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #availableIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.</p> + * + * @param dependent an option whose absence on a command line makes this builder's option allowed + * @param otherDependents other options whose absence on a command line makes this builder's option allowed + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder availableUnless( String dependent, String... otherDependents ) { + List<String> dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) + parser.availableUnless( options(), each ); + + return this; + } + + /** + * <p>Informs an option parser that this builder's option is allowed if the given option is absent on the command + * line.</p> + * + * <p>For a given option, you <em>should not</em> mix this with {@link #availableIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.</p> + * + * <p>This method recognizes only instances of options returned from the fluent interface methods.</p> + * + * @param dependent the option whose absence on a command line makes this builder's option allowed + * @param otherDependents other options whose absence on a command line makes this builder's option allowed + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder availableUnless( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) { + parser.availableUnless( options(), dependent ); + for ( OptionSpec<?> each : otherDependents ) + parser.availableUnless(options(), each); + + return this; + } + + private List<String> validatedDependents( String dependent, String... otherDependents ) { + List<String> dependents = new ArrayList<>(); + dependents.add( dependent ); + Collections.addAll( dependents, otherDependents ); + + for ( String each : dependents ) { + if ( !parser.isRecognized( each ) ) + throw new UnconfiguredOptionException( each ); + } + + return dependents; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecTokenizer.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecTokenizer.java new file mode 100644 index 0000000000..f9e4606c0c --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionSpecTokenizer.java @@ -0,0 +1,126 @@ +/* + 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.util.NoSuchElementException; + +import static joptsimple.ParserRules.*; + +/** + * Tokenizes a short option specification string. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class OptionSpecTokenizer { + private static final char POSIXLY_CORRECT_MARKER = '+'; + private static final char HELP_MARKER = '*'; + + private String specification; + private int index; + + OptionSpecTokenizer( String specification ) { + if ( specification == null ) + throw new NullPointerException( "null option specification" ); + + this.specification = specification; + } + + boolean hasMore() { + return index < specification.length(); + } + + AbstractOptionSpec<?> next() { + if ( !hasMore() ) + throw new NoSuchElementException(); + + + String optionCandidate = String.valueOf( specification.charAt( index ) ); + index++; + + AbstractOptionSpec<?> spec; + if ( RESERVED_FOR_EXTENSIONS.equals( optionCandidate ) ) { + spec = handleReservedForExtensionsToken(); + + if ( spec != null ) + return spec; + } + + ensureLegalOption( optionCandidate ); + + if ( hasMore() ) { + boolean forHelp = false; + if ( specification.charAt( index ) == HELP_MARKER ) { + forHelp = true; + ++index; + } + spec = hasMore() && specification.charAt( index ) == ':' + ? handleArgumentAcceptingOption( optionCandidate ) + : new NoArgumentOptionSpec( optionCandidate ); + if ( forHelp ) + spec.forHelp(); + } else + spec = new NoArgumentOptionSpec( optionCandidate ); + + return spec; + } + + void configure( OptionParser parser ) { + adjustForPosixlyCorrect( parser ); + + while ( hasMore() ) + parser.recognize( next() ); + } + + private void adjustForPosixlyCorrect( OptionParser parser ) { + if ( POSIXLY_CORRECT_MARKER == specification.charAt( 0 ) ) { + parser.posixlyCorrect( true ); + specification = specification.substring( 1 ); + } + } + + private AbstractOptionSpec<?> handleReservedForExtensionsToken() { + if ( !hasMore() ) + return new NoArgumentOptionSpec( RESERVED_FOR_EXTENSIONS ); + + if ( specification.charAt( index ) == ';' ) { + ++index; + return new AlternativeLongOptionSpec(); + } + + return null; + } + + private AbstractOptionSpec<?> handleArgumentAcceptingOption( String candidate ) { + index++; + + if ( hasMore() && specification.charAt( index ) == ':' ) { + index++; + return new OptionalArgumentOptionSpec<String>( candidate ); + } + + return new RequiredArgumentOptionSpec<String>( candidate ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/OptionalArgumentOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionalArgumentOptionSpec.java new file mode 100644 index 0000000000..cd641ed580 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/OptionalArgumentOptionSpec.java @@ -0,0 +1,69 @@ +/* + 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.util.List; + +/** + * Specification of an option that accepts an optional argument. + * + * @param <V> represents the type of the arguments this option accepts + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class OptionalArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> { + OptionalArgumentOptionSpec( String option ) { + super( option, false ); + } + + OptionalArgumentOptionSpec( List<String> options, String description ) { + super( options, false, description ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( arguments.hasMore() ) { + String nextArgument = arguments.peek(); + + if ( !parser.looksLikeAnOption( nextArgument ) && canConvertArgument( nextArgument ) ) + handleOptionArgument( parser, detectedOptions, arguments ); + else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) ) + addArguments( detectedOptions, arguments.next() ); + else + detectedOptions.add( this ); + } + else + detectedOptions.add( this ); + } + + private void handleOptionArgument( OptionParser parser, OptionSet detectedOptions, ArgumentList arguments ) { + if ( parser.posixlyCorrect() ) { + detectedOptions.add( this ); + parser.noMoreOptions(); + } + else + addArguments( detectedOptions, arguments.next() ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/ParserRules.java b/third_party/java/jopt-simple/src/main/java/joptsimple/ParserRules.java new file mode 100644 index 0000000000..34ef7814d5 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/ParserRules.java @@ -0,0 +1,84 @@ +/* + 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.util.List; + +import static java.lang.Character.*; + +/** + * Can tell whether or not options are well-formed. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +final class ParserRules { + static final char HYPHEN_CHAR = '-'; + static final String HYPHEN = String.valueOf( HYPHEN_CHAR ); + static final String DOUBLE_HYPHEN = "--"; + static final String OPTION_TERMINATOR = DOUBLE_HYPHEN; + static final String RESERVED_FOR_EXTENSIONS = "W"; + + private ParserRules() { + throw new UnsupportedOperationException(); + } + + static boolean isShortOptionToken( String argument ) { + return argument.startsWith( HYPHEN ) + && !HYPHEN.equals( argument ) + && !isLongOptionToken( argument ); + } + + static boolean isLongOptionToken( String argument ) { + return argument.startsWith( DOUBLE_HYPHEN ) && !isOptionTerminator( argument ); + } + + static boolean isOptionTerminator( String argument ) { + return OPTION_TERMINATOR.equals( argument ); + } + + static void ensureLegalOption( String option ) { + if ( option.startsWith( HYPHEN ) ) + throw new IllegalOptionSpecificationException( String.valueOf( option ) ); + + for ( int i = 0; i < option.length(); ++i ) + ensureLegalOptionCharacter( option.charAt( i ) ); + } + + static void ensureLegalOptions( List<String> options ) { + for ( String each : options ) + ensureLegalOption( each ); + } + + private static void ensureLegalOptionCharacter( char option ) { + if ( !( isLetterOrDigit( option ) || isAllowedPunctuation( option ) ) ) + throw new IllegalOptionSpecificationException( String.valueOf( option ) ); + } + + private static boolean isAllowedPunctuation( char option ) { + String allowedPunctuation = "?._" + HYPHEN_CHAR; + return allowedPunctuation.indexOf( option ) != -1; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/RequiredArgumentOptionSpec.java b/third_party/java/jopt-simple/src/main/java/joptsimple/RequiredArgumentOptionSpec.java new file mode 100644 index 0000000000..4c7ab880c7 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/RequiredArgumentOptionSpec.java @@ -0,0 +1,52 @@ +/* + 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.util.List; + +/** + * Specification of an option that accepts a required argument. + * + * @param <V> represents the type of the arguments this option accepts + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class RequiredArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> { + RequiredArgumentOptionSpec( String option ) { + super( option, true ); + } + + RequiredArgumentOptionSpec( List<String> options, String description ) { + super( options, true, description ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( !arguments.hasMore() ) + throw new OptionMissingRequiredArgumentException( this ); + + addArguments( detectedOptions, arguments.next() ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/UnavailableOptionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/UnavailableOptionException.java new file mode 100644 index 0000000000..b1fa0e3a1e --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/UnavailableOptionException.java @@ -0,0 +1,45 @@ +/* + 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.util.List; + +/** + * Thrown when options marked as allowed are specified on the command line, but the options they depend upon are + * present/not present. + */ +class UnavailableOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + UnavailableOptionException( List<? extends OptionSpec<?>> forbiddenOptions ) { + super( forbiddenOptions ); + } + + @Override + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/UnconfiguredOptionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/UnconfiguredOptionException.java new file mode 100644 index 0000000000..f62d88bd4a --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/UnconfiguredOptionException.java @@ -0,0 +1,52 @@ +/* + 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.util.List; + +import static java.util.Collections.*; + +/** + * Thrown when an option parser refers to an option that is not in fact configured already on the parser. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class UnconfiguredOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + UnconfiguredOptionException( String option ) { + this( singletonList( option ) ); + } + + UnconfiguredOptionException( List<String> options ) { + super( options ); + } + + @Override + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/UnrecognizedOptionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/UnrecognizedOptionException.java new file mode 100644 index 0000000000..73e7d74a0b --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/UnrecognizedOptionException.java @@ -0,0 +1,46 @@ +/* + 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 static java.util.Collections.*; + +/** + * Thrown when the option parser encounters an unrecognized option. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class UnrecognizedOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + UnrecognizedOptionException( String option ) { + super( singletonList( option ) ); + } + + @Override + Object[] messageArguments() { + return new Object[] { singleOptionString() }; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConversionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConversionException.java new file mode 100644 index 0000000000..50d575d194 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConversionException.java @@ -0,0 +1,54 @@ +/* + 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; + +/** + * Thrown by {@link ValueConverter}s when problems occur in converting string values to other Java types. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class ValueConversionException extends RuntimeException { + private static final long serialVersionUID = -1L; + + /** + * Creates a new exception with the specified detail message. + * + * @param message the detail message + */ + public ValueConversionException( String message ) { + this( message, null ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message the detail message + * @param cause the original exception + */ + public ValueConversionException( String message, Throwable cause ) { + super( message, cause ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConverter.java new file mode 100644 index 0000000000..bc968da2d8 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/ValueConverter.java @@ -0,0 +1,58 @@ +/* + 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; + +/** + * Instances of this interface are used to convert arguments of options into specific Java types. + * + * @param <V> constraint on the type of values being converted to + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public interface ValueConverter<V> { + /** + * Converts the given string value into a Java type. + * + * @param value the string to convert + * @return the converted value + * @throws ValueConversionException if a problem occurs while converting the value + */ + V convert( String value ); + + /** + * Gives the class of the type of values this converter converts to. + * + * @return the target class for conversion + */ + Class<? extends V> valueType(); + + /** + * Gives a string that describes the pattern of the values this converter expects, if any. For example, a date + * converter can respond with a {@link java.text.SimpleDateFormat date format string}. + * + * @return a value pattern, or {@code null} if there's nothing interesting here + */ + String valuePattern(); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/AbbreviationMap.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/AbbreviationMap.java new file mode 100644 index 0000000000..0d601839a5 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/AbbreviationMap.java @@ -0,0 +1,242 @@ +/* + 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.internal; + +import java.util.Map; +import java.util.TreeMap; + +/** + * <p>A map whose keys are strings; when a key/value pair is added to the map, the longest unique abbreviations of that + * key are added as well, and associated with the value. Thus:</p> + * + * <pre> + * <code> + * abbreviations.put( "good", "bye" ); + * </code> + * </pre> + * + * <p>would make it such that you could retrieve the value {@code "bye"} from the map using the keys {@code "good"}, + * {@code "goo"}, {@code "go"}, and {@code "g"}. A subsequent invocation of:</p> + * <pre> + * <code> + * abbreviations.put( "go", "fish" ); + * </code> + * </pre> + * + * <p>would make it such that you could retrieve the value {@code "bye"} using the keys {@code "good"} and + * {@code "goo"}, and the value {@code "fish"} using the key {@code "go"}. The key {@code "g"} would yield + * {@code null}, since it would no longer be a unique abbreviation.</p> + * + * <p>The data structure is much like a "trie".</p> + * + * @param <V> a constraint on the types of the values in the map + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + * @see <a href="http://perldoc.perl.org/Text/Abbrev.html">Perl's Text::Abbrev module</a> + * @see <a href="https://en.wikipedia.org/wiki/Radix_tree">Radix tree</a> + */ +public class AbbreviationMap<V> implements OptionNameMap<V> { + private final Map<Character, AbbreviationMap<V>> children = new TreeMap<>(); + + private String key; + private V value; + private int keysBeyond; + + /** + * <p>Tells whether the given key is in the map, or whether the given key is a unique + * abbreviation of a key that is in the map.</p> + * + * @param key key to look up + * @return {@code true} if {@code key} is present in the map + * @throws NullPointerException if {@code key} is {@code null} + */ + @Override + public boolean contains(String key) { + return get(key) != null; + } + + /** + * <p>Answers the value associated with the given key. The key can be a unique + * abbreviation of a key that is in the map. </p> + * + * @param key key to look up + * @return the value associated with {@code aKey}; or {@code null} if there is no + * such value or {@code aKey} is not a unique abbreviation of a key in the map + * @throws NullPointerException if {@code aKey} is {@code null} + */ + @Override + public V get( String key ) { + char[] chars = charsOf( key ); + + AbbreviationMap<V> child = this; + for ( char each : chars ) { + child = child.children.get( each ); + if ( child == null ) + return null; + } + + return child.value; + } + + /** + * <p>Associates a given value with a given key. If there was a previous + * association, the old value is replaced with the new one.</p> + * + * @param key key to create in the map + * @param newValue value to associate with the key + * @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null} + * @throws IllegalArgumentException if {@code aKey} is a zero-length string + */ + @Override + public void put( String key, V newValue ) { + if ( newValue == null ) + throw new NullPointerException(); + if ( key.length() == 0 ) + throw new IllegalArgumentException(); + + char[] chars = charsOf(key); + add( chars, newValue, 0, chars.length ); + } + + /** + * <p>Associates a given value with a given set of keys. If there was a previous + * association, the old value is replaced with the new one.</p> + * + * @param keys keys to create in the map + * @param newValue value to associate with the key + * @throws NullPointerException if {@code keys} or {@code newValue} is {@code null} + * @throws IllegalArgumentException if any of {@code keys} is a zero-length string + */ + @Override + public void putAll( Iterable<String> keys, V newValue ) { + for ( String each : keys ) + put( each, newValue ); + } + + private boolean add( char[] chars, V newValue, int offset, int length ) { + if ( offset == length ) { + value = newValue; + boolean wasAlreadyAKey = key != null; + key = new String( chars ); + return !wasAlreadyAKey; + } + + char nextChar = chars[ offset ]; + AbbreviationMap<V> child = children.get( nextChar ); + if ( child == null ) { + child = new AbbreviationMap<>(); + children.put( nextChar, child ); + } + + boolean newKeyAdded = child.add( chars, newValue, offset + 1, length ); + + if ( newKeyAdded ) + ++keysBeyond; + + if ( key == null ) + value = keysBeyond > 1 ? null : newValue; + + return newKeyAdded; + } + + /** + * <p>If the map contains the given key, dissociates the key from its value.</p> + * + * @param key key to remove + * @throws NullPointerException if {@code aKey} is {@code null} + * @throws IllegalArgumentException if {@code aKey} is a zero-length string + */ + @Override + public void remove( String key ) { + if ( key.length() == 0 ) + throw new IllegalArgumentException(); + + char[] keyChars = charsOf(key); + remove( keyChars, 0, keyChars.length ); + } + + private boolean remove( char[] aKey, int offset, int length ) { + if ( offset == length ) + return removeAtEndOfKey(); + + char nextChar = aKey[ offset ]; + AbbreviationMap<V> child = children.get( nextChar ); + if ( child == null || !child.remove( aKey, offset + 1, length ) ) + return false; + + --keysBeyond; + if ( child.keysBeyond == 0 ) + children.remove( nextChar ); + if ( keysBeyond == 1 && key == null ) + setValueToThatOfOnlyChild(); + + return true; + } + + private void setValueToThatOfOnlyChild() { + Map.Entry<Character, AbbreviationMap<V>> entry = children.entrySet().iterator().next(); + AbbreviationMap<V> onlyChild = entry.getValue(); + value = onlyChild.value; + } + + private boolean removeAtEndOfKey() { + if ( key == null ) + return false; + + key = null; + if ( keysBeyond == 1 ) + setValueToThatOfOnlyChild(); + else + value = null; + + return true; + } + + /** + * Gives a Java map representation of this abbreviation map. + * + * @return a Java map corresponding to this abbreviation map + */ + @Override + public Map<String, V> toJavaUtilMap() { + Map<String, V> mappings = new TreeMap<>(); + addToMappings( mappings ); + return mappings; + } + + private void addToMappings( Map<String, V> mappings ) { + if ( key != null ) + mappings.put( key, value ); + + for ( AbbreviationMap<V> each : children.values() ) + each.addToMappings( mappings ); + } + + private static char[] charsOf( String aKey ) { + char[] chars = new char[ aKey.length() ]; + aKey.getChars( 0, aKey.length(), chars, 0 ); + return chars; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Classes.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Classes.java new file mode 100644 index 0000000000..f7030f88cb --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Classes.java @@ -0,0 +1,75 @@ +/* + 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.internal; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public final class Classes { + private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<>( 13 ); + + static { + WRAPPERS.put( boolean.class, Boolean.class ); + WRAPPERS.put( byte.class, Byte.class ); + WRAPPERS.put( char.class, Character.class ); + WRAPPERS.put( double.class, Double.class ); + WRAPPERS.put( float.class, Float.class ); + WRAPPERS.put( int.class, Integer.class ); + WRAPPERS.put( long.class, Long.class ); + WRAPPERS.put( short.class, Short.class ); + WRAPPERS.put( void.class, Void.class ); + } + + private Classes() { + throw new UnsupportedOperationException(); + } + + /** + * Gives the "short version" of the given class name. Somewhat naive to inner classes. + * + * @param className class name to chew on + * @return the short name of the class + */ + public static String shortNameOf( String className ) { + return className.substring( className.lastIndexOf( '.' ) + 1 ); + } + + /** + * Gives the primitive wrapper class for the given class. If the given class is not + * {@linkplain Class#isPrimitive() primitive}, returns the class itself. + * + * @param <T> generic class type + * @param clazz the class to check + * @return primitive wrapper type if {@code clazz} is primitive, otherwise {@code clazz} + */ + @SuppressWarnings( "unchecked" ) + public static <T> Class<T> wrapperOf( Class<T> clazz ) { + return clazz.isPrimitive() ? (Class<T>) WRAPPERS.get( clazz ) : clazz; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Columns.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Columns.java new file mode 100644 index 0000000000..a012b601f0 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Columns.java @@ -0,0 +1,106 @@ +/* + 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.internal; + +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.List; + +import static java.text.BreakIterator.*; + +import static joptsimple.internal.Strings.*; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class Columns { + private static final int INDENT_WIDTH = 2; + + private final int optionWidth; + private final int descriptionWidth; + + Columns( int optionWidth, int descriptionWidth ) { + this.optionWidth = optionWidth; + this.descriptionWidth = descriptionWidth; + } + + List<Row> fit( Row row ) { + List<String> options = piecesOf( row.option, optionWidth ); + List<String> descriptions = piecesOf( row.description, descriptionWidth ); + + List<Row> rows = new ArrayList<>(); + for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i ) + rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) ); + + return rows; + } + + private static String itemOrEmpty( List<String> items, int index ) { + return index >= items.size() ? "" : items.get( index ); + } + + private List<String> piecesOf( String raw, int width ) { + List<String> pieces = new ArrayList<>(); + + for ( String each : raw.trim().split( LINE_SEPARATOR ) ) + pieces.addAll( piecesOfEmbeddedLine( each, width ) ); + + return pieces; + } + + private List<String> piecesOfEmbeddedLine( String line, int width ) { + List<String> pieces = new ArrayList<>(); + + BreakIterator words = BreakIterator.getLineInstance(); + words.setText( line ); + + StringBuilder nextPiece = new StringBuilder(); + + int start = words.first(); + for ( int end = words.next(); end != DONE; start = end, end = words.next() ) + nextPiece = processNextWord( line, nextPiece, start, end, width, pieces ); + + if ( nextPiece.length() > 0 ) + pieces.add( nextPiece.toString() ); + + return pieces; + } + + private StringBuilder processNextWord( String source, StringBuilder nextPiece, int start, int end, int width, + List<String> pieces ) { + StringBuilder augmented = nextPiece; + + String word = source.substring( start, end ); + if ( augmented.length() + word.length() > width ) { + pieces.add( augmented.toString().replaceAll( "\\s+$", "" ) ); + augmented = new StringBuilder( repeat( ' ', INDENT_WIDTH ) ).append( word ); + } + else + augmented.append( word ); + + return augmented; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ConstructorInvokingValueConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ConstructorInvokingValueConverter.java new file mode 100644 index 0000000000..d3a641b57d --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ConstructorInvokingValueConverter.java @@ -0,0 +1,56 @@ +/* + 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.internal; + +import java.lang.reflect.Constructor; + +import joptsimple.ValueConverter; + +import static joptsimple.internal.Reflection.*; + +/** + * @param <V> constraint on the type of values being converted to + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class ConstructorInvokingValueConverter<V> implements ValueConverter<V> { + private final Constructor<V> ctor; + + ConstructorInvokingValueConverter( Constructor<V> ctor ) { + this.ctor = ctor; + } + + public V convert( String value ) { + return instantiate( ctor, value ); + } + + public Class<V> valueType() { + return ctor.getDeclaringClass(); + } + + public String valuePattern() { + return null; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Messages.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Messages.java new file mode 100644 index 0000000000..5bb71fc727 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Messages.java @@ -0,0 +1,47 @@ +/* + 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.internal; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class Messages { + private Messages() { + throw new UnsupportedOperationException(); + } + + public static String message( Locale locale, String bundleName, Class<?> type, String key, Object... args ) { + ResourceBundle bundle = ResourceBundle.getBundle( bundleName, locale ); + String template = bundle.getString( type.getName() + '.' + key ); + MessageFormat format = new MessageFormat( template ); + format.setLocale( locale ); + return format.format( args ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/MethodInvokingValueConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/MethodInvokingValueConverter.java new file mode 100644 index 0000000000..503d6778d8 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/MethodInvokingValueConverter.java @@ -0,0 +1,58 @@ +/* + 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.internal; + +import java.lang.reflect.Method; + +import joptsimple.ValueConverter; + +import static joptsimple.internal.Reflection.*; + +/** + * @param <V> constraint on the type of values being converted to + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class MethodInvokingValueConverter<V> implements ValueConverter<V> { + private final Method method; + private final Class<V> clazz; + + MethodInvokingValueConverter( Method method, Class<V> clazz ) { + this.method = method; + this.clazz = clazz; + } + + public V convert( String value ) { + return clazz.cast( invoke( method, value ) ); + } + + public Class<V> valueType() { + return clazz; + } + + public String valuePattern() { + return null; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/OptionNameMap.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/OptionNameMap.java new file mode 100644 index 0000000000..1b9e49197b --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/OptionNameMap.java @@ -0,0 +1,47 @@ +/* + 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.internal; + +import java.util.Map; + +/** + * Map-like interface for storing String-value pairs. + * + * @param <V> type of values stored in the map + */ +public interface OptionNameMap<V> { + boolean contains( String key ); + + V get( String key ); + + void put( String key, V newValue ); + + void putAll( Iterable<String> keys, V newValue ); + + void remove( String key ); + + Map<String, V> toJavaUtilMap(); +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Reflection.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Reflection.java new file mode 100644 index 0000000000..5dad882787 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Reflection.java @@ -0,0 +1,142 @@ +/* + 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.internal; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static java.lang.reflect.Modifier.*; + +import joptsimple.ValueConverter; + +import static joptsimple.internal.Classes.*; + +/** + * Helper methods for reflection. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public final class Reflection { + private Reflection() { + throw new UnsupportedOperationException(); + } + + /** + * Finds an appropriate value converter for the given class. + * + * @param <V> a constraint on the class object to introspect + * @param clazz class to introspect on + * @return a converter method or constructor + */ + public static <V> ValueConverter<V> findConverter( Class<V> clazz ) { + Class<V> maybeWrapper = wrapperOf( clazz ); + + ValueConverter<V> valueOf = valueOfConverter( maybeWrapper ); + if ( valueOf != null ) + return valueOf; + + ValueConverter<V> constructor = constructorConverter( maybeWrapper ); + if ( constructor != null ) + return constructor; + + throw new IllegalArgumentException( clazz + " is not a value type" ); + } + + private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) { + try { + Method valueOf = clazz.getMethod( "valueOf", String.class ); + if ( meetsConverterRequirements( valueOf, clazz ) ) + return new MethodInvokingValueConverter<>( valueOf, clazz ); + + return null; + } catch ( NoSuchMethodException ignored ) { + return null; + } + } + + private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) { + try { + return new ConstructorInvokingValueConverter<>( clazz.getConstructor( String.class ) ); + } catch ( NoSuchMethodException ignored ) { + return null; + } + } + + /** + * Invokes the given constructor with the given arguments. + * + * @param <T> constraint on the type of the objects yielded by the constructor + * @param constructor constructor to invoke + * @param args arguments to hand to the constructor + * @return the result of invoking the constructor + * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions + */ + public static <T> T instantiate( Constructor<T> constructor, Object... args ) { + try { + return constructor.newInstance( args ); + } catch ( Exception ex ) { + throw reflectionException( ex ); + } + } + + /** + * Invokes the given static method with the given arguments. + * + * @param method method to invoke + * @param args arguments to hand to the method + * @return the result of invoking the method + * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions + */ + public static Object invoke( Method method, Object... args ) { + try { + return method.invoke( null, args ); + } catch ( Exception ex ) { + throw reflectionException( ex ); + } + } + + @SuppressWarnings( "unchecked" ) + public static <V> V convertWith( ValueConverter<V> converter, String raw ) { + return converter == null ? (V) raw : converter.convert( raw ); + } + + private static boolean meetsConverterRequirements( Method method, Class<?> expectedReturnType ) { + int modifiers = method.getModifiers(); + return isPublic( modifiers ) && isStatic( modifiers ) && expectedReturnType.equals( method.getReturnType() ); + } + + private static RuntimeException reflectionException( Exception ex ) { + if ( ex instanceof IllegalArgumentException ) + return new ReflectionException( ex ); + if ( ex instanceof InvocationTargetException ) + return new ReflectionException( ex.getCause() ); + if ( ex instanceof RuntimeException ) + return (RuntimeException) ex; + + return new ReflectionException( ex ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ReflectionException.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ReflectionException.java new file mode 100644 index 0000000000..17cd4d6330 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/ReflectionException.java @@ -0,0 +1,39 @@ +/* + 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.internal; + +/** + * This unchecked exception wraps reflection-oriented exceptions. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class ReflectionException extends RuntimeException { + private static final long serialVersionUID = -2L; + + ReflectionException( Throwable cause ) { + super( cause ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Row.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Row.java new file mode 100644 index 0000000000..13d8e34905 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Row.java @@ -0,0 +1,55 @@ +/* + 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.internal; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +class Row { + final String option; + final String description; + + Row( String option, String description ) { + this.option = option; + this.description = description; + } + + @Override + public boolean equals( Object that ) { + if ( that == this ) + return true; + if ( that == null || !getClass().equals( that.getClass() ) ) + return false; + + Row other = (Row) that; + return option.equals( other.option ) && description.equals( other.description ); + } + + @Override + public int hashCode() { + return option.hashCode() ^ description.hashCode(); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Rows.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Rows.java new file mode 100644 index 0000000000..c2cae82ce4 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Rows.java @@ -0,0 +1,103 @@ +/* + 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.internal; + +import java.util.ArrayList; +import java.util.List; + +import static java.lang.Math.*; + +import static joptsimple.internal.Strings.*; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class Rows { + private final int overallWidth; + private final int columnSeparatorWidth; + private final List<Row> rows = new ArrayList<>(); + + private int widthOfWidestOption; + private int widthOfWidestDescription; + + public Rows( int overallWidth, int columnSeparatorWidth ) { + this.overallWidth = overallWidth; + this.columnSeparatorWidth = columnSeparatorWidth; + } + + public void add( String option, String description ) { + add( new Row( option, description ) ); + } + + private void add( Row row ) { + rows.add( row ); + widthOfWidestOption = max( widthOfWidestOption, row.option.length() ); + widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() ); + } + + public void reset() { + rows.clear(); + widthOfWidestOption = 0; + widthOfWidestDescription = 0; + } + + public void fitToWidth() { + Columns columns = new Columns( optionWidth(), descriptionWidth() ); + + List<Row> fitted = new ArrayList<>(); + for ( Row each : rows ) + fitted.addAll( columns.fit( each ) ); + + reset(); + + for ( Row each : fitted ) + add( each ); + } + + public String render() { + StringBuilder buffer = new StringBuilder(); + + for ( Row each : rows ) { + pad( buffer, each.option, optionWidth() ).append( repeat( ' ', columnSeparatorWidth ) ); + pad( buffer, each.description, descriptionWidth() ).append( LINE_SEPARATOR ); + } + + return buffer.toString(); + } + + private int optionWidth() { + return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestOption ); + } + + private int descriptionWidth() { + return min( overallWidth - optionWidth() - columnSeparatorWidth, widthOfWidestDescription ); + } + + private StringBuilder pad( StringBuilder buffer, String s, int length ) { + buffer.append( s ).append( repeat( ' ', length - s.length() ) ); + return buffer; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/SimpleOptionNameMap.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/SimpleOptionNameMap.java new file mode 100644 index 0000000000..69ad6b5c4c --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/SimpleOptionNameMap.java @@ -0,0 +1,67 @@ +/* + 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.internal; + +import java.util.HashMap; +import java.util.Map; + +/** + * <p>An {@code OptionNameMap} which wraps and behaves like {@code HashMap}.</p> + */ +public class SimpleOptionNameMap<V> implements OptionNameMap<V> { + private final Map<String, V> map = new HashMap<>(); + + @Override + public boolean contains( String key ) { + return map.containsKey( key ); + } + + @Override + public V get( String key ) { + return map.get( key ); + } + + @Override + public void put( String key, V newValue ) { + map.put( key, newValue ); + } + + @Override + public void putAll( Iterable<String> keys, V newValue ) { + for ( String each : keys ) + map.put( each, newValue ); + } + + @Override + public void remove( String key ) { + map.remove( key ); + } + + @Override + public Map<String, V> toJavaUtilMap() { + return new HashMap<>( map ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Strings.java b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Strings.java new file mode 100644 index 0000000000..50ea3e49ea --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/internal/Strings.java @@ -0,0 +1,115 @@ +/* + 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.internal; + +import java.util.Iterator; + +import static java.lang.System.*; +import static java.util.Arrays.*; + +/** + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public final class Strings { + public static final String EMPTY = ""; + public static final String LINE_SEPARATOR = getProperty( "line.separator" ); + + private Strings() { + throw new UnsupportedOperationException(); + } + + /** + * Gives a string consisting of the given character repeated the given number of times. + * + * @param ch the character to repeat + * @param count how many times to repeat the character + * @return the resultant string + */ + public static String repeat( char ch, int count ) { + StringBuilder buffer = new StringBuilder(); + + for ( int i = 0; i < count; ++i ) + buffer.append( ch ); + + return buffer.toString(); + } + + /** + * Tells whether the given string is either {@code} or consists solely of whitespace characters. + * + * @param target string to check + * @return {@code true} if the target string is null or empty + */ + public static boolean isNullOrEmpty( String target ) { + return target == null || target.isEmpty(); + } + + + /** + * Gives a string consisting of a given string prepended and appended with surrounding characters. + * + * @param target a string + * @param begin character to prepend + * @param end character to append + * @return the surrounded string + */ + public static String surround( String target, char begin, char end ) { + return begin + target + end; + } + + /** + * Gives a string consisting of the elements of a given array of strings, each separated by a given separator + * string. + * + * @param pieces the strings to join + * @param separator the separator + * @return the joined string + */ + public static String join( String[] pieces, String separator ) { + return join( asList( pieces ), separator ); + } + + /** + * Gives a string consisting of the string representations of the elements of a given array of objects, + * each separated by a given separator string. + * + * @param pieces the elements whose string representations are to be joined + * @param separator the separator + * @return the joined string + */ + public static String join( Iterable<String> pieces, String separator ) { + StringBuilder buffer = new StringBuilder(); + + for ( Iterator<String> iter = pieces.iterator(); iter.hasNext(); ) { + buffer.append( iter.next() ); + + if ( iter.hasNext() ) + buffer.append( separator ); + } + + return buffer.toString(); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/DateConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/DateConverter.java new file mode 100644 index 0000000000..c3182ae2fd --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/DateConverter.java @@ -0,0 +1,114 @@ +/* + 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.util; + +import java.text.DateFormat; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import joptsimple.ValueConversionException; +import joptsimple.ValueConverter; +import joptsimple.internal.Messages; + +/** + * Converts values to {@link Date}s using a {@link DateFormat} object. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class DateConverter implements ValueConverter<Date> { + private final DateFormat formatter; + + /** + * Creates a converter that uses the given date formatter/parser. + * + * @param formatter the formatter/parser to use + * @throws NullPointerException if {@code formatter} is {@code null} + */ + public DateConverter( DateFormat formatter ) { + if ( formatter == null ) + throw new NullPointerException( "illegal null formatter" ); + + this.formatter = formatter; + } + + /** + * Creates a converter that uses a {@link SimpleDateFormat} with the given date/time pattern. The date formatter + * created is not {@link SimpleDateFormat#setLenient(boolean) lenient}. + * + * @param pattern expected date/time pattern + * @return the new converter + * @throws NullPointerException if {@code pattern} is {@code null} + * @throws IllegalArgumentException if {@code pattern} is invalid + */ + public static DateConverter datePattern( String pattern ) { + SimpleDateFormat formatter = new SimpleDateFormat( pattern ); + formatter.setLenient( false ); + + return new DateConverter( formatter ); + } + + public Date convert( String value ) { + ParsePosition position = new ParsePosition( 0 ); + + Date date = formatter.parse( value, position ); + if ( position.getIndex() != value.length() ) + throw new ValueConversionException( message( value ) ); + + return date; + } + + public Class<Date> valueType() { + return Date.class; + } + + public String valuePattern() { + return formatter instanceof SimpleDateFormat + ? ( (SimpleDateFormat) formatter ).toPattern() + : ""; + } + + private String message( String value ) { + String key; + Object[] arguments; + + if ( formatter instanceof SimpleDateFormat ) { + key = "with.pattern.message"; + arguments = new Object[] { value, ( (SimpleDateFormat) formatter ).toPattern() }; + } else { + key = "without.pattern.message"; + arguments = new Object[] { value }; + } + + return Messages.message( + Locale.getDefault(), + "joptsimple.ExceptionMessages", + DateConverter.class, + key, + arguments ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/EnumConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/EnumConverter.java new file mode 100644 index 0000000000..c75b86607f --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/EnumConverter.java @@ -0,0 +1,104 @@ +/* + The MIT License + + Copyright (c) 2004-2014 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.util; + +import java.text.MessageFormat; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.ResourceBundle; + +import joptsimple.ValueConversionException; +import joptsimple.ValueConverter; + +/** + * Converts values to {@link java.lang.Enum}s. + * + * @author <a href="mailto:christian.ohr@gmail.com">Christian Ohr</a> + */ +public abstract class EnumConverter<E extends Enum<E>> implements ValueConverter<E> { + private final Class<E> clazz; + + private String delimiters = "[,]"; + + /** + * This constructor must be called by subclasses, providing the enum class as the parameter. + * + * @param clazz enum class + */ + protected EnumConverter( Class<E> clazz ) { + this.clazz = clazz; + } + + @Override + public E convert( String value ) { + for ( E each : valueType().getEnumConstants() ) { + if ( each.name().equalsIgnoreCase( value ) ) { + return each; + } + } + + throw new ValueConversionException( message( value ) ); + } + + @Override + public Class<E> valueType() { + return clazz; + } + + /** + * Sets the delimiters for the message string. Must be a 3-letter string, + * where the first character is the prefix, the second character is the + * delimiter between the values, and the 3rd character is the suffix. + * + * @param delimiters delimiters for message string. Default is [,] + */ + public void setDelimiters( String delimiters ) { + this.delimiters = delimiters; + } + + @Override + public String valuePattern() { + EnumSet<E> values = EnumSet.allOf( valueType() ); + + StringBuilder builder = new StringBuilder(); + builder.append( delimiters.charAt(0) ); + for ( Iterator<E> i = values.iterator(); i.hasNext(); ) { + builder.append( i.next().toString() ); + if ( i.hasNext() ) + builder.append( delimiters.charAt( 1 ) ); + } + builder.append( delimiters.charAt( 2 ) ); + + return builder.toString(); + } + + private String message( String value ) { + ResourceBundle bundle = ResourceBundle.getBundle( "joptsimple.ExceptionMessages" ); + Object[] arguments = new Object[] { value, valuePattern() }; + String template = bundle.getString( EnumConverter.class.getName() + ".message" ); + return new MessageFormat( template ).format( arguments ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/InetAddressConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/InetAddressConverter.java new file mode 100644 index 0000000000..2f116f810d --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/InetAddressConverter.java @@ -0,0 +1,67 @@ +/* + 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.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Locale; + +import joptsimple.ValueConversionException; +import joptsimple.ValueConverter; +import joptsimple.internal.Messages; + +/** + * Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}. + * + * @author <a href="mailto:r@ymund.de">Raymund F\u00FCl\u00F6p</a> + */ +public class InetAddressConverter implements ValueConverter<InetAddress> { + public InetAddress convert( String value ) { + try { + return InetAddress.getByName( value ); + } + catch ( UnknownHostException e ) { + throw new ValueConversionException( message( value ) ); + } + } + + public Class<InetAddress> valueType() { + return InetAddress.class; + } + + public String valuePattern() { + return null; + } + + private String message( String value ) { + return Messages.message( + Locale.getDefault(), + "joptsimple.ExceptionMessages", + InetAddressConverter.class, + "message", + value ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/KeyValuePair.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/KeyValuePair.java new file mode 100644 index 0000000000..bdc2424190 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/KeyValuePair.java @@ -0,0 +1,83 @@ +/* + 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.util; + +import static joptsimple.internal.Strings.*; + +/** + * <p>A simple string key/string value pair.</p> + * + * <p>This is useful as an argument type for options whose values take on the form {@code key=value}, such as JVM + * command line system properties.</p> + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public final class KeyValuePair { + public final String key; + public final String value; + + private KeyValuePair( String key, String value ) { + this.key = key; + this.value = value; + } + + /** + * Parses a string assumed to be of the form {@code key=value} into its parts. + * + * @param asString key-value string + * @return a key-value pair + * @throws NullPointerException if {@code stringRepresentation} is {@code null} + */ + public static KeyValuePair valueOf( String asString ) { + int equalsIndex = asString.indexOf( '=' ); + if ( equalsIndex == -1 ) + return new KeyValuePair( asString, EMPTY ); + + String aKey = asString.substring( 0, equalsIndex ); + String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 ); + + return new KeyValuePair( aKey, aValue ); + } + + @Override + public boolean equals( Object that ) { + if ( !( that instanceof KeyValuePair ) ) + return false; + + KeyValuePair other = (KeyValuePair) that; + return key.equals( other.key ) && value.equals( other.value ); + } + + @Override + public int hashCode() { + return key.hashCode() ^ value.hashCode(); + } + + @Override + public String toString() { + return key + '=' + value; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathConverter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathConverter.java new file mode 100644 index 0000000000..295bc00362 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathConverter.java @@ -0,0 +1,51 @@ +package joptsimple.util; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.ResourceBundle; + +import joptsimple.ValueConversionException; +import joptsimple.ValueConverter; + +/** + * Converts command line options to {@link Path} objects and checks the status of the underlying file. + */ +public class PathConverter implements ValueConverter<Path> { + private final PathProperties[] pathProperties; + + public PathConverter( PathProperties... pathProperties ) { + this.pathProperties = pathProperties; + } + + @Override + public Path convert( String value ) { + Path path = Paths.get(value); + + if ( pathProperties != null ) { + for ( PathProperties each : pathProperties ) { + if ( !each.accept( path ) ) + throw new ValueConversionException( message( each.getMessageKey(), path.toString() ) ); + } + } + + return path; + } + + @Override + public Class<Path> valueType() { + return Path.class; + } + + @Override + public String valuePattern() { + return null; + } + + private String message( String errorKey, String value ) { + ResourceBundle bundle = ResourceBundle.getBundle( "joptsimple.ExceptionMessages" ); + Object[] arguments = new Object[] { value, valuePattern() }; + String template = bundle.getString( PathConverter.class.getName() + "." + errorKey + ".message" ); + return new MessageFormat( template ).format( arguments ); + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathProperties.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathProperties.java new file mode 100644 index 0000000000..a7fb045025 --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/PathProperties.java @@ -0,0 +1,60 @@ +package joptsimple.util; + +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Enum for checking common conditions of files and directories. + * + * @see joptsimple.util.PathConverter + */ +public enum PathProperties { + FILE_EXISTING( "file.existing" ) { + @Override + boolean accept( Path path ) { + return Files.isRegularFile( path ); + } + }, + DIRECTORY_EXISTING( "directory.existing" ) { + @Override + boolean accept( Path path ) { + return Files.isDirectory( path ); + } + }, + NOT_EXISTING( "file.not.existing" ) { + @Override + boolean accept( Path path ) { + return Files.notExists( path ); + } + }, + FILE_OVERWRITABLE( "file.overwritable" ) { + @Override + boolean accept( Path path ) { + return FILE_EXISTING.accept( path ) && WRITABLE.accept( path ); + } + }, + READABLE( "file.readable" ) { + @Override + boolean accept( Path path ) { + return Files.isReadable( path ); + } + }, + WRITABLE( "file.writable" ) { + @Override + boolean accept( Path path ) { + return Files.isWritable( path ); + } + }; + + private final String messageKey; + + private PathProperties( String messageKey ) { + this.messageKey = messageKey; + } + + abstract boolean accept( Path path ); + + String getMessageKey() { + return messageKey; + } +} diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/util/RegexMatcher.java b/third_party/java/jopt-simple/src/main/java/joptsimple/util/RegexMatcher.java new file mode 100644 index 0000000000..aca788c7ec --- /dev/null +++ b/third_party/java/jopt-simple/src/main/java/joptsimple/util/RegexMatcher.java @@ -0,0 +1,95 @@ +/* + 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.util; + +import java.util.Locale; +import java.util.regex.Pattern; + +import static java.util.regex.Pattern.*; +import static joptsimple.internal.Messages.message; + +import joptsimple.ValueConversionException; +import joptsimple.ValueConverter; + +/** + * Ensures that values entirely match a regular expression. + * + * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> + */ +public class RegexMatcher implements ValueConverter<String> { + private final Pattern pattern; + + /** + * Creates a matcher that uses the given regular expression, modified by the given flags. + * + * @param pattern the regular expression pattern + * @param flags modifying regex flags + * @throws IllegalArgumentException if bit values other than those corresponding to the defined match flags are + * set in {@code flags} + * @throws java.util.regex.PatternSyntaxException if the expression's syntax is invalid + */ + public RegexMatcher( String pattern, int flags ) { + this.pattern = compile( pattern, flags ); + } + + /** + * Gives a matcher that uses the given regular expression. + * + * @param pattern the regular expression pattern + * @return the new converter + * @throws java.util.regex.PatternSyntaxException if the expression's syntax is invalid + */ + public static ValueConverter<String> regex( String pattern ) { + return new RegexMatcher( pattern, 0 ); + } + + public String convert( String value ) { + if ( !pattern.matcher( value ).matches() ) { + raiseValueConversionFailure( value ); + } + + return value; + } + + public Class<String> valueType() { + return String.class; + } + + public String valuePattern() { + return pattern.pattern(); + } + + private void raiseValueConversionFailure( String value ) { + String message = message( + Locale.getDefault(), + "joptsimple.ExceptionMessages", + RegexMatcher.class, + "message", + value, + pattern.pattern() ); + throw new ValueConversionException( message ); + } +} |