8203891: Upgrade JOpt Simple to 5.0.4

Reviewed-by: alanb, chegar, mchung
This commit is contained in:
Jan Lahoda 2018-06-06 15:36:29 +02:00
parent ff93cf18a7
commit b766bdef51
58 changed files with 1544 additions and 419 deletions

View File

@ -325,6 +325,10 @@ jdk.internal.le_COPY += .properties
################################################################################ ################################################################################
jdk.internal.opt_COPY += .properties
################################################################################
jdk.jcmd_COPY += _options jdk.jcmd_COPY += _options
################################################################################ ################################################################################

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -56,7 +56,6 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import static java.util.Collections.*; import static java.util.Collections.*;
@ -70,22 +69,22 @@ import static jdk.internal.joptsimple.internal.Strings.*;
* @param <V> represents the type of the arguments this option accepts * @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor { public abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor {
private final List<String> options = new ArrayList<String>(); private final List<String> options = new ArrayList<>();
private final String description; private final String description;
private boolean forHelp; private boolean forHelp;
protected AbstractOptionSpec( String option ) { AbstractOptionSpec( String option ) {
this( singletonList( option ), EMPTY ); this( singletonList( option ), EMPTY );
} }
protected AbstractOptionSpec( Collection<String> options, String description ) { AbstractOptionSpec( List<String> options, String description ) {
arrangeOptions( options ); arrangeOptions( options );
this.description = description; this.description = description;
} }
public final Collection<String> options() { public final List<String> options() {
return unmodifiableList( options ); return unmodifiableList( options );
} }
@ -119,12 +118,8 @@ abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor
protected V convertWith( ValueConverter<V> converter, String argument ) { protected V convertWith( ValueConverter<V> converter, String argument ) {
try { try {
return Reflection.convertWith( converter, argument ); return Reflection.convertWith( converter, argument );
} } catch ( ReflectionException | ValueConversionException ex ) {
catch ( ReflectionException ex ) { throw new OptionArgumentConversionException( this, argument, ex );
throw new OptionArgumentConversionException( options(), argument, ex );
}
catch ( ValueConversionException ex ) {
throw new OptionArgumentConversionException( options(), argument, ex );
} }
} }
@ -139,14 +134,14 @@ abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor
abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
String detectedArgument ); String detectedArgument );
private void arrangeOptions( Collection<String> unarranged ) { private void arrangeOptions( List<String> unarranged ) {
if ( unarranged.size() == 1 ) { if ( unarranged.size() == 1 ) {
options.addAll( unarranged ); options.addAll( unarranged );
return; return;
} }
List<String> shortOptions = new ArrayList<String>(); List<String> shortOptions = new ArrayList<>();
List<String> longOptions = new ArrayList<String>(); List<String> longOptions = new ArrayList<>();
for ( String each : unarranged ) { for ( String each : unarranged ) {
if ( each.length() == 1 ) if ( each.length() == 1 )

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,26 +55,40 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import jdk.internal.joptsimple.internal.Messages;
import java.util.Locale;
import static java.util.Collections.*; import static java.util.Collections.*;
import static jdk.internal.joptsimple.ParserRules.*; import static jdk.internal.joptsimple.ParserRules.*;
/** /**
* Represents the <kbd>"-W"</kbd> form of long option specification. * Represents the {@code "-W"} form of long option specification.
* *
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec<String> { class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec<String> {
AlternativeLongOptionSpec() { AlternativeLongOptionSpec() {
super( singletonList( RESERVED_FOR_EXTENSIONS ), true, "Alternative form of long options" ); super( singletonList( RESERVED_FOR_EXTENSIONS ),
true,
Messages.message(
Locale.getDefault(),
"jdk.internal.joptsimple.HelpFormatterMessages",
AlternativeLongOptionSpec.class,
"description" ) );
describedAs( "opt=value" ); describedAs( Messages.message(
Locale.getDefault(),
"jdk.internal.joptsimple.HelpFormatterMessages",
AlternativeLongOptionSpec.class,
"arg.description" ) );
} }
@Override @Override
protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
if ( !arguments.hasMore() ) if ( !arguments.hasMore() )
throw new OptionMissingRequiredArgumentException( options() ); throw new OptionMissingRequiredArgumentException( this );
arguments.treatNextAsLongOption(); arguments.treatNextAsLongOption();
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -56,13 +56,12 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import static java.util.Collections.*; import static java.util.Collections.*;
import static java.util.Objects.*;
import static jdk.internal.joptsimple.internal.Objects.*;
import static jdk.internal.joptsimple.internal.Reflection.*; import static jdk.internal.joptsimple.internal.Reflection.*;
import static jdk.internal.joptsimple.internal.Strings.*; import static jdk.internal.joptsimple.internal.Strings.*;
@ -88,12 +87,13 @@ import static jdk.internal.joptsimple.internal.Strings.*;
public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<V> { public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<V> {
private static final char NIL_VALUE_SEPARATOR = '\u0000'; private static final char NIL_VALUE_SEPARATOR = '\u0000';
private boolean optionRequired;
private final boolean argumentRequired; private final boolean argumentRequired;
private final List<V> defaultValues = new ArrayList<>();
private boolean optionRequired;
private ValueConverter<V> converter; private ValueConverter<V> converter;
private String argumentDescription = ""; private String argumentDescription = "";
private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR ); private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR );
private final List<V> defaultValues = new ArrayList<V>();
ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) { ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) {
super( option ); super( option );
@ -101,7 +101,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
this.argumentRequired = argumentRequired; this.argumentRequired = argumentRequired;
} }
ArgumentAcceptingOptionSpec( Collection<String> options, boolean argumentRequired, String description ) { ArgumentAcceptingOptionSpec( List<String> options, boolean argumentRequired, String description ) {
super( options, description ); super( options, description );
this.argumentRequired = argumentRequired; this.argumentRequired = argumentRequired;
@ -182,7 +182,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
* </code> * </code>
* </pre> * </pre>
* *
* <p>Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p> * <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> * <p>You cannot use Unicode U+0000 as the separator.</p>
* *
@ -211,7 +211,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
* </code> * </code>
* </pre> * </pre>
* *
* <p>Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p> * <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> * <p>You cannot use Unicode U+0000 in the separator.</p>
* *
@ -236,8 +236,9 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
* @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are * @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are
* {@code null} * {@code null}
*/ */
@SuppressWarnings("unchecked") @SafeVarargs
public ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) { @SuppressWarnings("varargs")
public final ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) {
addDefaultValue( value ); addDefaultValue( value );
defaultsTo( values ); defaultsTo( values );
@ -275,7 +276,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
} }
private void addDefaultValue( V value ) { private void addDefaultValue( V value ) {
ensureNotNull( value ); requireNonNull( value );
defaultValues.add( value ); defaultValues.add( value );
} }
@ -283,7 +284,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
String detectedArgument ) { String detectedArgument ) {
if ( isNullOrEmpty( detectedArgument ) ) if ( detectedArgument == null )
detectOptionArgument( parser, arguments, detectedOptions ); detectOptionArgument( parser, arguments, detectedOptions );
else else
addArguments( detectedOptions, detectedArgument ); addArguments( detectedOptions, detectedArgument );
@ -314,8 +315,7 @@ public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<
while ( lexer.hasMoreTokens() ) while ( lexer.hasMoreTokens() )
convert( lexer.nextToken() ); convert( lexer.nextToken() );
return true; return true;
} } catch ( OptionException ignored ) {
catch ( OptionException ignored ) {
return false; return false;
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,14 +55,9 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.*;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import jdk.internal.joptsimple.internal.Messages;
import jdk.internal.joptsimple.internal.Rows; import jdk.internal.joptsimple.internal.Rows;
import jdk.internal.joptsimple.internal.Strings; import jdk.internal.joptsimple.internal.Strings;
@ -73,10 +68,17 @@ import static jdk.internal.joptsimple.internal.Strings.*;
/** /**
* <p>A help formatter that allows configuration of overall row width and column separator width.</p> * <p>A help formatter that allows configuration of overall row width and column separator width.</p>
* *
* <p>The formatter produces a two-column output. The left column is for the options, and the right column for their * <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 * 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> * 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> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
public class BuiltinHelpFormatter implements HelpFormatter { public class BuiltinHelpFormatter implements HelpFormatter {
@ -102,7 +104,20 @@ public class BuiltinHelpFormatter implements HelpFormatter {
optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth ); 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 ) { public String format( Map<String, ? extends OptionDescriptor> options ) {
optionRows.reset();
nonOptionRows.reset();
Comparator<OptionDescriptor> comparator = Comparator<OptionDescriptor> comparator =
new Comparator<OptionDescriptor>() { new Comparator<OptionDescriptor>() {
public int compare( OptionDescriptor first, OptionDescriptor second ) { public int compare( OptionDescriptor first, OptionDescriptor second ) {
@ -110,7 +125,7 @@ public class BuiltinHelpFormatter implements HelpFormatter {
} }
}; };
Set<OptionDescriptor> sorted = new TreeSet<OptionDescriptor>( comparator ); Set<OptionDescriptor> sorted = new TreeSet<>( comparator );
sorted.addAll( options.values() ); sorted.addAll( options.values() );
addRows( sorted ); addRows( sorted );
@ -118,21 +133,102 @@ public class BuiltinHelpFormatter implements HelpFormatter {
return formattedHelpOutput(); return formattedHelpOutput();
} }
private String 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(); StringBuilder formatted = new StringBuilder();
String nonOptionDisplay = nonOptionRows.render(); String nonOptionDisplay = nonOptionOutput();
if ( !Strings.isNullOrEmpty( nonOptionDisplay ) ) if ( !Strings.isNullOrEmpty( nonOptionDisplay ) )
formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR ); formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR );
formatted.append( optionRows.render() ); formatted.append( optionOutput() );
return formatted.toString(); return formatted.toString();
} }
private void addRows( Collection<? extends OptionDescriptor> options ) { /**
* <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 ); addNonOptionsDescription( options );
if ( options.isEmpty() ) if ( options.isEmpty() )
optionRows.add( "No options specified", "" ); addOptionRow( message( "no.options.specified" ) );
else { else {
addHeaders( options ); addHeaders( options );
addOptions( options ); addOptions( options );
@ -141,34 +237,87 @@ public class BuiltinHelpFormatter implements HelpFormatter {
fitRowsToWidth(); fitRowsToWidth();
} }
private void addNonOptionsDescription( Collection<? extends OptionDescriptor> options ) { /**
* <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 ); OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options );
if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) { if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) {
nonOptionRows.add( "Non-option arguments:", "" ); addNonOptionRow( message( "non.option.arguments.header" ) );
nonOptionRows.add(createNonOptionArgumentsDisplay(nonOptions), ""); addNonOptionRow( createNonOptionArgumentsDisplay( nonOptions ) );
} }
} }
private boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptions ) { /**
return !Strings.isNullOrEmpty( nonOptions.description() ) * <p>Decides whether or not to show a non-option arguments help.</p>
|| !Strings.isNullOrEmpty( nonOptions.argumentTypeIndicator() ) *
|| !Strings.isNullOrEmpty( nonOptions.argumentDescription() ); * <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() );
} }
private String createNonOptionArgumentsDisplay(OptionDescriptor nonOptions) { /**
* <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(); StringBuilder buffer = new StringBuilder();
maybeAppendOptionInfo( buffer, nonOptions ); maybeAppendOptionInfo( buffer, nonOptionDescriptor );
maybeAppendNonOptionsDescription( buffer, nonOptions ); maybeAppendNonOptionsDescription( buffer, nonOptionDescriptor );
return buffer.toString(); return buffer.toString();
} }
private void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) { /**
* <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() ) ? " -- " : "" ) buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" )
.append( nonOptions.description() ); .append( nonOptions.description() );
} }
private OptionDescriptor findAndRemoveNonOptionsSpec( Collection<? extends OptionDescriptor> options ) { /**
* 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(); ) { for ( Iterator<? extends OptionDescriptor> it = options.iterator(); it.hasNext(); ) {
OptionDescriptor next = it.next(); OptionDescriptor next = it.next();
if ( next.representsNonOptions() ) { if ( next.representsNonOptions() ) {
@ -180,17 +329,32 @@ public class BuiltinHelpFormatter implements HelpFormatter {
throw new AssertionError( "no non-options argument spec" ); throw new AssertionError( "no non-options argument spec" );
} }
private void addHeaders( Collection<? extends OptionDescriptor> options ) { /**
* <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 ) ) { if ( hasRequiredOption( options ) ) {
optionRows.add("Option (* = required)", "Description"); addOptionRow( message( "option.header.with.required.indicator" ), message( "description.header" ) );
optionRows.add("---------------------", "-----------"); addOptionRow( message( "option.divider.with.required.indicator" ), message( "description.divider" ) );
} else { } else {
optionRows.add("Option", "Description"); addOptionRow( message( "option.header" ), message( "description.header" ) );
optionRows.add("------", "-----------"); addOptionRow( message( "option.divider" ), message( "description.divider" ) );
} }
} }
private boolean hasRequiredOption( Collection<? extends OptionDescriptor> options ) { /**
* 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 ) { for ( OptionDescriptor each : options ) {
if ( each.isRequired() ) if ( each.isRequired() )
return true; return true;
@ -199,19 +363,46 @@ public class BuiltinHelpFormatter implements HelpFormatter {
return false; return false;
} }
private void addOptions( Collection<? extends OptionDescriptor> options ) { /**
* <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 ) { for ( OptionDescriptor each : options ) {
if ( !each.representsNonOptions() ) if ( !each.representsNonOptions() )
optionRows.add( createOptionDisplay( each ), createDescriptionDisplay( each ) ); addOptionRow( createOptionDisplay( each ), createDescriptionDisplay( each ) );
} }
} }
private String createOptionDisplay( OptionDescriptor descriptor ) { /**
* <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() ? "* " : "" ); StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" );
for ( Iterator<String> i = descriptor.options().iterator(); i.hasNext(); ) { for ( Iterator<String> i = descriptor.options().iterator(); i.hasNext(); ) {
String option = i.next(); String option = i.next();
buffer.append( option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN ); buffer.append( optionLeader( option ) );
buffer.append( option ); buffer.append( option );
if ( i.hasNext() ) if ( i.hasNext() )
@ -223,31 +414,105 @@ public class BuiltinHelpFormatter implements HelpFormatter {
return buffer.toString(); return buffer.toString();
} }
private void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) { /**
String indicator = extractTypeIndicator( descriptor ); * <p>Gives a string that represents the given option's "option leader" in help.</p>
String description = descriptor.argumentDescription(); *
if ( indicator != null || !isNullOrEmpty( description ) ) * <p>This implementation answers with {@code "--"} for options of length greater than one; otherwise answers
appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() ); * 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;
} }
private String extractTypeIndicator( OptionDescriptor descriptor ) { /**
* <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 jdk.internal.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(); String indicator = descriptor.argumentTypeIndicator();
if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) ) if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) )
return shortNameOf( indicator ); return shortNameOf( indicator );
return null; return "String";
} }
private void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, boolean required ) { /**
* <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 ) if ( required )
appendTypeIndicator( buffer, typeIndicator, description, '<', '>' ); appendTypeIndicator( buffer, typeIndicator, description, '<', '>' );
else else
appendTypeIndicator( buffer, typeIndicator, description, '[', ']' ); appendTypeIndicator( buffer, typeIndicator, description, '[', ']' );
} }
private void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description, /**
char start, char end ) { * <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 ); buffer.append( ' ' ).append( start );
if ( typeIndicator != null ) if ( typeIndicator != null )
buffer.append( typeIndicator ); buffer.append( typeIndicator );
@ -262,21 +527,69 @@ public class BuiltinHelpFormatter implements HelpFormatter {
buffer.append( end ); buffer.append( end );
} }
private String createDescriptionDisplay( OptionDescriptor descriptor ) { /**
* <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(); List<?> defaultValues = descriptor.defaultValues();
if ( defaultValues.isEmpty() ) if ( defaultValues.isEmpty() )
return descriptor.description(); return descriptor.description();
String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues ); String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues );
return ( descriptor.description() + ' ' + surround( "default: " + defaultValuesDisplay, '(', ')' ) ).trim(); return ( descriptor.description()
+ ' '
+ surround( message( "default.value.header" ) + ' ' + defaultValuesDisplay, '(', ')' )
).trim();
} }
private String createDefaultValuesDisplay( List<?> defaultValues ) { /**
* <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(); return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString();
} }
private void fitRowsToWidth() { /**
nonOptionRows.fitToWidth(); * <p>Looks up and gives a resource bundle message.</p>
optionRows.fitToWidth(); *
* <p>This implementation looks in the bundle {@code "jdk.internal.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(),
"jdk.internal.joptsimple.HelpFormatterMessages",
BuiltinHelpFormatter.class,
keySuffix,
args );
} }
} }

View File

@ -0,0 +1,44 @@
#
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
jdk.internal.joptsimple.IllegalOptionSpecificationException.message = {0} is not a legal option character
jdk.internal.joptsimple.MissingRequiredOptionsException.message = Missing required option(s) {0}
jdk.internal.joptsimple.MultipleArgumentsForOptionException.message = Found multiple arguments for option {0}, but you asked for only one
jdk.internal.joptsimple.OptionArgumentConversionException.message = Cannot parse argument ''{0}'' of option {1}
jdk.internal.joptsimple.OptionMissingRequiredArgumentException.message = Option {0} requires an argument
jdk.internal.joptsimple.UnavailableOptionException.message = Option(s) {0} are unavailable given other options on the command line
jdk.internal.joptsimple.UnconfiguredOptionException.message = Option(s) {0} not configured on this parser
jdk.internal.joptsimple.UnrecognizedOptionException.message = {0} is not a recognized option
jdk.internal.joptsimple.util.DateConverter.without.pattern.message = Value [{0}] does not match date/time pattern
jdk.internal.joptsimple.util.DateConverter.with.pattern.message = Value [{0}] does not match date/time pattern [{1}]
jdk.internal.joptsimple.util.RegexMatcher.message = Value [{0}] did not match regex [{1}]
jdk.internal.joptsimple.util.EnumConverter.message = Value [{0}] is not one of [{1}]
jdk.internal.joptsimple.util.PathConverter.file.existing.message = File [{0}] does not exist
jdk.internal.joptsimple.util.PathConverter.directory.existing.message = Directory [{0}] does not exist
jdk.internal.joptsimple.util.PathConverter.file.not.existing.message = File [{0}] does already exist
jdk.internal.joptsimple.util.PathConverter.file.overwritable.message = File [{0}] is not overwritable
jdk.internal.joptsimple.util.PathConverter.file.readable.message = File [{0}] is not readable
jdk.internal.joptsimple.util.PathConverter.file.writable.message = File [{0}] is not writable
jdk.internal.joptsimple.util.InetAddressConverter.message = Cannot convert value [{0}] into an InetAddress

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -0,0 +1,36 @@
#
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
jdk.internal.joptsimple.BuiltinHelpFormatter.no.options.specified = No options specified
jdk.internal.joptsimple.BuiltinHelpFormatter.non.option.arguments.header = Non-option arguments:
jdk.internal.joptsimple.BuiltinHelpFormatter.option.header.with.required.indicator = Option (* = required)
jdk.internal.joptsimple.BuiltinHelpFormatter.option.divider.with.required.indicator = ---------------------
jdk.internal.joptsimple.BuiltinHelpFormatter.option.header = Option
jdk.internal.joptsimple.BuiltinHelpFormatter.option.divider = ------
jdk.internal.joptsimple.BuiltinHelpFormatter.description.header = Description
jdk.internal.joptsimple.BuiltinHelpFormatter.description.divider = -----------
jdk.internal.joptsimple.BuiltinHelpFormatter.default.value.header = default:
jdk.internal.joptsimple.AlternativeLongOptionSpec.description = Alternative form of long options
jdk.internal.joptsimple.AlternativeLongOptionSpec.arg.description = opt=value

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -70,7 +70,7 @@ class IllegalOptionSpecificationException extends OptionException {
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return singleOptionMessage() + " is not a legal option character"; return new Object[] { singleOptionString() };
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,22 +55,22 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
/** /**
* Thrown when an option is marked as required, but not specified on the command line. * Thrown when options marked as required are not specified on the command line.
* *
* @author <a href="https://github.com/TC1">Emils Solmanis</a> * @author <a href="https://github.com/TC1">Emils Solmanis</a>
*/ */
class MissingRequiredOptionException extends OptionException { class MissingRequiredOptionsException extends OptionException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
protected MissingRequiredOptionException( Collection<String> options ) { protected MissingRequiredOptionsException( List<? extends OptionSpec<?>> missingRequiredOptions ) {
super( options ); super( missingRequiredOptions );
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return "Missing required option(s) " + multipleOptionMessage(); return new Object[] { multipleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import static java.util.Collections.*;
/** /**
* Thrown when asking an {@link OptionSet} for a single argument of an option when many have been specified. * Thrown when asking an {@link OptionSet} for a single argument of an option when many have been specified.
@ -65,12 +65,12 @@ import java.util.Collection;
class MultipleArgumentsForOptionException extends OptionException { class MultipleArgumentsForOptionException extends OptionException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
MultipleArgumentsForOptionException( Collection<String> options ) { MultipleArgumentsForOptionException( OptionSpec<?> options ) {
super( options ); super( singleton( options ) );
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return "Found multiple arguments for option " + multipleOptionMessage() + ", but you asked for only one"; return new Object[] { singleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,6 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection;
import java.util.List; import java.util.List;
import static java.util.Collections.*; import static java.util.Collections.*;
@ -70,7 +69,7 @@ class NoArgumentOptionSpec extends AbstractOptionSpec<Void> {
this( singletonList( option ), "" ); this( singletonList( option ), "" );
} }
NoArgumentOptionSpec( Collection<String> options, String description ) { NoArgumentOptionSpec( List<String> options, String description ) {
super( options, description ); super( options, description );
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -87,7 +87,7 @@ public class NonOptionArgumentSpec<V> extends AbstractOptionSpec<V> {
private String argumentDescription = ""; private String argumentDescription = "";
NonOptionArgumentSpec() { NonOptionArgumentSpec() {
this(""); this( "" );
} }
NonOptionArgumentSpec( String description ) { NonOptionArgumentSpec( String description ) {

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import static java.util.Collections.*;
/** /**
* Thrown when a problem occurs converting an argument of an option from {@link String} to another type. * Thrown when a problem occurs converting an argument of an option from {@link String} to another type.
@ -67,14 +67,14 @@ class OptionArgumentConversionException extends OptionException {
private final String argument; private final String argument;
OptionArgumentConversionException( Collection<String> options, String argument, Throwable cause ) { OptionArgumentConversionException( OptionSpec<?> options, String argument, Throwable cause ) {
super( options, cause ); super( singleton( options ), cause );
this.argument = argument; this.argument = argument;
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return "Cannot parse argument '" + argument + "' of option " + multipleOptionMessage(); return new Object[] { argument, singleOptionString() };
} }
} }

View File

@ -25,14 +25,20 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
/** /**
* Trains the option parser. This interface aids integration with other code which may expose declaration of options but * Trains the option parser. This interface aids integration that disposes declaration of options but not actual
* not actual command-line parsing. * 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> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @see OptionParser * @see OptionParser
* @since 4.6
*/ */
public interface OptionDeclarer { public interface OptionDeclarer {
/** /**
@ -78,12 +84,12 @@ public interface OptionDeclarer {
* @throws OptionException if any of the options contain illegal characters * @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 NullPointerException if the option list or any of its elements are {@code null}
*/ */
OptionSpecBuilder acceptsAll( Collection<String> options ); OptionSpecBuilder acceptsAll( List<String> options );
/** /**
* Tells the parser to recognize the given options, and treat them as synonymous. * Tells the parser to recognize the given options, and treat them as synonymous.
* *
* @see #acceptsAll(Collection) * @see #acceptsAll(List)
* @param options the options to recognize and treat as synonymous * @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 * @param description a string that describes the purpose of the option. This is used when generating help
* information about the parser. * information about the parser.
@ -92,7 +98,7 @@ public interface OptionDeclarer {
* @throws NullPointerException if the option list or any of its elements are {@code null} * @throws NullPointerException if the option list or any of its elements are {@code null}
* @throws IllegalArgumentException if the option list is empty * @throws IllegalArgumentException if the option list is empty
*/ */
OptionSpecBuilder acceptsAll( Collection<String> options, String description ); OptionSpecBuilder acceptsAll( List<String> options, String description );
/** /**
* Gives an object that represents an access point for non-option arguments on a command line. * Gives an object that represents an access point for non-option arguments on a command line.
@ -127,7 +133,7 @@ public interface OptionDeclarer {
void allowsUnrecognizedOptions(); void allowsUnrecognizedOptions();
/** /**
* Tells the parser either to recognize or ignore <kbd>"-W"</kbd>-style long options. * 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 * @param recognize {@code true} if the parser is to recognize the special style of long options
*/ */

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,6 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -70,7 +69,7 @@ public interface OptionDescriptor {
* *
* @return synonymous options * @return synonymous options
*/ */
Collection<String> options(); List<String> options();
/** /**
* Description of this option's purpose. * Description of this option's purpose.

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -58,11 +58,15 @@ package jdk.internal.joptsimple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Set;
import jdk.internal.joptsimple.internal.Strings;
import static java.util.Collections.*; import static java.util.Collections.*;
import static jdk.internal.joptsimple.internal.Messages.*;
import static jdk.internal.joptsimple.internal.Strings.*;
/** /**
* Thrown when a problem occurs during option parsing. * Thrown when a problem occurs during option parsing.
@ -72,16 +76,30 @@ import static jdk.internal.joptsimple.internal.Strings.*;
public abstract class OptionException extends RuntimeException { public abstract class OptionException extends RuntimeException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
private final List<String> options = new ArrayList<String>(); private final List<String> options = new ArrayList<>();
protected OptionException( Collection<String> options ) { protected OptionException( List<String> options ) {
this.options.addAll( options ); this.options.addAll( options );
} }
protected OptionException( Collection<String> options, Throwable cause ) { protected OptionException( Collection<? extends OptionSpec<?>> options ) {
super( cause ); this.options.addAll( specsToStrings( options ) );
}
this.options.addAll( 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() ), "/" );
} }
/** /**
@ -89,23 +107,24 @@ public abstract class OptionException extends RuntimeException {
* *
* @return the option being considered when the exception was created * @return the option being considered when the exception was created
*/ */
public Collection<String> options() { public List<String> options() {
return unmodifiableCollection( options ); return unmodifiableList( options );
} }
protected final String singleOptionMessage() { protected final String singleOptionString() {
return singleOptionMessage( options.get( 0 ) ); return singleOptionString( options.get( 0 ) );
} }
protected final String singleOptionMessage( String option ) { protected final String singleOptionString( String option ) {
return SINGLE_QUOTE + option + SINGLE_QUOTE; return option;
} }
protected final String multipleOptionMessage() { protected final String multipleOptionString() {
StringBuilder buffer = new StringBuilder( "[" ); StringBuilder buffer = new StringBuilder( "[" );
for ( Iterator<String> iter = options.iterator(); iter.hasNext(); ) { Set<String> asSet = new LinkedHashSet<String>( options );
buffer.append( singleOptionMessage( iter.next() ) ); for ( Iterator<String> iter = asSet.iterator(); iter.hasNext(); ) {
buffer.append( singleOptionString(iter.next()) );
if ( iter.hasNext() ) if ( iter.hasNext() )
buffer.append( ", " ); buffer.append( ", " );
} }
@ -118,4 +137,19 @@ public abstract class OptionException extends RuntimeException {
static OptionException unrecognizedOption( String option ) { static OptionException unrecognizedOption( String option ) {
return new UnrecognizedOptionException( 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, "jdk.internal.joptsimple.ExceptionMessages", getClass(), "message", messageArguments() );
}
abstract Object[] messageArguments();
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,22 +55,22 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import static java.util.Arrays.*;
/** /**
* Thrown when the option parser discovers an option that requires an argument, but that argument is missing. * 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> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
class OptionMissingRequiredArgumentException extends OptionException { class OptionMissingRequiredArgumentException extends OptionException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
OptionMissingRequiredArgumentException( Collection<String> options ) { OptionMissingRequiredArgumentException( OptionSpec<?> option ) {
super( options ); super( asList( option ) );
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return "Option " + multipleOptionMessage() + " requires an argument"; return new Object[] { singleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,18 +55,16 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import jdk.internal.joptsimple.internal.AbbreviationMap;
import jdk.internal.joptsimple.util.KeyValuePair;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.HashSet; import jdk.internal.joptsimple.internal.AbbreviationMap;
import java.util.Map; import jdk.internal.joptsimple.internal.SimpleOptionNameMap;
import java.util.Set; import jdk.internal.joptsimple.internal.OptionNameMap;
import jdk.internal.joptsimple.util.KeyValuePair;
import static java.util.Collections.*; import static java.util.Collections.*;
import static jdk.internal.joptsimple.OptionException.*; import static jdk.internal.joptsimple.OptionException.*;
@ -80,57 +78,58 @@ import static jdk.internal.joptsimple.ParserRules.*;
* <p>This parser supports short options and long options.</p> * <p>This parser supports short options and long options.</p>
* *
* <ul> * <ul>
* <li><dfn>Short options</dfn> begin with a single hyphen ("<kbd>-</kbd>") followed by a single letter or digit, * <li><dfn>Short options</dfn> begin with a single hyphen ("{@code -}") followed by a single letter or digit,
* or question mark ("<kbd>?</kbd>"), or dot ("<kbd>.</kbd>").</li> * 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 * <li>Short options can accept single arguments. The argument can be made required or optional. The option's
* argument can occur: * argument can occur:
* <ul> * <ul>
* <li>in the slot after the option, as in <kbd>-d /tmp</kbd></li> * <li>in the slot after the option, as in {@code -d /tmp}</li>
* <li>right up against the option, as in <kbd>-d/tmp</kbd></li> * <li>right up against the option, as in {@code -d/tmp}</li>
* <li>right up against the option separated by an equals sign (<kbd>"="</kbd>), as in <kbd>-d=/tmp</kbd></li> * <li>right up against the option separated by an equals sign ({@code "="}), as in {@code -d=/tmp}</li>
* </ul> * </ul>
* To specify <em>n</em> arguments for an option, specify the option <em>n</em> times, once for each argument, * To specify <em>n</em> arguments for an option, specify the option <em>n</em> times, once for each argument,
* as in <kbd>-d /tmp -d /var -d /opt</kbd>; or, when using the * as in {@code -d /tmp -d /var -d /opt}; or, when using the
* {@linkplain ArgumentAcceptingOptionSpec#withValuesSeparatedBy(char) "separated values"} clause of the "fluent * {@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 * interface" (see below), give multiple values separated by a given character as a single argument to the
* option.</li> * option.</li>
* *
* <li>Short options can be clustered, so that <kbd>-abc</kbd> is treated as <kbd>-a -b -c</kbd>. If a short option * <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 * in the cluster can accept an argument, the remaining characters are interpreted as the argument for that
* option.</li> * option.</li>
* *
* <li>An argument consisting only of two hyphens (<kbd>"--"</kbd>) signals that the remaining arguments are to be * <li>An argument consisting only of two hyphens ({@code "--"}) signals that the remaining arguments are to be
* treated as non-options.</li> * 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 * <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 * argument of an option). Many Unix programs treat single hyphens as stand-ins for the standard input or standard
* output streams.</li> * output streams.</li>
* *
* <li><dfn>Long options</dfn> begin with two hyphens (<kbd>"--"</kbd>), followed by multiple letters, digits, * <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 * hyphens, question marks, or dots. A hyphen cannot be the first character of a long option specification when
* configuring the parser.</li> * configuring the parser.</li>
* *
* <li>You can abbreviate long options, so long as the abbreviation is unique.</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 * <li>Long options can accept single arguments. The argument can be made required or optional. The option's
* argument can occur: * argument can occur:
* <ul> * <ul>
* <li>in the slot after the option, as in <kbd>--directory /tmp</kbd></li> * <li>in the slot after the option, as in {@code --directory /tmp}</li>
* <li>right up against the option separated by an equals sign (<kbd>"="</kbd>), as in * <li>right up against the option separated by an equals sign ({@code "="}), as in
* <kbd>--directory=/tmp</kbd> * {@code --directory=/tmp}
* </ul> * </ul>
* Specify multiple arguments for a long option in the same manner as for short options (see above).</li> * 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 (<kbd>"-"</kbd>) instead of a double hyphen (<kbd>"--"</kbd>) for a long * <li>You can use a single hyphen ({@code "-"}) instead of a double hyphen ({@code "--"}) for a long
* option.</li> * option.</li>
* *
* <li>The option <kbd>-W</kbd> is reserved. If you tell the parser to {@linkplain * <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, * #recognizeAlternativeLongOptions(boolean) recognize alternative long options}, then it will treat, for example,
* <kbd>-W foo=bar</kbd> as the long option <kbd>foo</kbd> with argument <kbd>bar</kbd>, as though you had written * {@code -W foo=bar} as the long option {@code foo} with argument {@code bar}, as though you had written
* <kbd>--foo=bar</kbd>.</li> * {@code --foo=bar}.</li>
* *
* <li>You can specify <kbd>-W</kbd> as a valid short option, or use it as an abbreviation for a long option, but * <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 * {@linkplain #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will always supersede
* this behavior.</li> * this behavior.</li>
* *
@ -148,15 +147,15 @@ import static jdk.internal.joptsimple.ParserRules.*;
* parser.accepts( "2" ); * parser.accepts( "2" );
* OptionSet options = parser.parse( "-a", "-2" ); * OptionSet options = parser.parse( "-a", "-2" );
* </code></pre> * </code></pre>
* In this case, the option set contains <kbd>"a"</kbd> with argument <kbd>-2</kbd>, not both <kbd>"a"</kbd> and * In this case, the option set contains {@code "a"} with argument {@code -2}, not both {@code "a"} and
* <kbd>"2"</kbd>. Swapping the elements in the <em>args</em> array gives the latter.</li> * {@code "2"}. Swapping the elements in the <em>args</em> array gives the latter.</li>
* </ul> * </ul>
* *
* <p>There are two ways to tell the parser what options to recognize:</p> * <p>There are two ways to tell the parser what options to recognize:</p>
* *
* <ol> * <ol>
* <li>A "fluent interface"-style API for specifying options, available since version 2. Sentences in this fluent * <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(Collection) * 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, * 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, * 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 * etc. Since version 3, these calls return an instance of {@link OptionSpec}, which can subsequently be used to
@ -169,28 +168,28 @@ import static jdk.internal.joptsimple.ParserRules.*;
* <ul> * <ul>
* <li>Any letter or digit is treated as an option character.</li> * <li>Any letter or digit is treated as an option character.</li>
* *
* <li>An option character can be immediately followed by an asterisk (*) to indicate that the option is a * <li>An option character can be immediately followed by an asterisk ({@code *)} to indicate that
* "help" option.</li> * the option is a "help" option.</li>
* *
* <li>If an option character (with possible trailing asterisk) is followed by a single colon (<kbd>":"</kbd>), * <li>If an option character (with possible trailing asterisk) is followed by a single colon ({@code ":"}),
* then the option requires an argument.</li> * then the option requires an argument.</li>
* *
* <li>If an option character (with possible trailing asterisk) is followed by two colons (<kbd>"::"</kbd>), * <li>If an option character (with possible trailing asterisk) is followed by two colons ({@code "::"}),
* then the option accepts an optional argument.</li> * then the option accepts an optional argument.</li>
* *
* <li>Otherwise, the option character accepts no argument.</li> * <li>Otherwise, the option character accepts no argument.</li>
* *
* <li>If the option specification string begins with a plus sign (<kbd>"+"</kbd>), the parser will behave * <li>If the option specification string begins with a plus sign ({@code "+" }), the parser will behave
* "POSIX-ly correct".</li> * "POSIX-ly correct".</li>
* *
* <li>If the option specification string contains the sequence <kbd>"W;"</kbd> (capital W followed by a * <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> * semicolon), the parser will recognize the alternative form of long options.</li>
* </ul> * </ul>
* </li> * </li>
* </ol> * </ol>
* *
* <p>Each of the options in a list of options given to {@link #acceptsAll(Collection) acceptsAll} is treated as a * <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: * synonym of the others. For example:</p>
* <pre> * <pre>
* <code> * <code>
* OptionParser parser = new OptionParser(); * OptionParser parser = new OptionParser();
@ -198,14 +197,14 @@ import static jdk.internal.joptsimple.ParserRules.*;
* OptionSet options = parser.parse( "-w" ); * OptionSet options = parser.parse( "-w" );
* </code> * </code>
* </pre> * </pre>
* In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer {@code true} when given arguments * <p>In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer {@code true} when given arguments
* <kbd>"w"</kbd>, <kbd>"interactive"</kbd>, and <kbd>"confirmation"</kbd>. The {@link OptionSet} would give the same * {@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> * 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, * <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 * 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 * 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 <kbd>=</kbd> syntax.</p> * 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}. * <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> * "POSIX-ly correct" parsers are configured by either:</p>
@ -214,16 +213,20 @@ import static jdk.internal.joptsimple.ParserRules.*;
* <li>using the method {@link #posixlyCorrect(boolean)}, or</li> * <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 * <li>using the {@linkplain #OptionParser(String) constructor} with an argument whose first character is a plus sign
* (<kbd>"+"</kbd>)</li> * ({@code "+"})</li>
* </ol> * </ol>
* *
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @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> * @see <a href="http://www.gnu.org/software/libc/manual">The GNU C Library</a>
*/ */
public class OptionParser implements OptionDeclarer { public class OptionParser implements OptionDeclarer {
private final AbbreviationMap<AbstractOptionSpec<?>> recognizedOptions; private final OptionNameMap<AbstractOptionSpec<?>> recognizedOptions;
private final Map<Collection<String>, Set<OptionSpec<?>>> requiredIf; private final ArrayList<AbstractOptionSpec<?>> trainingOrder;
private final Map<Collection<String>, Set<OptionSpec<?>>> requiredUnless; 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 OptionParserState state;
private boolean posixlyCorrect; private boolean posixlyCorrect;
private boolean allowsUnrecognizedOptions; private boolean allowsUnrecognizedOptions;
@ -234,11 +237,28 @@ public class OptionParser implements OptionDeclarer {
* behavior. * behavior.
*/ */
public OptionParser() { public OptionParser() {
recognizedOptions = new AbbreviationMap<AbstractOptionSpec<?>>(); this(true);
requiredIf = new HashMap<Collection<String>, Set<OptionSpec<?>>>(); }
requiredUnless = new HashMap<Collection<String>, Set<OptionSpec<?>>>();
/**
* 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 ); state = moreOptions( false );
recognizedOptions = allowAbbreviations
? new AbbreviationMap<AbstractOptionSpec<?>>()
: new SimpleOptionNameMap<AbstractOptionSpec<?>>();
recognize( new NonOptionArgumentSpec<String>() ); recognize( new NonOptionArgumentSpec<String>() );
} }
@ -266,11 +286,11 @@ public class OptionParser implements OptionDeclarer {
return acceptsAll( singletonList( option ), description ); return acceptsAll( singletonList( option ), description );
} }
public OptionSpecBuilder acceptsAll( Collection<String> options ) { public OptionSpecBuilder acceptsAll( List<String> options ) {
return acceptsAll( options, "" ); return acceptsAll( options, "" );
} }
public OptionSpecBuilder acceptsAll( Collection<String> options, String description ) { public OptionSpecBuilder acceptsAll( List<String> options, String description ) {
if ( options.isEmpty() ) if ( options.isEmpty() )
throw new IllegalArgumentException( "need at least one option" ); throw new IllegalArgumentException( "need at least one option" );
@ -280,7 +300,7 @@ public class OptionParser implements OptionDeclarer {
} }
public NonOptionArgumentSpec<String> nonOptions() { public NonOptionArgumentSpec<String> nonOptions() {
NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<String>(); NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<>();
recognize( spec ); recognize( spec );
@ -288,7 +308,7 @@ public class OptionParser implements OptionDeclarer {
} }
public NonOptionArgumentSpec<String> nonOptions( String description ) { public NonOptionArgumentSpec<String> nonOptions( String description ) {
NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<String>( description ); NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<>( description );
recognize( spec ); recognize( spec );
@ -321,6 +341,7 @@ public class OptionParser implements OptionDeclarer {
void recognize( AbstractOptionSpec<?> spec ) { void recognize( AbstractOptionSpec<?> spec ) {
recognizedOptions.putAll( spec.options(), spec ); recognizedOptions.putAll( spec.options(), spec );
trainingOrder.add( spec );
} }
/** /**
@ -348,7 +369,7 @@ public class OptionParser implements OptionDeclarer {
* @see #printHelpOn(OutputStream) * @see #printHelpOn(OutputStream)
*/ */
public void printHelpOn( Writer sink ) throws IOException { public void printHelpOn( Writer sink ) throws IOException {
sink.write( helpFormatter.format( recognizedOptions.toJavaUtilMap() ) ); sink.write( helpFormatter.format( _recognizedOptions() ) );
sink.flush(); sink.flush();
} }
@ -366,15 +387,29 @@ public class OptionParser implements OptionDeclarer {
} }
/** /**
* Retrieves all the options which have been configured for the parser. * 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.
* *
* @return a {@link Map} containing all the configured options and their corresponding {@link OptionSpec} * (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() { public Map<String, OptionSpec<?>> recognizedOptions() {
return new HashMap<String, OptionSpec<?>>( recognizedOptions.toJavaUtilMap() ); 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. * Parses the given command line arguments according to the option specifications given to the parser.
* *
* @param arguments arguments to parse * @param arguments arguments to parse
@ -393,45 +428,89 @@ public class OptionParser implements OptionDeclarer {
reset(); reset();
ensureRequiredOptions( detected ); ensureRequiredOptions( detected );
ensureAllowedOptions( detected );
return 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 ) { private void ensureRequiredOptions( OptionSet options ) {
Collection<String> missingRequiredOptions = missingRequiredOptions( options ); List<AbstractOptionSpec<?>> missingRequiredOptions = missingRequiredOptions(options);
boolean helpOptionPresent = isHelpOptionPresent( options ); boolean helpOptionPresent = isHelpOptionPresent( options );
if ( !missingRequiredOptions.isEmpty() && !helpOptionPresent ) if ( !missingRequiredOptions.isEmpty() && !helpOptionPresent )
throw new MissingRequiredOptionException( missingRequiredOptions ); throw new MissingRequiredOptionsException( missingRequiredOptions );
} }
private Collection<String> missingRequiredOptions( OptionSet options ) { private void ensureAllowedOptions( OptionSet options ) {
Collection<String> missingRequiredOptions = new HashSet<String>(); 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() ) { for ( AbstractOptionSpec<?> each : recognizedOptions.toJavaUtilMap().values() ) {
if ( each.isRequired() && !options.has( each ) ) if ( each.isRequired() && !options.has( each ) )
missingRequiredOptions.addAll( each.options() ); missingRequiredOptions.add(each);
} }
for ( Map.Entry<Collection<String>, Set<OptionSpec<?>>> eachEntry : requiredIf.entrySet() ) { for ( Map.Entry<List<String>, Set<OptionSpec<?>>> each : requiredIf.entrySet() ) {
AbstractOptionSpec<?> required = specFor( eachEntry.getKey().iterator().next() ); AbstractOptionSpec<?> required = specFor( each.getKey().iterator().next() );
if ( optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { if ( optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) )
missingRequiredOptions.addAll( required.options() ); missingRequiredOptions.add( required );
}
} }
for ( Map.Entry<Collection<String>, Set<OptionSpec<?>>> eachEntry : requiredUnless.entrySet() ) { for ( Map.Entry<List<String>, Set<OptionSpec<?>>> each : requiredUnless.entrySet() ) {
AbstractOptionSpec<?> required = specFor( eachEntry.getKey().iterator().next() ); AbstractOptionSpec<?> required = specFor(each.getKey().iterator().next());
if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { if ( !optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) )
missingRequiredOptions.addAll( required.options() ); missingRequiredOptions.add( required );
}
} }
return missingRequiredOptions; 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 ) { private boolean optionsHasAnyOf( OptionSet options, Collection<OptionSpec<?>> specs ) {
for ( OptionSpec<?> each : specs ) { for ( OptionSpec<?> each : specs ) {
if ( options.has( each ) ) if ( options.has( each ) )
@ -443,12 +522,14 @@ public class OptionParser implements OptionDeclarer {
private boolean isHelpOptionPresent( OptionSet options ) { private boolean isHelpOptionPresent( OptionSet options ) {
boolean helpOptionPresent = false; boolean helpOptionPresent = false;
for ( AbstractOptionSpec<?> each : recognizedOptions.toJavaUtilMap().values() ) { for ( AbstractOptionSpec<?> each : recognizedOptions.toJavaUtilMap().values() ) {
if ( each.isForHelp() && options.has( each ) ) { if ( each.isForHelp() && options.has( each ) ) {
helpOptionPresent = true; helpOptionPresent = true;
break; break;
} }
} }
return helpOptionPresent; return helpOptionPresent;
} }
@ -505,24 +586,40 @@ public class OptionParser implements OptionDeclarer {
return recognizedOptions.contains( option ); return recognizedOptions.contains( option );
} }
void requiredIf( Collection<String> precedentSynonyms, String required ) { void requiredIf( List<String> precedentSynonyms, String required ) {
requiredIf( precedentSynonyms, specFor( required ) ); requiredIf( precedentSynonyms, specFor( required ) );
} }
void requiredIf( Collection<String> precedentSynonyms, OptionSpec<?> required ) { void requiredIf( List<String> precedentSynonyms, OptionSpec<?> required ) {
putRequiredOption( precedentSynonyms, required, requiredIf ); putDependentOption( precedentSynonyms, required, requiredIf );
} }
void requiredUnless( Collection<String> precedentSynonyms, String required ) { void requiredUnless( List<String> precedentSynonyms, String required ) {
requiredUnless( precedentSynonyms, specFor( required ) ); requiredUnless( precedentSynonyms, specFor( required ) );
} }
void requiredUnless( Collection<String> precedentSynonyms, OptionSpec<?> required ) { void requiredUnless( List<String> precedentSynonyms, OptionSpec<?> required ) {
putRequiredOption( precedentSynonyms, required, requiredUnless ); putDependentOption( precedentSynonyms, required, requiredUnless );
} }
private void putRequiredOption( Collection<String> precedentSynonyms, OptionSpec<?> required, void availableIf( List<String> precedentSynonyms, String available ) {
Map<Collection<String>, Set<OptionSpec<?>>> target ) { 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 ) { for ( String each : precedentSynonyms ) {
AbstractOptionSpec<?> spec = specFor( each ); AbstractOptionSpec<?> spec = specFor( each );
@ -532,7 +629,7 @@ public class OptionParser implements OptionDeclarer {
Set<OptionSpec<?>> associated = target.get( precedentSynonyms ); Set<OptionSpec<?>> associated = target.get( precedentSynonyms );
if ( associated == null ) { if ( associated == null ) {
associated = new HashSet<OptionSpec<?>>(); associated = new HashSet<>();
target.put( precedentSynonyms, associated ); target.put( precedentSynonyms, associated );
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,11 +55,14 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.*; 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.Collections.*;
import static java.util.Objects.*;
import static jdk.internal.joptsimple.internal.Objects.*;
/** /**
* Representation of a group of detected command line options, their arguments, and non-option arguments. * Representation of a group of detected command line options, their arguments, and non-option arguments.
@ -77,9 +80,9 @@ public class OptionSet {
* Package-private because clients don't create these. * Package-private because clients don't create these.
*/ */
OptionSet( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) { OptionSet( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) {
detectedSpecs = new ArrayList<OptionSpec<?>>(); detectedSpecs = new ArrayList<>();
detectedOptions = new HashMap<String, AbstractOptionSpec<?>>(); detectedOptions = new HashMap<>();
optionsToArguments = new IdentityHashMap<AbstractOptionSpec<?>, List<String>>(); optionsToArguments = new IdentityHashMap<>();
defaultValues = defaultValues( recognizedSpecs ); defaultValues = defaultValues( recognizedSpecs );
this.recognizedSpecs = recognizedSpecs; this.recognizedSpecs = recognizedSpecs;
} }
@ -90,7 +93,7 @@ public class OptionSet {
* @return {@code true} if any options were detected * @return {@code true} if any options were detected
*/ */
public boolean hasOptions() { public boolean hasOptions() {
return !detectedOptions.isEmpty(); return !( detectedOptions.size() == 1 && detectedOptions.values().iterator().next().representsNonOptions() );
} }
/** /**
@ -148,7 +151,7 @@ public class OptionSet {
* @see #hasArgument(String) * @see #hasArgument(String)
*/ */
public boolean hasArgument( OptionSpec<?> option ) { public boolean hasArgument( OptionSpec<?> option ) {
ensureNotNull( option ); requireNonNull( option );
List<String> values = optionsToArguments.get( option ); List<String> values = optionsToArguments.get( option );
return values != null && !values.isEmpty(); return values != null && !values.isEmpty();
@ -169,7 +172,7 @@ public class OptionSet {
* @throws OptionException if more than one argument was detected for the option * @throws OptionException if more than one argument was detected for the option
*/ */
public Object valueOf( String option ) { public Object valueOf( String option ) {
ensureNotNull( option ); requireNonNull( option );
AbstractOptionSpec<?> spec = detectedOptions.get( option ); AbstractOptionSpec<?> spec = detectedOptions.get( option );
if ( spec == null ) { if ( spec == null ) {
@ -194,7 +197,7 @@ public class OptionSet {
* @throws ClassCastException if the arguments of this option are not of the expected type * @throws ClassCastException if the arguments of this option are not of the expected type
*/ */
public <V> V valueOf( OptionSpec<V> option ) { public <V> V valueOf( OptionSpec<V> option ) {
ensureNotNull( option ); requireNonNull( option );
List<V> values = valuesOf( option ); List<V> values = valuesOf( option );
switch ( values.size() ) { switch ( values.size() ) {
@ -203,7 +206,7 @@ public class OptionSet {
case 1: case 1:
return values.get( 0 ); return values.get( 0 );
default: default:
throw new MultipleArgumentsForOptionException( option.options() ); throw new MultipleArgumentsForOptionException( option );
} }
} }
@ -217,7 +220,7 @@ public class OptionSet {
* @throws NullPointerException if {@code option} is {@code null} * @throws NullPointerException if {@code option} is {@code null}
*/ */
public List<?> valuesOf( String option ) { public List<?> valuesOf( String option ) {
ensureNotNull( option ); requireNonNull( option );
AbstractOptionSpec<?> spec = detectedOptions.get( option ); AbstractOptionSpec<?> spec = detectedOptions.get( option );
return spec == null ? defaultValuesFor( option ) : valuesOf( spec ); return spec == null ? defaultValuesFor( option ) : valuesOf( spec );
@ -238,14 +241,14 @@ public class OptionSet {
* example, if the type does not implement a correct conversion constructor or method * example, if the type does not implement a correct conversion constructor or method
*/ */
public <V> List<V> valuesOf( OptionSpec<V> option ) { public <V> List<V> valuesOf( OptionSpec<V> option ) {
ensureNotNull( option ); requireNonNull( option );
List<String> values = optionsToArguments.get( option ); List<String> values = optionsToArguments.get( option );
if ( values == null || values.isEmpty() ) if ( values == null || values.isEmpty() )
return defaultValueFor( option ); return defaultValueFor( option );
AbstractOptionSpec<V> spec = (AbstractOptionSpec<V>) option; AbstractOptionSpec<V> spec = (AbstractOptionSpec<V>) option;
List<V> convertedValues = new ArrayList<V>(); List<V> convertedValues = new ArrayList<>();
for ( String each : values ) for ( String each : values )
convertedValues.add( spec.convert( each ) ); convertedValues.add( spec.convert( each ) );
@ -260,7 +263,7 @@ public class OptionSet {
*/ */
public List<OptionSpec<?>> specs() { public List<OptionSpec<?>> specs() {
List<OptionSpec<?>> specs = detectedSpecs; List<OptionSpec<?>> specs = detectedSpecs;
specs.remove( detectedOptions.get( NonOptionArgumentSpec.NAME ) ); specs.removeAll( singletonList( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) );
return unmodifiableList( specs ); return unmodifiableList( specs );
} }
@ -271,10 +274,13 @@ public class OptionSet {
* @return the declared options as a map * @return the declared options as a map
*/ */
public Map<OptionSpec<?>, List<?>> asMap() { public Map<OptionSpec<?>, List<?>> asMap() {
Map<OptionSpec<?>, List<?>> map = new HashMap<OptionSpec<?>, List<?>>(); Map<OptionSpec<?>, List<?>> map = new HashMap<>();
for ( AbstractOptionSpec<?> spec : recognizedSpecs.values() )
for ( AbstractOptionSpec<?> spec : recognizedSpecs.values() ) {
if ( !spec.representsNonOptions() ) if ( !spec.representsNonOptions() )
map.put( spec, valuesOf( spec ) ); map.put( spec, valuesOf( spec ) );
}
return unmodifiableMap( map ); return unmodifiableMap( map );
} }
@ -282,7 +288,8 @@ public class OptionSet {
* @return the detected non-option arguments * @return the detected non-option arguments
*/ */
public List<?> nonOptionArguments() { public List<?> nonOptionArguments() {
return unmodifiableList( valuesOf( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) ); AbstractOptionSpec<?> spec = detectedOptions.get( NonOptionArgumentSpec.NAME );
return valuesOf( spec );
} }
void add( AbstractOptionSpec<?> spec ) { void add( AbstractOptionSpec<?> spec ) {
@ -298,7 +305,7 @@ public class OptionSet {
List<String> optionArguments = optionsToArguments.get( spec ); List<String> optionArguments = optionsToArguments.get( spec );
if ( optionArguments == null ) { if ( optionArguments == null ) {
optionArguments = new ArrayList<String>(); optionArguments = new ArrayList<>();
optionsToArguments.put( spec, optionArguments ); optionsToArguments.put( spec, optionArguments );
} }
@ -315,25 +322,22 @@ public class OptionSet {
return false; return false;
OptionSet other = (OptionSet) that; OptionSet other = (OptionSet) that;
Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments );
new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments ); Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments = new HashMap<>( other.optionsToArguments );
Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments =
new HashMap<AbstractOptionSpec<?>, List<String>>( other.optionsToArguments );
return detectedOptions.equals( other.detectedOptions ) return detectedOptions.equals( other.detectedOptions )
&& thisOptionsToArguments.equals( otherOptionsToArguments ); && thisOptionsToArguments.equals( otherOptionsToArguments );
} }
@Override @Override
public int hashCode() { public int hashCode() {
Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments );
new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments );
return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode(); return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode();
} }
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private <V> List<V> defaultValuesFor( String option ) { private <V> List<V> defaultValuesFor( String option ) {
if ( defaultValues.containsKey( option ) ) if ( defaultValues.containsKey( option ) )
return (List<V>) defaultValues.get( option ); return unmodifiableList( (List<V>) defaultValues.get( option ) );
return emptyList(); return emptyList();
} }
@ -343,7 +347,7 @@ public class OptionSet {
} }
private static Map<String, List<?>> defaultValues( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) { private static Map<String, List<?>> defaultValues( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) {
Map<String, List<?>> defaults = new HashMap<String, List<?>>(); Map<String, List<?>> defaults = new HashMap<>();
for ( Map.Entry<String, AbstractOptionSpec<?>> each : recognizedSpecs.entrySet() ) for ( Map.Entry<String, AbstractOptionSpec<?>> each : recognizedSpecs.entrySet() )
defaults.put( each.getKey(), each.getValue().defaultValues() ); defaults.put( each.getKey(), each.getValue().defaultValues() );
return defaults; return defaults;

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,6 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -116,7 +115,7 @@ public interface OptionSpec<V> {
/** /**
* @return the string representations of this option * @return the string representations of this option
*/ */
Collection<String> options(); List<String> options();
/** /**
* Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line * Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -56,7 +56,6 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -90,7 +89,7 @@ import java.util.List;
public class OptionSpecBuilder extends NoArgumentOptionSpec { public class OptionSpecBuilder extends NoArgumentOptionSpec {
private final OptionParser parser; private final OptionParser parser;
OptionSpecBuilder( OptionParser parser, Collection<String> options, String description ) { OptionSpecBuilder( OptionParser parser, List<String> options, String description ) {
super( options, description ); super( options, description );
this.parser = parser; this.parser = parser;
@ -107,8 +106,7 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec {
* @return a specification for the option * @return a specification for the option
*/ */
public ArgumentAcceptingOptionSpec<String> withRequiredArg() { public ArgumentAcceptingOptionSpec<String> withRequiredArg() {
ArgumentAcceptingOptionSpec<String> newSpec = ArgumentAcceptingOptionSpec<String> newSpec = new RequiredArgumentOptionSpec<>( options(), description() );
new RequiredArgumentOptionSpec<String>( options(), description() );
parser.recognize( newSpec ); parser.recognize( newSpec );
return newSpec; return newSpec;
@ -121,7 +119,7 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec {
*/ */
public ArgumentAcceptingOptionSpec<String> withOptionalArg() { public ArgumentAcceptingOptionSpec<String> withOptionalArg() {
ArgumentAcceptingOptionSpec<String> newSpec = ArgumentAcceptingOptionSpec<String> newSpec =
new OptionalArgumentOptionSpec<String>( options(), description() ); new OptionalArgumentOptionSpec<>( options(), description() );
parser.recognize( newSpec ); parser.recognize( newSpec );
return newSpec; return newSpec;
@ -141,9 +139,8 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec {
*/ */
public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) { public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) {
List<String> dependents = validatedDependents( dependent, otherDependents ); List<String> dependents = validatedDependents( dependent, otherDependents );
for ( String each : dependents ) { for ( String each : dependents )
parser.requiredIf( options(), each ); parser.requiredIf( options(), each );
}
return this; return this;
} }
@ -210,8 +207,91 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec {
return this; 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 ) { private List<String> validatedDependents( String dependent, String... otherDependents ) {
List<String> dependents = new ArrayList<String>(); List<String> dependents = new ArrayList<>();
dependents.add( dependent ); dependents.add( dependent );
Collections.addAll( dependents, otherDependents ); Collections.addAll( dependents, otherDependents );

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
/** /**
* Specification of an option that accepts an optional argument. * Specification of an option that accepts an optional argument.
@ -68,7 +68,7 @@ class OptionalArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> {
super( option, false ); super( option, false );
} }
OptionalArgumentOptionSpec( Collection<String> options, String description ) { OptionalArgumentOptionSpec( List<String> options, String description ) {
super( options, false, description ); super( options, false, description );
} }
@ -77,7 +77,7 @@ class OptionalArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> {
if ( arguments.hasMore() ) { if ( arguments.hasMore() ) {
String nextArgument = arguments.peek(); String nextArgument = arguments.peek();
if ( !parser.looksLikeAnOption( nextArgument ) ) if ( !parser.looksLikeAnOption( nextArgument ) && canConvertArgument( nextArgument ) )
handleOptionArgument( parser, detectedOptions, arguments ); handleOptionArgument( parser, detectedOptions, arguments );
else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) ) else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) )
addArguments( detectedOptions, arguments.next() ); addArguments( detectedOptions, arguments.next() );

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
import static java.lang.Character.*; import static java.lang.Character.*;
@ -97,7 +97,7 @@ final class ParserRules {
ensureLegalOptionCharacter( option.charAt( i ) ); ensureLegalOptionCharacter( option.charAt( i ) );
} }
static void ensureLegalOptions( Collection<String> options ) { static void ensureLegalOptions( List<String> options ) {
for ( String each : options ) for ( String each : options )
ensureLegalOption( each ); ensureLegalOption( each );
} }
@ -108,7 +108,7 @@ final class ParserRules {
} }
private static boolean isAllowedPunctuation( char option ) { private static boolean isAllowedPunctuation( char option ) {
String allowedPunctuation = "?." + HYPHEN_CHAR; String allowedPunctuation = "?._" + HYPHEN_CHAR;
return allowedPunctuation.indexOf( option ) != -1; return allowedPunctuation.indexOf( option ) != -1;
} }
} }

View File

@ -1,3 +1,3 @@
JOpt Simple, Version 4.6 JOpt Simple, Version 5.0.4
https://pholser.github.io/jopt-simple/ https://pholser.github.io/jopt-simple/

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
/** /**
* Specification of an option that accepts a required argument. * Specification of an option that accepts a required argument.
@ -68,14 +68,14 @@ class RequiredArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> {
super( option, true ); super( option, true );
} }
RequiredArgumentOptionSpec( Collection<String> options, String description ) { RequiredArgumentOptionSpec( List<String> options, String description ) {
super( options, true, description ); super( options, true, description );
} }
@Override @Override
protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
if ( !arguments.hasMore() ) if ( !arguments.hasMore() )
throw new OptionMissingRequiredArgumentException( options() ); throw new OptionMissingRequiredArgumentException( this );
addArguments( detectedOptions, arguments.next() ); addArguments( detectedOptions, arguments.next() );
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,30 +55,21 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import static java.util.Collections.*; import java.util.List;
/** /**
* Thrown when the option parser detects an unacceptable number of {@code linkplain NonOptionArgumentSpec * Thrown when options marked as allowed are specified on the command line, but the options they depend upon are
* non-option arguments}. * present/not present.
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
class UnacceptableNumberOfNonOptionsException extends OptionException { class UnavailableOptionException extends OptionException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
private final int minimum;
private final int maximum;
private final int actual;
UnacceptableNumberOfNonOptionsException( int minimum, int maximum, int actual ) { UnavailableOptionException( List<? extends OptionSpec<?>> forbiddenOptions ) {
super( singletonList( NonOptionArgumentSpec.NAME ) ); super( forbiddenOptions );
this.minimum = minimum;
this.maximum = maximum;
this.actual = actual;
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return String.format( "actual = %d, minimum = %d, maximum = %d", actual, minimum, maximum ); return new Object[] { multipleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,7 +55,7 @@
package jdk.internal.joptsimple; package jdk.internal.joptsimple;
import java.util.Collection; import java.util.List;
import static java.util.Collections.*; import static java.util.Collections.*;
@ -71,12 +71,12 @@ class UnconfiguredOptionException extends OptionException {
this( singletonList( option ) ); this( singletonList( option ) );
} }
UnconfiguredOptionException( Collection<String> options ) { UnconfiguredOptionException( List<String> options ) {
super( options ); super( options );
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return "Option " + multipleOptionMessage() + " has not been configured on this parser"; return new Object[] { multipleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -70,7 +70,7 @@ class UnrecognizedOptionException extends OptionException {
} }
@Override @Override
public String getMessage() { Object[] messageArguments() {
return singleOptionMessage() + " is not a recognized option"; return new Object[] { singleOptionString() };
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -76,7 +76,7 @@ public interface ValueConverter<V> {
* *
* @return the target class for conversion * @return the target class for conversion
*/ */
Class<V> valueType(); Class<? extends V> valueType();
/** /**
* Gives a string that describes the pattern of the values this converter expects, if any. For example, a date * Gives a string that describes the pattern of the values this converter expects, if any. For example, a date

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -84,37 +84,41 @@ import java.util.TreeMap;
* *
* @param <V> a constraint on the types of the values in the map * @param <V> a constraint on the types of the values in the map
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @see <a href="http://www.perldoc.com/perl5.8.0/lib/Text/Abbrev.html">Perl's Text::Abbrev module</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> { public class AbbreviationMap<V> implements OptionNameMap<V> {
private final Map<Character, AbbreviationMap<V>> children = new TreeMap<>();
private String key; private String key;
private V value; private V value;
private final Map<Character, AbbreviationMap<V>> children = new TreeMap<Character, AbbreviationMap<V>>();
private int keysBeyond; private int keysBeyond;
/** /**
* <p>Tells whether the given key is in the map, or whether the given key is a unique * <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> * abbreviation of a key that is in the map.</p>
* *
* @param aKey key to look up * @param key key to look up
* @return {@code true} if {@code key} is present in the map * @return {@code true} if {@code key} is present in the map
* @throws NullPointerException if {@code key} is {@code null} * @throws NullPointerException if {@code key} is {@code null}
*/ */
public boolean contains( String aKey ) { @Override
return get( aKey ) != null; public boolean contains(String key) {
return get(key) != null;
} }
/** /**
* <p>Answers the value associated with the given key. The key can be a unique * <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> * abbreviation of a key that is in the map. </p>
* *
* @param aKey key to look up * @param key key to look up
* @return the value associated with {@code aKey}; or {@code null} if there is no * @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 * such value or {@code aKey} is not a unique abbreviation of a key in the map
* @throws NullPointerException if {@code aKey} is {@code null} * @throws NullPointerException if {@code aKey} is {@code null}
*/ */
public V get( String aKey ) { @Override
char[] chars = charsOf( aKey ); public V get( String key ) {
char[] chars = charsOf( key );
AbbreviationMap<V> child = this; AbbreviationMap<V> child = this;
for ( char each : chars ) { for ( char each : chars ) {
@ -130,18 +134,19 @@ public class AbbreviationMap<V> {
* <p>Associates a given value with a given key. If there was a previous * <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> * association, the old value is replaced with the new one.</p>
* *
* @param aKey key to create in the map * @param key key to create in the map
* @param newValue value to associate with the key * @param newValue value to associate with the key
* @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null} * @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null}
* @throws IllegalArgumentException if {@code aKey} is a zero-length string * @throws IllegalArgumentException if {@code aKey} is a zero-length string
*/ */
public void put( String aKey, V newValue ) { @Override
public void put( String key, V newValue ) {
if ( newValue == null ) if ( newValue == null )
throw new NullPointerException(); throw new NullPointerException();
if ( aKey.length() == 0 ) if ( key.length() == 0 )
throw new IllegalArgumentException(); throw new IllegalArgumentException();
char[] chars = charsOf( aKey ); char[] chars = charsOf(key);
add( chars, newValue, 0, chars.length ); add( chars, newValue, 0, chars.length );
} }
@ -154,6 +159,7 @@ public class AbbreviationMap<V> {
* @throws NullPointerException if {@code keys} or {@code newValue} is {@code null} * @throws NullPointerException if {@code keys} or {@code newValue} is {@code null}
* @throws IllegalArgumentException if any of {@code keys} is a zero-length string * @throws IllegalArgumentException if any of {@code keys} is a zero-length string
*/ */
@Override
public void putAll( Iterable<String> keys, V newValue ) { public void putAll( Iterable<String> keys, V newValue ) {
for ( String each : keys ) for ( String each : keys )
put( each, newValue ); put( each, newValue );
@ -170,7 +176,7 @@ public class AbbreviationMap<V> {
char nextChar = chars[ offset ]; char nextChar = chars[ offset ];
AbbreviationMap<V> child = children.get( nextChar ); AbbreviationMap<V> child = children.get( nextChar );
if ( child == null ) { if ( child == null ) {
child = new AbbreviationMap<V>(); child = new AbbreviationMap<>();
children.put( nextChar, child ); children.put( nextChar, child );
} }
@ -188,15 +194,16 @@ public class AbbreviationMap<V> {
/** /**
* <p>If the map contains the given key, dissociates the key from its value.</p> * <p>If the map contains the given key, dissociates the key from its value.</p>
* *
* @param aKey key to remove * @param key key to remove
* @throws NullPointerException if {@code aKey} is {@code null} * @throws NullPointerException if {@code aKey} is {@code null}
* @throws IllegalArgumentException if {@code aKey} is a zero-length string * @throws IllegalArgumentException if {@code aKey} is a zero-length string
*/ */
public void remove( String aKey ) { @Override
if ( aKey.length() == 0 ) public void remove( String key ) {
if ( key.length() == 0 )
throw new IllegalArgumentException(); throw new IllegalArgumentException();
char[] keyChars = charsOf( aKey ); char[] keyChars = charsOf(key);
remove( keyChars, 0, keyChars.length ); remove( keyChars, 0, keyChars.length );
} }
@ -242,8 +249,9 @@ public class AbbreviationMap<V> {
* *
* @return a Java map corresponding to this abbreviation map * @return a Java map corresponding to this abbreviation map
*/ */
@Override
public Map<String, V> toJavaUtilMap() { public Map<String, V> toJavaUtilMap() {
Map<String, V> mappings = new TreeMap<String, V>(); Map<String, V> mappings = new TreeMap<>();
addToMappings( mappings ); addToMappings( mappings );
return mappings; return mappings;
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -62,7 +62,7 @@ import java.util.Map;
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/ */
public final class Classes { public final class Classes {
private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<Class<?>, Class<?>>( 13 ); private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<>( 13 );
static { static {
WRAPPERS.put( boolean.class, Boolean.class ); WRAPPERS.put( boolean.class, Boolean.class );

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -58,7 +58,6 @@ package jdk.internal.joptsimple.internal;
import java.text.BreakIterator; import java.text.BreakIterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import static java.text.BreakIterator.*; import static java.text.BreakIterator.*;
@ -82,7 +81,7 @@ class Columns {
List<String> options = piecesOf( row.option, optionWidth ); List<String> options = piecesOf( row.option, optionWidth );
List<String> descriptions = piecesOf( row.description, descriptionWidth ); List<String> descriptions = piecesOf( row.description, descriptionWidth );
List<Row> rows = new ArrayList<Row>(); List<Row> rows = new ArrayList<>();
for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i ) for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i )
rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) ); rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) );
@ -94,7 +93,7 @@ class Columns {
} }
private List<String> piecesOf( String raw, int width ) { private List<String> piecesOf( String raw, int width ) {
List<String> pieces = new ArrayList<String>(); List<String> pieces = new ArrayList<>();
for ( String each : raw.trim().split( LINE_SEPARATOR ) ) for ( String each : raw.trim().split( LINE_SEPARATOR ) )
pieces.addAll( piecesOfEmbeddedLine( each, width ) ); pieces.addAll( piecesOfEmbeddedLine( each, width ) );
@ -103,9 +102,9 @@ class Columns {
} }
private List<String> piecesOfEmbeddedLine( String line, int width ) { private List<String> piecesOfEmbeddedLine( String line, int width ) {
List<String> pieces = new ArrayList<String>(); List<String> pieces = new ArrayList<>();
BreakIterator words = BreakIterator.getLineInstance( Locale.US ); BreakIterator words = BreakIterator.getLineInstance();
words.setText( line ); words.setText( line );
StringBuilder nextPiece = new StringBuilder(); StringBuilder nextPiece = new StringBuilder();

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 jdk.internal.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 );
}
}

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,22 +55,23 @@
package jdk.internal.joptsimple.internal; package jdk.internal.joptsimple.internal;
/** import java.util.Map;
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
*/
public final class Objects {
private Objects() {
throw new UnsupportedOperationException();
}
/** /**
* Rejects {@code null} references. * Map-like interface for storing String-value pairs.
* *
* @param target reference to check * @param <V> type of values stored in the map
* @throws NullPointerException if {@code target} is {@code null} */
*/ public interface OptionNameMap<V> {
public static void ensureNotNull( Object target ) { boolean contains( String key );
if ( target == null )
throw new NullPointerException(); 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();
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -98,22 +98,20 @@ public final class Reflection {
private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) { private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) {
try { try {
Method valueOf = clazz.getDeclaredMethod( "valueOf", String.class ); Method valueOf = clazz.getMethod( "valueOf", String.class );
if ( meetsConverterRequirements( valueOf, clazz ) ) if ( meetsConverterRequirements( valueOf, clazz ) )
return new MethodInvokingValueConverter<V>( valueOf, clazz ); return new MethodInvokingValueConverter<>( valueOf, clazz );
return null; return null;
} } catch ( NoSuchMethodException ignored ) {
catch ( NoSuchMethodException ignored ) {
return null; return null;
} }
} }
private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) { private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) {
try { try {
return new ConstructorInvokingValueConverter<V>( clazz.getConstructor( String.class ) ); return new ConstructorInvokingValueConverter<>( clazz.getConstructor( String.class ) );
} } catch ( NoSuchMethodException ignored ) {
catch ( NoSuchMethodException ignored ) {
return null; return null;
} }
} }
@ -130,8 +128,7 @@ public final class Reflection {
public static <T> T instantiate( Constructor<T> constructor, Object... args ) { public static <T> T instantiate( Constructor<T> constructor, Object... args ) {
try { try {
return constructor.newInstance( args ); return constructor.newInstance( args );
} } catch ( Exception ex ) {
catch ( Exception ex ) {
throw reflectionException( ex ); throw reflectionException( ex );
} }
} }
@ -147,8 +144,7 @@ public final class Reflection {
public static Object invoke( Method method, Object... args ) { public static Object invoke( Method method, Object... args ) {
try { try {
return method.invoke( null, args ); return method.invoke( null, args );
} } catch ( Exception ex ) {
catch ( Exception ex ) {
throw reflectionException( ex ); throw reflectionException( ex );
} }
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,8 +55,8 @@
package jdk.internal.joptsimple.internal; package jdk.internal.joptsimple.internal;
import java.util.LinkedHashSet; import java.util.ArrayList;
import java.util.Set; import java.util.List;
import static java.lang.Math.*; import static java.lang.Math.*;
@ -68,7 +68,8 @@ import static jdk.internal.joptsimple.internal.Strings.*;
public class Rows { public class Rows {
private final int overallWidth; private final int overallWidth;
private final int columnSeparatorWidth; private final int columnSeparatorWidth;
private final Set<Row> rows = new LinkedHashSet<Row>(); private final List<Row> rows = new ArrayList<>();
private int widthOfWidestOption; private int widthOfWidestOption;
private int widthOfWidestDescription; private int widthOfWidestDescription;
@ -87,7 +88,7 @@ public class Rows {
widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() ); widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() );
} }
private void reset() { public void reset() {
rows.clear(); rows.clear();
widthOfWidestOption = 0; widthOfWidestOption = 0;
widthOfWidestDescription = 0; widthOfWidestDescription = 0;
@ -96,7 +97,7 @@ public class Rows {
public void fitToWidth() { public void fitToWidth() {
Columns columns = new Columns( optionWidth(), descriptionWidth() ); Columns columns = new Columns( optionWidth(), descriptionWidth() );
Set<Row> fitted = new LinkedHashSet<Row>(); List<Row> fitted = new ArrayList<>();
for ( Row each : rows ) for ( Row each : rows )
fitted.addAll( columns.fit( each ) ); fitted.addAll( columns.fit( each ) );
@ -122,7 +123,7 @@ public class Rows {
} }
private int descriptionWidth() { private int descriptionWidth() {
return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestDescription ); return min( overallWidth - optionWidth() - columnSeparatorWidth, widthOfWidestDescription );
} }
private StringBuilder pad( StringBuilder buffer, String s, int length ) { private StringBuilder pad( StringBuilder buffer, String s, int length ) {

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 jdk.internal.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 );
}
}

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -56,7 +56,6 @@
package jdk.internal.joptsimple.internal; package jdk.internal.joptsimple.internal;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import static java.lang.System.*; import static java.lang.System.*;
import static java.util.Arrays.*; import static java.util.Arrays.*;
@ -66,7 +65,6 @@ import static java.util.Arrays.*;
*/ */
public final class Strings { public final class Strings {
public static final String EMPTY = ""; public static final String EMPTY = "";
public static final String SINGLE_QUOTE = "'";
public static final String LINE_SEPARATOR = getProperty( "line.separator" ); public static final String LINE_SEPARATOR = getProperty( "line.separator" );
private Strings() { private Strings() {
@ -96,7 +94,7 @@ public final class Strings {
* @return {@code true} if the target string is null or empty * @return {@code true} if the target string is null or empty
*/ */
public static boolean isNullOrEmpty( String target ) { public static boolean isNullOrEmpty( String target ) {
return target == null || EMPTY.equals( target ); return target == null || target.isEmpty();
} }
@ -132,7 +130,7 @@ public final class Strings {
* @param separator the separator * @param separator the separator
* @return the joined string * @return the joined string
*/ */
public static String join( List<String> pieces, String separator ) { public static String join( Iterable<String> pieces, String separator ) {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
for ( Iterator<String> iter = pieces.iterator(); iter.hasNext(); ) { for ( Iterator<String> iter = pieces.iterator(); iter.hasNext(); ) {

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -59,9 +59,11 @@ import java.text.DateFormat;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale;
import jdk.internal.joptsimple.ValueConversionException; import jdk.internal.joptsimple.ValueConversionException;
import jdk.internal.joptsimple.ValueConverter; import jdk.internal.joptsimple.ValueConverter;
import jdk.internal.joptsimple.internal.Messages;
/** /**
* Converts values to {@link Date}s using a {@link DateFormat} object. * Converts values to {@link Date}s using a {@link DateFormat} object.
@ -121,10 +123,22 @@ public class DateConverter implements ValueConverter<Date> {
} }
private String message( String value ) { private String message( String value ) {
String message = "Value [" + value + "] does not match date/time pattern"; String key;
if ( formatter instanceof SimpleDateFormat ) Object[] arguments;
message += " [" + ( (SimpleDateFormat) formatter ).toPattern() + ']';
return message; 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(),
"jdk.internal.joptsimple.ExceptionMessages",
DateConverter.class,
key,
arguments );
} }
} }

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 jdk.internal.joptsimple.util;
import java.text.MessageFormat;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.ResourceBundle;
import jdk.internal.joptsimple.ValueConversionException;
import jdk.internal.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( "jdk.internal.joptsimple.ExceptionMessages" );
Object[] arguments = new Object[] { value, valuePattern() };
String template = bundle.getString( EnumConverter.class.getName() + ".message" );
return new MessageFormat( template ).format( arguments );
}
}

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -57,9 +57,11 @@ package jdk.internal.joptsimple.util;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Locale;
import jdk.internal.joptsimple.ValueConversionException; import jdk.internal.joptsimple.ValueConversionException;
import jdk.internal.joptsimple.ValueConverter; import jdk.internal.joptsimple.ValueConverter;
import jdk.internal.joptsimple.internal.Messages;
/** /**
* Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}. * Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}.
@ -70,8 +72,9 @@ public class InetAddressConverter implements ValueConverter<InetAddress> {
public InetAddress convert( String value ) { public InetAddress convert( String value ) {
try { try {
return InetAddress.getByName( value ); return InetAddress.getByName( value );
} catch ( UnknownHostException e ) { }
throw new ValueConversionException( "Cannot convert value [" + value + " into an InetAddress", e ); catch ( UnknownHostException e ) {
throw new ValueConversionException( message( value ) );
} }
} }
@ -82,4 +85,13 @@ public class InetAddressConverter implements ValueConverter<InetAddress> {
public String valuePattern() { public String valuePattern() {
return null; return null;
} }
private String message( String value ) {
return Messages.message(
Locale.getDefault(),
"jdk.internal.joptsimple.ExceptionMessages",
InetAddressConverter.class,
"message",
value );
}
} }

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -60,7 +60,7 @@ import static jdk.internal.joptsimple.internal.Strings.*;
/** /**
* <p>A simple string key/string value pair.</p> * <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 <kbd>key=value</kbd>, such as JVM * <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> * command line system properties.</p>
* *
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
@ -75,7 +75,7 @@ public final class KeyValuePair {
} }
/** /**
* Parses a string assumed to be of the form <kbd>key=value</kbd> into its parts. * Parses a string assumed to be of the form {@code key=value} into its parts.
* *
* @param asString key-value string * @param asString key-value string
* @return a key-value pair * @return a key-value pair
@ -84,7 +84,7 @@ public final class KeyValuePair {
public static KeyValuePair valueOf( String asString ) { public static KeyValuePair valueOf( String asString ) {
int equalsIndex = asString.indexOf( '=' ); int equalsIndex = asString.indexOf( '=' );
if ( equalsIndex == -1 ) if ( equalsIndex == -1 )
return new KeyValuePair( asString, EMPTY ); return new KeyValuePair( asString, null );
String aKey = asString.substring( 0, equalsIndex ); String aKey = asString.substring( 0, equalsIndex );
String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 ); String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 );

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.joptsimple.util;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import jdk.internal.joptsimple.ValueConversionException;
import jdk.internal.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( "jdk.internal.joptsimple.ExceptionMessages" );
Object[] arguments = new Object[] { value, valuePattern() };
String template = bundle.getString( PathConverter.class.getName() + "." + errorKey + ".message" );
return new MessageFormat( template ).format( arguments );
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.joptsimple.util;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Enum for checking common conditions of files and directories.
*
* @see jdk.internal.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;
}
}

View File

@ -31,7 +31,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2014 Paul R. Holser, Jr. * Copyright (c) 2004-2015 Paul R. Holser, Jr.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -55,9 +55,11 @@
package jdk.internal.joptsimple.util; package jdk.internal.joptsimple.util;
import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static java.util.regex.Pattern.*; import static java.util.regex.Pattern.*;
import static jdk.internal.joptsimple.internal.Messages.message;
import jdk.internal.joptsimple.ValueConversionException; import jdk.internal.joptsimple.ValueConversionException;
import jdk.internal.joptsimple.ValueConverter; import jdk.internal.joptsimple.ValueConverter;
@ -96,8 +98,7 @@ public class RegexMatcher implements ValueConverter<String> {
public String convert( String value ) { public String convert( String value ) {
if ( !pattern.matcher( value ).matches() ) { if ( !pattern.matcher( value ).matches() ) {
throw new ValueConversionException( raiseValueConversionFailure( value );
"Value [" + value + "] did not match regex [" + pattern.pattern() + ']' );
} }
return value; return value;
@ -110,4 +111,15 @@ public class RegexMatcher implements ValueConverter<String> {
public String valuePattern() { public String valuePattern() {
return pattern.pattern(); return pattern.pattern();
} }
private void raiseValueConversionFailure( String value ) {
String message = message(
Locale.getDefault(),
"jdk.internal.joptsimple.ExceptionMessages",
RegexMatcher.class,
"message",
value,
pattern.pattern() );
throw new ValueConversionException( message );
}
} }

View File

@ -1,4 +1,4 @@
## jopt-simple v4.6 ## jopt-simple v5.0.4
### MIT License ### MIT License
<pre> <pre>

View File

@ -1224,7 +1224,7 @@ public class JmodTask {
all.put(CMD_FILENAME, new OptionDescriptor() { all.put(CMD_FILENAME, new OptionDescriptor() {
@Override @Override
public Collection<String> options() { public List<String> options() {
List<String> ret = new ArrayList<>(); List<String> ret = new ArrayList<>();
ret.add(CMD_FILENAME); ret.add(CMD_FILENAME);
return ret; return ret;
@ -1314,7 +1314,7 @@ public class JmodTask {
.withValuesConvertedBy(new PatternConverter()); .withValuesConvertedBy(new PatternConverter());
OptionSpec<Void> help OptionSpec<Void> help
= parser.acceptsAll(Set.of("h", "help", "?"), getMessage("main.opt.help")) = parser.acceptsAll(List.of("h", "help", "?"), getMessage("main.opt.help"))
.forHelp(); .forHelp();
OptionSpec<Void> helpExtra OptionSpec<Void> helpExtra
@ -1347,7 +1347,7 @@ public class JmodTask {
.withValuesConvertedBy(DirPathConverter.INSTANCE); .withValuesConvertedBy(DirPathConverter.INSTANCE);
OptionSpec<List<Path>> modulePath OptionSpec<List<Path>> modulePath
= parser.acceptsAll(Set.of("p", "module-path"), = parser.acceptsAll(List.of("p", "module-path"),
getMessage("main.opt.module-path")) getMessage("main.opt.module-path"))
.withRequiredArg() .withRequiredArg()
.withValuesConvertedBy(DirPathConverter.INSTANCE); .withValuesConvertedBy(DirPathConverter.INSTANCE);

View File

@ -100,7 +100,7 @@ public class JmodNegativeTest {
jmod("--badOption") jmod("--badOption")
.assertFailure() .assertFailure()
.resultChecker(r -> .resultChecker(r ->
assertContains(r.output, "Error: 'badOption' is not a recognized option") assertContains(r.output, "Error: badOption is not a recognized option")
); );
} }

View File

@ -111,7 +111,7 @@ public class JmodTest {
Path jmod = MODS_DIR.resolve("apa.jmod"); Path jmod = MODS_DIR.resolve("apa.jmod");
jmod("create", jmod("create",
"--libs=", libDir.toString(), "--libs=" + libDir.toString(),
"--class-path", classesDir.toString(), "--class-path", classesDir.toString(),
jmod.toString()) jmod.toString())
.assertSuccess(); .assertSuccess();
@ -310,7 +310,7 @@ public class JmodTest {
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
jmod("create", jmod("create",
"--libs=", lp.toString(), "--libs=" + lp.toString(),
"--class-path", cp.toString(), "--class-path", cp.toString(),
jmod.toString()) jmod.toString())
.assertSuccess() .assertSuccess()
@ -335,8 +335,8 @@ public class JmodTest {
jmod("create", jmod("create",
"--conf", cf.toString(), "--conf", cf.toString(),
"--cmds=", bp.toString(), "--cmds=" + bp.toString(),
"--libs=", lp.toString(), "--libs=" + lp.toString(),
"--class-path", cp.toString(), "--class-path", cp.toString(),
jmod.toString()) jmod.toString())
.assertSuccess() .assertSuccess()
@ -361,7 +361,7 @@ public class JmodTest {
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
jmod("create", jmod("create",
"--libs=", lp.toString(), "--libs=" + lp.toString(),
"--class-path", cp.toString(), "--class-path", cp.toString(),
"--exclude", "**internal**", "--exclude", "**internal**",
"--exclude", "first.so", "--exclude", "first.so",