diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 7a2e397aa5d..058f9a58eb8 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -325,6 +325,10 @@ jdk.internal.le_COPY += .properties ################################################################################ +jdk.internal.opt_COPY += .properties + +################################################################################ + jdk.jcmd_COPY += _options ################################################################################ diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java index 0d39af447f7..f101a2aa19f 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -56,7 +56,6 @@ package jdk.internal.joptsimple; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import static java.util.Collections.*; @@ -70,22 +69,22 @@ import static jdk.internal.joptsimple.internal.Strings.*; * @param represents the type of the arguments this option accepts * @author Paul Holser */ -abstract class AbstractOptionSpec implements OptionSpec, OptionDescriptor { - private final List options = new ArrayList(); +public abstract class AbstractOptionSpec implements OptionSpec, OptionDescriptor { + private final List options = new ArrayList<>(); private final String description; private boolean forHelp; - protected AbstractOptionSpec( String option ) { + AbstractOptionSpec( String option ) { this( singletonList( option ), EMPTY ); } - protected AbstractOptionSpec( Collection options, String description ) { + AbstractOptionSpec( List options, String description ) { arrangeOptions( options ); this.description = description; } - public final Collection options() { + public final List options() { return unmodifiableList( options ); } @@ -119,12 +118,8 @@ abstract class AbstractOptionSpec implements OptionSpec, OptionDescriptor protected V convertWith( ValueConverter converter, String argument ) { try { return Reflection.convertWith( converter, argument ); - } - catch ( ReflectionException ex ) { - throw new OptionArgumentConversionException( options(), argument, ex ); - } - catch ( ValueConversionException ex ) { - throw new OptionArgumentConversionException( options(), argument, ex ); + } catch ( ReflectionException | ValueConversionException ex ) { + throw new OptionArgumentConversionException( this, argument, ex ); } } @@ -139,14 +134,14 @@ abstract class AbstractOptionSpec implements OptionSpec, OptionDescriptor abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, String detectedArgument ); - private void arrangeOptions( Collection unarranged ) { + private void arrangeOptions( List unarranged ) { if ( unarranged.size() == 1 ) { options.addAll( unarranged ); return; } - List shortOptions = new ArrayList(); - List longOptions = new ArrayList(); + List shortOptions = new ArrayList<>(); + List longOptions = new ArrayList<>(); for ( String each : unarranged ) { if ( each.length() == 1 ) diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java index 12532c6b3bc..68bcd0ec7ea 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,26 +55,40 @@ package jdk.internal.joptsimple; +import jdk.internal.joptsimple.internal.Messages; + +import java.util.Locale; + import static java.util.Collections.*; import static jdk.internal.joptsimple.ParserRules.*; /** - * Represents the "-W" form of long option specification. + * Represents the {@code "-W"} form of long option specification. * * @author Paul Holser */ class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec { 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 protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { if ( !arguments.hasMore() ) - throw new OptionMissingRequiredArgumentException( options() ); + throw new OptionMissingRequiredArgumentException( this ); arguments.treatNextAsLongOption(); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java index ffb083746e9..b3064afe6a0 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -56,13 +56,12 @@ package jdk.internal.joptsimple; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.StringTokenizer; 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.Strings.*; @@ -88,12 +87,13 @@ import static jdk.internal.joptsimple.internal.Strings.*; public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec { private static final char NIL_VALUE_SEPARATOR = '\u0000'; - private boolean optionRequired; private final boolean argumentRequired; + private final List defaultValues = new ArrayList<>(); + + private boolean optionRequired; private ValueConverter converter; private String argumentDescription = ""; private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR ); - private final List defaultValues = new ArrayList(); ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) { super( option ); @@ -101,7 +101,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< this.argumentRequired = argumentRequired; } - ArgumentAcceptingOptionSpec( Collection options, boolean argumentRequired, String description ) { + ArgumentAcceptingOptionSpec( List options, boolean argumentRequired, String description ) { super( options, description ); this.argumentRequired = argumentRequired; @@ -182,7 +182,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< * * * - *

Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.

+ *

Then options.valuesOf( "z" ) would yield the list {@code [foo, bar, baz, fizz, buzz]}.

* *

You cannot use Unicode U+0000 as the separator.

* @@ -211,7 +211,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< * * * - *

Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.

+ *

Then options.valuesOf( "z" ) would yield the list {@code [foo, bar, baz, fizz, buzz]}.

* *

You cannot use Unicode U+0000 in the separator.

* @@ -236,8 +236,9 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< * @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are * {@code null} */ - @SuppressWarnings("unchecked") - public ArgumentAcceptingOptionSpec defaultsTo( V value, V... values ) { + @SafeVarargs + @SuppressWarnings("varargs") + public final ArgumentAcceptingOptionSpec defaultsTo( V value, V... values ) { addDefaultValue( value ); defaultsTo( values ); @@ -275,7 +276,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< } private void addDefaultValue( V value ) { - ensureNotNull( value ); + requireNonNull( value ); defaultValues.add( value ); } @@ -283,7 +284,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, String detectedArgument ) { - if ( isNullOrEmpty( detectedArgument ) ) + if ( detectedArgument == null ) detectOptionArgument( parser, arguments, detectedOptions ); else addArguments( detectedOptions, detectedArgument ); @@ -314,8 +315,7 @@ public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec< while ( lexer.hasMoreTokens() ) convert( lexer.nextToken() ); return true; - } - catch ( OptionException ignored ) { + } catch ( OptionException ignored ) { return false; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java index e8cf157f99c..04af7965aea 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java index ba72af36f90..8e7fe5146ad 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,14 +55,9 @@ package jdk.internal.joptsimple; -import java.util.Collection; -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 java.util.*; +import jdk.internal.joptsimple.internal.Messages; import jdk.internal.joptsimple.internal.Rows; import jdk.internal.joptsimple.internal.Strings; @@ -73,10 +68,17 @@ import static jdk.internal.joptsimple.internal.Strings.*; /** *

A help formatter that allows configuration of overall row width and column separator width.

* - *

The formatter produces a two-column output. The left column is for the options, and the right column for their + *

The formatter produces output in two sections: one for the options, and one for non-option arguments.

+ * + *

The options section has two columns: the left column for the options, and the right column for their * descriptions. The formatter will allow as much space as possible for the descriptions, by minimizing the option * column's width, no greater than slightly less than half the overall desired width.

* + *

The non-option arguments section is one column, occupying as much width as it can.

+ * + *

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.

+ * * @author Paul Holser */ public class BuiltinHelpFormatter implements HelpFormatter { @@ -102,7 +104,20 @@ public class BuiltinHelpFormatter implements HelpFormatter { optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth ); } + /** + * {@inheritDoc} + * + *

This implementation:

+ *
    + *
  • Sorts the given descriptors by their first elements of {@link OptionDescriptor#options()}
  • + *
  • Passes the resulting sorted set to {@link #addRows(java.util.Collection)}
  • + *
  • Returns the result of {@link #formattedHelpOutput()}
  • + *
+ */ public String format( Map options ) { + optionRows.reset(); + nonOptionRows.reset(); + Comparator comparator = new Comparator() { public int compare( OptionDescriptor first, OptionDescriptor second ) { @@ -110,7 +125,7 @@ public class BuiltinHelpFormatter implements HelpFormatter { } }; - Set sorted = new TreeSet( comparator ); + Set sorted = new TreeSet<>( comparator ); sorted.addAll( options.values() ); addRows( sorted ); @@ -118,21 +133,102 @@ public class BuiltinHelpFormatter implements HelpFormatter { 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(); + } + + /** + *

Produces help output for an entire set of options and non-option arguments.

+ * + *

This implementation concatenates:

+ *
    + *
  • the result of {@link #nonOptionOutput()}
  • + *
  • if there is non-option output, a line separator
  • + *
  • the result of {@link #optionOutput()}
  • + *
+ * + * @return help output for entire set of options and non-option arguments + */ + protected String formattedHelpOutput() { StringBuilder formatted = new StringBuilder(); - String nonOptionDisplay = nonOptionRows.render(); + String nonOptionDisplay = nonOptionOutput(); if ( !Strings.isNullOrEmpty( nonOptionDisplay ) ) formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR ); - formatted.append( optionRows.render() ); + formatted.append( optionOutput() ); return formatted.toString(); } - private void addRows( Collection options ) { + /** + *

Adds rows of help output for the given options.

+ * + *

This implementation:

+ *
    + *
  • Calls {@link #addNonOptionsDescription(java.util.Collection)} with the options as the argument
  • + *
  • If there are no options, calls {@link #addOptionRow(String)} with an argument that indicates + * that no options are specified.
  • + *
  • 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.
  • + *
  • Calls {@link #fitRowsToWidth()}.
  • + *
+ * + * @param options descriptors for the configured options of a parser + */ + protected void addRows( Collection options ) { addNonOptionsDescription( options ); if ( options.isEmpty() ) - optionRows.add( "No options specified", "" ); + addOptionRow( message( "no.options.specified" ) ); else { addHeaders( options ); addOptions( options ); @@ -141,34 +237,87 @@ public class BuiltinHelpFormatter implements HelpFormatter { fitRowsToWidth(); } - private void addNonOptionsDescription( Collection options ) { + /** + *

Adds non-option arguments descriptions to the help output.

+ * + *

This implementation:

+ *
    + *
  • {@linkplain #findAndRemoveNonOptionsSpec(java.util.Collection) Finds and removes the non-option + * arguments descriptor}
  • + *
  • {@linkplain #shouldShowNonOptionArgumentDisplay(OptionDescriptor) Decides whether there is + * anything to show for non-option arguments}
  • + *
  • If there is, {@linkplain #addNonOptionRow(String) adds a header row} and + * {@linkplain #addNonOptionRow(String) adds a} + * {@linkplain #createNonOptionArgumentsDisplay(OptionDescriptor) non-option arguments description}
  • + *
+ * + * @param options descriptors for the configured options of a parser + */ + protected void addNonOptionsDescription( Collection options ) { OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options ); if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) { - nonOptionRows.add( "Non-option arguments:", "" ); - nonOptionRows.add(createNonOptionArgumentsDisplay(nonOptions), ""); + addNonOptionRow( message( "non.option.arguments.header" ) ); + addNonOptionRow( createNonOptionArgumentsDisplay( nonOptions ) ); } } - private boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptions ) { - return !Strings.isNullOrEmpty( nonOptions.description() ) - || !Strings.isNullOrEmpty( nonOptions.argumentTypeIndicator() ) - || !Strings.isNullOrEmpty( nonOptions.argumentDescription() ); + /** + *

Decides whether or not to show a non-option arguments help.

+ * + *

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()}.

+ * + * @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) { + /** + *

Creates a non-options argument help string.

+ * + *

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.

+ * + * @param nonOptionDescriptor non-option argument descriptor + * @return help string for non-options + */ + protected String createNonOptionArgumentsDisplay( OptionDescriptor nonOptionDescriptor ) { StringBuilder buffer = new StringBuilder(); - maybeAppendOptionInfo( buffer, nonOptions ); - maybeAppendNonOptionsDescription( buffer, nonOptions ); + maybeAppendOptionInfo( buffer, nonOptionDescriptor ); + maybeAppendNonOptionsDescription( buffer, nonOptionDescriptor ); return buffer.toString(); } - private void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) { + /** + *

Appends help for the given non-option arguments descriptor to the given buffer.

+ * + *

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()}.

+ * + * @param buffer string buffer + * @param nonOptions non-option arguments descriptor + */ + protected void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) { buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" ) .append( nonOptions.description() ); } - private OptionDescriptor findAndRemoveNonOptionsSpec( Collection 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 options ) { for ( Iterator it = options.iterator(); it.hasNext(); ) { OptionDescriptor next = it.next(); if ( next.representsNonOptions() ) { @@ -180,17 +329,32 @@ public class BuiltinHelpFormatter implements HelpFormatter { throw new AssertionError( "no non-options argument spec" ); } - private void addHeaders( Collection options ) { + /** + *

Adds help row headers for option help columns.

+ * + *

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 "-"}.

+ * + * @param options descriptors for the configured options of a parser + */ + protected void addHeaders( Collection options ) { if ( hasRequiredOption( options ) ) { - optionRows.add("Option (* = required)", "Description"); - optionRows.add("---------------------", "-----------"); + addOptionRow( message( "option.header.with.required.indicator" ), message( "description.header" ) ); + addOptionRow( message( "option.divider.with.required.indicator" ), message( "description.divider" ) ); } else { - optionRows.add("Option", "Description"); - optionRows.add("------", "-----------"); + addOptionRow( message( "option.header" ), message( "description.header" ) ); + addOptionRow( message( "option.divider" ), message( "description.divider" ) ); } } - private boolean hasRequiredOption( Collection 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 options ) { for ( OptionDescriptor each : options ) { if ( each.isRequired() ) return true; @@ -199,19 +363,46 @@ public class BuiltinHelpFormatter implements HelpFormatter { return false; } - private void addOptions( Collection options ) { + /** + *

Adds help rows for the given options.

+ * + *

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.

+ * + * @param options descriptors for the configured options of a parser + */ + protected void addOptions( Collection options ) { for ( OptionDescriptor each : options ) { if ( !each.representsNonOptions() ) - optionRows.add( createOptionDisplay( each ), createDescriptionDisplay( each ) ); + addOptionRow( createOptionDisplay( each ), createDescriptionDisplay( each ) ); } } - private String createOptionDisplay( OptionDescriptor descriptor ) { + /** + *

Creates a string for how the given option descriptor is to be represented in help.

+ * + *

This implementation gives a string consisting of the concatenation of:

+ *
    + *
  • {@code "* "} for "required" options, otherwise {@code ""}
  • + *
  • For each of the {@link OptionDescriptor#options()} of the descriptor, separated by {@code ", "}: + *
      + *
    • {@link #optionLeader(String)} of the option
    • + *
    • the option
    • + *
    + *
  • + *
  • the result of {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}
  • + *
+ * + * @param descriptor a descriptor for a configured option of a parser + * @return help string + */ + protected String createOptionDisplay( OptionDescriptor descriptor ) { StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" ); for ( Iterator i = descriptor.options().iterator(); i.hasNext(); ) { String option = i.next(); - buffer.append( option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN ); + buffer.append( optionLeader( option ) ); buffer.append( option ); if ( i.hasNext() ) @@ -223,31 +414,105 @@ public class BuiltinHelpFormatter implements HelpFormatter { return buffer.toString(); } - private void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) { - String indicator = extractTypeIndicator( descriptor ); - String description = descriptor.argumentDescription(); - if ( indicator != null || !isNullOrEmpty( description ) ) - appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() ); + /** + *

Gives a string that represents the given option's "option leader" in help.

+ * + *

This implementation answers with {@code "--"} for options of length greater than one; otherwise answers + * with {@code "-"}.

+ * + * @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 ) { + /** + *

Appends additional info about the given option to the given buffer.

+ * + *

This implementation:

+ *
    + *
  • calls {@link #extractTypeIndicator(OptionDescriptor)} for the descriptor
  • + *
  • calls {@link jdk.internal.joptsimple.OptionDescriptor#argumentDescription()} for the descriptor
  • + *
  • if either of the above is present, calls + * {@link #appendOptionHelp(StringBuilder, String, String, boolean)}
  • + *
+ * + * @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() ); + } + } + + /** + *

Gives an indicator of the type of arguments of the option described by the given descriptor, + * for use in help.

+ * + *

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"}.

+ * + * @param descriptor a descriptor for a configured option of a parser + * @return type indicator text + */ + protected String extractTypeIndicator( OptionDescriptor descriptor ) { String indicator = descriptor.argumentTypeIndicator(); if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) ) return shortNameOf( indicator ); - return null; + return "String"; } - private void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, boolean required ) { + /** + *

Appends info about an option's argument to the given buffer.

+ * + *

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.

+ * + * @param buffer string buffer + * @param typeIndicator type indicator + * @param description type description + * @param required indicator of "required"-ness of the argument of the option + */ + protected void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, + boolean required ) { if ( required ) appendTypeIndicator( buffer, typeIndicator, description, '<', '>' ); else appendTypeIndicator( buffer, typeIndicator, description, '[', ']' ); } - private void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description, - char start, char end ) { + /** + *

Appends a type indicator for an option's argument to the given buffer.

+ * + *

This implementation appends, in order:

+ *
    + *
  • {@code ' '}
  • + *
  • {@code start}
  • + *
  • the type indicator, if not {@code null}
  • + *
  • if the description is present, then {@code ": "} plus the description if the type indicator is + * present; otherwise the description only
  • + *
  • {@code end}
  • + *
+ * + * @param buffer string buffer + * @param typeIndicator type indicator + * @param description type description + * @param start starting character + * @param end ending character + */ + protected void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description, + char start, char end ) { buffer.append( ' ' ).append( start ); if ( typeIndicator != null ) buffer.append( typeIndicator ); @@ -262,21 +527,69 @@ public class BuiltinHelpFormatter implements HelpFormatter { buffer.append( end ); } - private String createDescriptionDisplay( OptionDescriptor descriptor ) { + /** + *

Gives a string representing a description of the option with the given descriptor.

+ * + *

This implementation:

+ *
    + *
  • Asks for the descriptor's {@link OptionDescriptor#defaultValues()}
  • + *
  • If they're not present, answers the descriptor's {@link OptionDescriptor#description()}.
  • + *
  • If they are present, concatenates and returns: + *
      + *
    • the descriptor's {@link OptionDescriptor#description()}
    • + *
    • {@code ' '}
    • + *
    • {@code "default: "} plus the result of {@link #createDefaultValuesDisplay(java.util.List)}, + * surrounded by parentheses
    • + *
    + *
  • + *
+ * + * @param descriptor a descriptor for a configured option of a parser + * @return display text for the option's description + */ + protected String createDescriptionDisplay( OptionDescriptor descriptor ) { List defaultValues = descriptor.defaultValues(); if ( defaultValues.isEmpty() ) return descriptor.description(); String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues ); - return ( descriptor.description() + ' ' + surround( "default: " + defaultValuesDisplay, '(', ')' ) ).trim(); + return ( descriptor.description() + + ' ' + + surround( message( "default.value.header" ) + ' ' + defaultValuesDisplay, '(', ')' ) + ).trim(); } - private String createDefaultValuesDisplay( List defaultValues ) { + /** + *

Gives a display string for the default values of an option's argument.

+ * + *

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.

+ * + * @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(); } - private void fitRowsToWidth() { - nonOptionRows.fitToWidth(); - optionRows.fitToWidth(); + /** + *

Looks up and gives a resource bundle message.

+ * + *

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.

+ * + * @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 ); } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ExceptionMessages.properties b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ExceptionMessages.properties new file mode 100644 index 00000000000..c12fc25bb33 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ExceptionMessages.properties @@ -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 \ No newline at end of file diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java index e5dd316f1d7..f3e111158e8 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatterMessages.properties b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatterMessages.properties new file mode 100644 index 00000000000..31f060029aa --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatterMessages.properties @@ -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 diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java index 8696bf1a150..acf554cb8c9 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -70,7 +70,7 @@ class IllegalOptionSpecificationException extends OptionException { } @Override - public String getMessage() { - return singleOptionMessage() + " is not a legal option character"; + Object[] messageArguments() { + return new Object[] { singleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionsException.java similarity index 83% rename from src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java rename to src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionsException.java index 2c997e2052c..44a5a2e9453 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionsException.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,22 +55,22 @@ 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 Emils Solmanis */ -class MissingRequiredOptionException extends OptionException { +class MissingRequiredOptionsException extends OptionException { private static final long serialVersionUID = -1L; - protected MissingRequiredOptionException( Collection options ) { - super( options ); + protected MissingRequiredOptionsException( List> missingRequiredOptions ) { + super( missingRequiredOptions ); } @Override - public String getMessage() { - return "Missing required option(s) " + multipleOptionMessage(); + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java index e96cea33918..39c07fe3201 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ 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. @@ -65,12 +65,12 @@ import java.util.Collection; class MultipleArgumentsForOptionException extends OptionException { private static final long serialVersionUID = -1L; - MultipleArgumentsForOptionException( Collection options ) { - super( options ); + MultipleArgumentsForOptionException( OptionSpec options ) { + super( singleton( options ) ); } @Override - public String getMessage() { - return "Found multiple arguments for option " + multipleOptionMessage() + ", but you asked for only one"; + Object[] messageArguments() { + return new Object[] { singleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java index 9647ff1bad2..c2ee67f7536 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,6 @@ package jdk.internal.joptsimple; -import java.util.Collection; import java.util.List; import static java.util.Collections.*; @@ -70,7 +69,7 @@ class NoArgumentOptionSpec extends AbstractOptionSpec { this( singletonList( option ), "" ); } - NoArgumentOptionSpec( Collection options, String description ) { + NoArgumentOptionSpec( List options, String description ) { super( options, description ); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java index 8124a05e366..5332cf5b781 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -87,7 +87,7 @@ public class NonOptionArgumentSpec extends AbstractOptionSpec { private String argumentDescription = ""; NonOptionArgumentSpec() { - this(""); + this( "" ); } NonOptionArgumentSpec( String description ) { diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java index 063b97200f8..84c076efbe6 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ 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. @@ -67,14 +67,14 @@ class OptionArgumentConversionException extends OptionException { private final String argument; - OptionArgumentConversionException( Collection options, String argument, Throwable cause ) { - super( options, cause ); + OptionArgumentConversionException( OptionSpec options, String argument, Throwable cause ) { + super( singleton( options ), cause ); this.argument = argument; } @Override - public String getMessage() { - return "Cannot parse argument '" + argument + "' of option " + multipleOptionMessage(); + Object[] messageArguments() { + return new Object[] { argument, singleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java index 2a85e25901a..35ddac0af86 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java @@ -25,14 +25,20 @@ 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 - * not actual command-line parsing. + * Trains the option parser. This interface aids integration that disposes declaration of options but not actual + * command-line parsing. + * + * Typical use is for another class to implement {@code OptionDeclarer} as a facade, forwarding calls to an + * {@code OptionParser} instance. + * + * Note that although this is an interface, the returned values of calls are concrete jopt-simple classes. * * @author Paul Holser * @see OptionParser + * @since 4.6 */ public interface OptionDeclarer { /** @@ -78,12 +84,12 @@ public interface OptionDeclarer { * @throws OptionException if any of the options contain illegal characters * @throws NullPointerException if the option list or any of its elements are {@code null} */ - OptionSpecBuilder acceptsAll( Collection options ); + OptionSpecBuilder acceptsAll( List options ); /** * 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 description a string that describes the purpose of the option. This is used when generating help * 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 IllegalArgumentException if the option list is empty */ - OptionSpecBuilder acceptsAll( Collection options, String description ); + OptionSpecBuilder acceptsAll( List options, String description ); /** * 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(); /** - * Tells the parser either to recognize or ignore "-W"-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 */ diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java index 4a6694814f3..4707df23f23 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,6 @@ package jdk.internal.joptsimple; -import java.util.Collection; import java.util.List; /** @@ -70,7 +69,7 @@ public interface OptionDescriptor { * * @return synonymous options */ - Collection options(); + List options(); /** * Description of this option's purpose. diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java index 15977b63801..96cc928ad6b 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java @@ -31,7 +31,7 @@ * * 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 * 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.Collection; import java.util.Iterator; +import java.util.LinkedHashSet; 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 jdk.internal.joptsimple.internal.Strings.*; +import static jdk.internal.joptsimple.internal.Messages.*; /** * 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 { private static final long serialVersionUID = -1L; - private final List options = new ArrayList(); + private final List options = new ArrayList<>(); - protected OptionException( Collection options ) { + protected OptionException( List options ) { this.options.addAll( options ); } - protected OptionException( Collection options, Throwable cause ) { - super( cause ); + protected OptionException( Collection> options ) { + this.options.addAll( specsToStrings( options ) ); + } - this.options.addAll( options ); + protected OptionException( Collection> options, Throwable cause ) { + super( cause ); + this.options.addAll( specsToStrings( options ) ); + } + + private List specsToStrings( Collection> options ) { + List 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 */ - public Collection options() { - return unmodifiableCollection( options ); + public List options() { + return unmodifiableList( options ); } - protected final String singleOptionMessage() { - return singleOptionMessage( options.get( 0 ) ); + protected final String singleOptionString() { + return singleOptionString( options.get( 0 ) ); } - protected final String singleOptionMessage( String option ) { - return SINGLE_QUOTE + option + SINGLE_QUOTE; + protected final String singleOptionString( String option ) { + return option; } - protected final String multipleOptionMessage() { + protected final String multipleOptionString() { StringBuilder buffer = new StringBuilder( "[" ); - for ( Iterator iter = options.iterator(); iter.hasNext(); ) { - buffer.append( singleOptionMessage( iter.next() ) ); + Set asSet = new LinkedHashSet( options ); + for ( Iterator iter = asSet.iterator(); iter.hasNext(); ) { + buffer.append( singleOptionString(iter.next()) ); if ( iter.hasNext() ) buffer.append( ", " ); } @@ -118,4 +137,19 @@ public abstract class OptionException extends RuntimeException { static OptionException unrecognizedOption( String option ) { return new UnrecognizedOptionException( option ); } + + @Override + public final String getMessage() { + return localizedMessage( Locale.getDefault() ); + } + + final String localizedMessage( Locale locale ) { + return formattedMessage( locale ); + } + + private String formattedMessage( Locale locale ) { + return message( locale, "jdk.internal.joptsimple.ExceptionMessages", getClass(), "message", messageArguments() ); + } + + abstract Object[] messageArguments(); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java index f667b446527..f0fa6b3d24d 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,22 +55,22 @@ 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 Paul Holser */ class OptionMissingRequiredArgumentException extends OptionException { private static final long serialVersionUID = -1L; - OptionMissingRequiredArgumentException( Collection options ) { - super( options ); + OptionMissingRequiredArgumentException( OptionSpec option ) { + super( asList( option ) ); } @Override - public String getMessage() { - return "Option " + multipleOptionMessage() + " requires an argument"; + Object[] messageArguments() { + return new Object[] { singleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java index c6c319a329a..403a63927cf 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,18 +55,16 @@ package jdk.internal.joptsimple; -import jdk.internal.joptsimple.internal.AbbreviationMap; -import jdk.internal.joptsimple.util.KeyValuePair; - import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; + +import jdk.internal.joptsimple.internal.AbbreviationMap; +import jdk.internal.joptsimple.internal.SimpleOptionNameMap; +import jdk.internal.joptsimple.internal.OptionNameMap; +import jdk.internal.joptsimple.util.KeyValuePair; import static java.util.Collections.*; import static jdk.internal.joptsimple.OptionException.*; @@ -80,57 +78,58 @@ import static jdk.internal.joptsimple.ParserRules.*; *

This parser supports short options and long options.

* *
    - *
  • Short options begin with a single hyphen ("-") followed by a single letter or digit, - * or question mark ("?"), or dot (".").
  • + *
  • Short options begin with a single hyphen ("{@code -}") followed by a single letter or digit, + * or question mark ("{@code ?}"), or dot ("{@code .}"), or underscore ("{@code _}").
  • * *
  • Short options can accept single arguments. The argument can be made required or optional. The option's * argument can occur: *
      - *
    • in the slot after the option, as in -d /tmp
    • - *
    • right up against the option, as in -d/tmp
    • - *
    • right up against the option separated by an equals sign ("="), as in -d=/tmp
    • + *
    • in the slot after the option, as in {@code -d /tmp}
    • + *
    • right up against the option, as in {@code -d/tmp}
    • + *
    • right up against the option separated by an equals sign ({@code "="}), as in {@code -d=/tmp}
    • *
    * To specify n arguments for an option, specify the option n times, once for each argument, - * as in -d /tmp -d /var -d /opt; 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 * interface" (see below), give multiple values separated by a given character as a single argument to the * option.
  • * - *
  • Short options can be clustered, so that -abc is treated as -a -b -c. If a short option + *
  • Short options can be clustered, so that {@code -abc} is treated as {@code -a -b -c}. If a short option * in the cluster can accept an argument, the remaining characters are interpreted as the argument for that * option.
  • * - *
  • An argument consisting only of two hyphens ("--") signals that the remaining arguments are to be + *
  • An argument consisting only of two hyphens ({@code "--"}) signals that the remaining arguments are to be * treated as non-options.
  • * *
  • An argument consisting only of a single hyphen is considered a non-option argument (though it can be an * argument of an option). Many Unix programs treat single hyphens as stand-ins for the standard input or standard * output streams.
  • * - *
  • Long options begin with two hyphens ("--"), followed by multiple letters, digits, + *
  • Long options begin with two hyphens ({@code "--"}), followed by multiple letters, digits, * hyphens, question marks, or dots. A hyphen cannot be the first character of a long option specification when * configuring the parser.
  • * - *
  • You can abbreviate long options, so long as the abbreviation is unique.
  • + *
  • 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}.
  • * *
  • Long options can accept single arguments. The argument can be made required or optional. The option's * argument can occur: *
      - *
    • in the slot after the option, as in --directory /tmp
    • - *
    • right up against the option separated by an equals sign ("="), as in - * --directory=/tmp + *
    • in the slot after the option, as in {@code --directory /tmp}
    • + *
    • right up against the option separated by an equals sign ({@code "="}), as in + * {@code --directory=/tmp} *
    * Specify multiple arguments for a long option in the same manner as for short options (see above).
  • * - *
  • You can use a single hyphen ("-") instead of a double hyphen ("--") for a long + *
  • You can use a single hyphen ({@code "-"}) instead of a double hyphen ({@code "--"}) for a long * option.
  • * - *
  • The option -W is reserved. If you tell the parser to {@linkplain + *
  • 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, - * -W foo=bar as the long option foo with argument bar, as though you had written - * --foo=bar.
  • + * {@code -W foo=bar} as the long option {@code foo} with argument {@code bar}, as though you had written + * {@code --foo=bar}. * - *
  • You can specify -W as a valid short option, or use it as an abbreviation for a long option, but + *
  • You can specify {@code -W} as a valid short option, or use it as an abbreviation for a long option, but * {@linkplain #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will always supersede * this behavior.
  • * @@ -148,15 +147,15 @@ import static jdk.internal.joptsimple.ParserRules.*; * parser.accepts( "2" ); * OptionSet options = parser.parse( "-a", "-2" ); * - * In this case, the option set contains "a" with argument -2, not both "a" and - * "2". Swapping the elements in the args array gives the latter. + * In this case, the option set contains {@code "a"} with argument {@code -2}, not both {@code "a"} and + * {@code "2"}. Swapping the elements in the args array gives the latter. *
* *

There are two ways to tell the parser what options to recognize:

* *
    *
  1. 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, * 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 @@ -169,28 +168,28 @@ import static jdk.internal.joptsimple.ParserRules.*; *
      *
    • Any letter or digit is treated as an option character.
    • * - *
    • An option character can be immediately followed by an asterisk (*) to indicate that the option is a - * "help" option.
    • + *
    • An option character can be immediately followed by an asterisk ({@code *)} to indicate that + * the option is a "help" option.
    • * - *
    • If an option character (with possible trailing asterisk) is followed by a single colon (":"), + *
    • If an option character (with possible trailing asterisk) is followed by a single colon ({@code ":"}), * then the option requires an argument.
    • * - *
    • If an option character (with possible trailing asterisk) is followed by two colons ("::"), + *
    • If an option character (with possible trailing asterisk) is followed by two colons ({@code "::"}), * then the option accepts an optional argument.
    • * *
    • Otherwise, the option character accepts no argument.
    • * - *
    • If the option specification string begins with a plus sign ("+"), the parser will behave + *
    • If the option specification string begins with a plus sign ({@code "+" }), the parser will behave * "POSIX-ly correct".
    • * - *
    • If the option specification string contains the sequence "W;" (capital W followed by a + *
    • 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.
    • *
    *
  2. *
* - *

Each of the options in a list of options given to {@link #acceptsAll(Collection) acceptsAll} is treated as a - * synonym of the others. For example: + *

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:

*
  *     
  *     OptionParser parser = new OptionParser();
@@ -198,14 +197,14 @@ import static jdk.internal.joptsimple.ParserRules.*;
  *     OptionSet options = parser.parse( "-w" );
  *     
  *   
- * In this case, options.{@link OptionSet#has(String) has} would answer {@code true} when given arguments - * "w", "interactive", and "confirmation". The {@link OptionSet} would give the same + *

In this case, options.{@link OptionSet#has(String) has} would answer {@code true} when given arguments + * {@code "w"}, {@code "interactive"}, and {@code "confirmation"}. The {@link OptionSet} would give the same * responses to these arguments for its other methods as well.

* *

By default, as with GNU {@code getopt()}, the parser allows intermixing of options and non-options. If, however, * the parser has been created to be "POSIX-ly correct", then the first argument that does not look lexically like an * option, and is not a required argument of a preceding option, signals the end of options. You can still bind - * optional arguments to their options using the abutting (for short options) or = syntax.

+ * optional arguments to their options using the abutting (for short options) or {@code =} syntax.

* *

Unlike GNU {@code getopt()}, this parser does not honor the environment variable {@code POSIXLY_CORRECT}. * "POSIX-ly correct" parsers are configured by either:

@@ -214,16 +213,20 @@ import static jdk.internal.joptsimple.ParserRules.*; *
  • using the method {@link #posixlyCorrect(boolean)}, or
  • * *
  • using the {@linkplain #OptionParser(String) constructor} with an argument whose first character is a plus sign - * ("+")
  • + * ({@code "+"}) * * * @author Paul Holser * @see The GNU C Library */ public class OptionParser implements OptionDeclarer { - private final AbbreviationMap> recognizedOptions; - private final Map, Set>> requiredIf; - private final Map, Set>> requiredUnless; + private final OptionNameMap> recognizedOptions; + private final ArrayList> trainingOrder; + private final Map, Set>> requiredIf; + private final Map, Set>> requiredUnless; + private final Map, Set>> availableIf; + private final Map, Set>> availableUnless; + private OptionParserState state; private boolean posixlyCorrect; private boolean allowsUnrecognizedOptions; @@ -234,11 +237,28 @@ public class OptionParser implements OptionDeclarer { * behavior. */ public OptionParser() { - recognizedOptions = new AbbreviationMap>(); - requiredIf = new HashMap, Set>>(); - requiredUnless = new HashMap, Set>>(); + this(true); + } + + /** + * Creates an option parser that initially recognizes no options, and does not exhibit "POSIX-ly correct" + * behavior. + * + * @param allowAbbreviations whether unambiguous abbreviations of long options should be recognized + * by the parser + */ + public OptionParser( boolean allowAbbreviations ) { + trainingOrder = new ArrayList<>(); + requiredIf = new HashMap<>(); + requiredUnless = new HashMap<>(); + availableIf = new HashMap<>(); + availableUnless = new HashMap<>(); state = moreOptions( false ); + recognizedOptions = allowAbbreviations + ? new AbbreviationMap>() + : new SimpleOptionNameMap>(); + recognize( new NonOptionArgumentSpec() ); } @@ -266,11 +286,11 @@ public class OptionParser implements OptionDeclarer { return acceptsAll( singletonList( option ), description ); } - public OptionSpecBuilder acceptsAll( Collection options ) { + public OptionSpecBuilder acceptsAll( List options ) { return acceptsAll( options, "" ); } - public OptionSpecBuilder acceptsAll( Collection options, String description ) { + public OptionSpecBuilder acceptsAll( List options, String description ) { if ( options.isEmpty() ) throw new IllegalArgumentException( "need at least one option" ); @@ -280,7 +300,7 @@ public class OptionParser implements OptionDeclarer { } public NonOptionArgumentSpec nonOptions() { - NonOptionArgumentSpec spec = new NonOptionArgumentSpec(); + NonOptionArgumentSpec spec = new NonOptionArgumentSpec<>(); recognize( spec ); @@ -288,7 +308,7 @@ public class OptionParser implements OptionDeclarer { } public NonOptionArgumentSpec nonOptions( String description ) { - NonOptionArgumentSpec spec = new NonOptionArgumentSpec( description ); + NonOptionArgumentSpec spec = new NonOptionArgumentSpec<>( description ); recognize( spec ); @@ -321,6 +341,7 @@ public class OptionParser implements OptionDeclarer { void recognize( AbstractOptionSpec spec ) { recognizedOptions.putAll( spec.options(), spec ); + trainingOrder.add( spec ); } /** @@ -348,7 +369,7 @@ public class OptionParser implements OptionDeclarer { * @see #printHelpOn(OutputStream) */ public void printHelpOn( Writer sink ) throws IOException { - sink.write( helpFormatter.format( recognizedOptions.toJavaUtilMap() ) ); + sink.write( helpFormatter.format( _recognizedOptions() ) ); 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> recognizedOptions() { - return new HashMap>( recognizedOptions.toJavaUtilMap() ); + return new LinkedHashMap>( _recognizedOptions() ); } - /** + private Map> _recognizedOptions() { + Map> options = new LinkedHashMap<>(); + for ( AbstractOptionSpec spec : trainingOrder ) { + for ( String option : spec.options() ) + options.put( option, spec ); + } + return options; + } + + /** * Parses the given command line arguments according to the option specifications given to the parser. * * @param arguments arguments to parse @@ -393,45 +428,89 @@ public class OptionParser implements OptionDeclarer { reset(); ensureRequiredOptions( detected ); + ensureAllowedOptions( detected ); return detected; } + /** + * Mandates mutual exclusiveness for the options built by the specified builders. + * + * @param specs descriptors for options that should be mutually exclusive on a command line. + * @throws NullPointerException if {@code specs} is {@code null} + */ + public void mutuallyExclusive( OptionSpecBuilder... specs ) { + for ( int i = 0; i < specs.length; i++ ) { + for ( int j = 0; j < specs.length; j++ ) { + if ( i != j ) + specs[i].availableUnless( specs[j] ); + } + } + } + private void ensureRequiredOptions( OptionSet options ) { - Collection missingRequiredOptions = missingRequiredOptions( options ); + List> missingRequiredOptions = missingRequiredOptions(options); boolean helpOptionPresent = isHelpOptionPresent( options ); if ( !missingRequiredOptions.isEmpty() && !helpOptionPresent ) - throw new MissingRequiredOptionException( missingRequiredOptions ); + throw new MissingRequiredOptionsException( missingRequiredOptions ); } - private Collection missingRequiredOptions( OptionSet options ) { - Collection missingRequiredOptions = new HashSet(); + private void ensureAllowedOptions( OptionSet options ) { + List> forbiddenOptions = unavailableOptions( options ); + boolean helpOptionPresent = isHelpOptionPresent( options ); + + if ( !forbiddenOptions.isEmpty() && !helpOptionPresent ) + throw new UnavailableOptionException( forbiddenOptions ); + } + + private List> missingRequiredOptions( OptionSet options ) { + List> missingRequiredOptions = new ArrayList<>(); for ( AbstractOptionSpec each : recognizedOptions.toJavaUtilMap().values() ) { if ( each.isRequired() && !options.has( each ) ) - missingRequiredOptions.addAll( each.options() ); + missingRequiredOptions.add(each); } - for ( Map.Entry, Set>> eachEntry : requiredIf.entrySet() ) { - AbstractOptionSpec required = specFor( eachEntry.getKey().iterator().next() ); + for ( Map.Entry, Set>> each : requiredIf.entrySet() ) { + AbstractOptionSpec required = specFor( each.getKey().iterator().next() ); - if ( optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { - missingRequiredOptions.addAll( required.options() ); - } + if ( optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) ) + missingRequiredOptions.add( required ); } - for ( Map.Entry, Set>> eachEntry : requiredUnless.entrySet() ) { - AbstractOptionSpec required = specFor( eachEntry.getKey().iterator().next() ); + for ( Map.Entry, Set>> each : requiredUnless.entrySet() ) { + AbstractOptionSpec required = specFor(each.getKey().iterator().next()); - if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { - missingRequiredOptions.addAll( required.options() ); - } + if ( !optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) ) + missingRequiredOptions.add( required ); } return missingRequiredOptions; } + private List> unavailableOptions(OptionSet options) { + List> unavailableOptions = new ArrayList<>(); + + for ( Map.Entry, Set>> eachEntry : availableIf.entrySet() ) { + AbstractOptionSpec forbidden = specFor( eachEntry.getKey().iterator().next() ); + + if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && options.has( forbidden ) ) { + unavailableOptions.add(forbidden); + } + } + + for ( Map.Entry, Set>> 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> specs ) { for ( OptionSpec each : specs ) { if ( options.has( each ) ) @@ -443,12 +522,14 @@ public class OptionParser implements OptionDeclarer { private boolean isHelpOptionPresent( OptionSet options ) { boolean helpOptionPresent = false; + for ( AbstractOptionSpec each : recognizedOptions.toJavaUtilMap().values() ) { if ( each.isForHelp() && options.has( each ) ) { helpOptionPresent = true; break; } } + return helpOptionPresent; } @@ -505,24 +586,40 @@ public class OptionParser implements OptionDeclarer { return recognizedOptions.contains( option ); } - void requiredIf( Collection precedentSynonyms, String required ) { + void requiredIf( List precedentSynonyms, String required ) { requiredIf( precedentSynonyms, specFor( required ) ); } - void requiredIf( Collection precedentSynonyms, OptionSpec required ) { - putRequiredOption( precedentSynonyms, required, requiredIf ); + void requiredIf( List precedentSynonyms, OptionSpec required ) { + putDependentOption( precedentSynonyms, required, requiredIf ); } - void requiredUnless( Collection precedentSynonyms, String required ) { + void requiredUnless( List precedentSynonyms, String required ) { requiredUnless( precedentSynonyms, specFor( required ) ); } - void requiredUnless( Collection precedentSynonyms, OptionSpec required ) { - putRequiredOption( precedentSynonyms, required, requiredUnless ); + void requiredUnless( List precedentSynonyms, OptionSpec required ) { + putDependentOption( precedentSynonyms, required, requiredUnless ); } - private void putRequiredOption( Collection precedentSynonyms, OptionSpec required, - Map, Set>> target ) { + void availableIf( List precedentSynonyms, String available ) { + availableIf( precedentSynonyms, specFor( available ) ); + } + + void availableIf( List precedentSynonyms, OptionSpec available) { + putDependentOption( precedentSynonyms, available, availableIf ); + } + + void availableUnless( List precedentSynonyms, String available ) { + availableUnless( precedentSynonyms, specFor( available ) ); + } + + void availableUnless( List precedentSynonyms, OptionSpec available ) { + putDependentOption( precedentSynonyms, available, availableUnless ); + } + + private void putDependentOption( List precedentSynonyms, OptionSpec required, + Map, Set>> target ) { for ( String each : precedentSynonyms ) { AbstractOptionSpec spec = specFor( each ); @@ -532,7 +629,7 @@ public class OptionParser implements OptionDeclarer { Set> associated = target.get( precedentSynonyms ); if ( associated == null ) { - associated = new HashSet>(); + associated = new HashSet<>(); target.put( precedentSynonyms, associated ); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java index 7fdbcbf3618..d2affe8e48d 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java index 71061156fa0..ef781f2d223 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,11 +55,14 @@ 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 jdk.internal.joptsimple.internal.Objects.*; +import static java.util.Objects.*; /** * 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. */ OptionSet( Map> recognizedSpecs ) { - detectedSpecs = new ArrayList>(); - detectedOptions = new HashMap>(); - optionsToArguments = new IdentityHashMap, List>(); + detectedSpecs = new ArrayList<>(); + detectedOptions = new HashMap<>(); + optionsToArguments = new IdentityHashMap<>(); defaultValues = defaultValues( recognizedSpecs ); this.recognizedSpecs = recognizedSpecs; } @@ -90,7 +93,7 @@ public class OptionSet { * @return {@code true} if any options were detected */ 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) */ public boolean hasArgument( OptionSpec option ) { - ensureNotNull( option ); + requireNonNull( option ); List values = optionsToArguments.get( option ); return values != null && !values.isEmpty(); @@ -169,7 +172,7 @@ public class OptionSet { * @throws OptionException if more than one argument was detected for the option */ public Object valueOf( String option ) { - ensureNotNull( option ); + requireNonNull( option ); AbstractOptionSpec spec = detectedOptions.get( option ); if ( spec == null ) { @@ -194,7 +197,7 @@ public class OptionSet { * @throws ClassCastException if the arguments of this option are not of the expected type */ public V valueOf( OptionSpec option ) { - ensureNotNull( option ); + requireNonNull( option ); List values = valuesOf( option ); switch ( values.size() ) { @@ -203,7 +206,7 @@ public class OptionSet { case 1: return values.get( 0 ); 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} */ public List valuesOf( String option ) { - ensureNotNull( option ); + requireNonNull( option ); AbstractOptionSpec spec = detectedOptions.get( option ); 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 */ public List valuesOf( OptionSpec option ) { - ensureNotNull( option ); + requireNonNull( option ); List values = optionsToArguments.get( option ); if ( values == null || values.isEmpty() ) return defaultValueFor( option ); AbstractOptionSpec spec = (AbstractOptionSpec) option; - List convertedValues = new ArrayList(); + List convertedValues = new ArrayList<>(); for ( String each : values ) convertedValues.add( spec.convert( each ) ); @@ -260,7 +263,7 @@ public class OptionSet { */ public List> specs() { List> specs = detectedSpecs; - specs.remove( detectedOptions.get( NonOptionArgumentSpec.NAME ) ); + specs.removeAll( singletonList( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) ); return unmodifiableList( specs ); } @@ -271,10 +274,13 @@ public class OptionSet { * @return the declared options as a map */ public Map, List> asMap() { - Map, List> map = new HashMap, List>(); - for ( AbstractOptionSpec spec : recognizedSpecs.values() ) + Map, List> map = new HashMap<>(); + + for ( AbstractOptionSpec spec : recognizedSpecs.values() ) { if ( !spec.representsNonOptions() ) map.put( spec, valuesOf( spec ) ); + } + return unmodifiableMap( map ); } @@ -282,7 +288,8 @@ public class OptionSet { * @return the detected non-option arguments */ public List nonOptionArguments() { - return unmodifiableList( valuesOf( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) ); + AbstractOptionSpec spec = detectedOptions.get( NonOptionArgumentSpec.NAME ); + return valuesOf( spec ); } void add( AbstractOptionSpec spec ) { @@ -298,7 +305,7 @@ public class OptionSet { List optionArguments = optionsToArguments.get( spec ); if ( optionArguments == null ) { - optionArguments = new ArrayList(); + optionArguments = new ArrayList<>(); optionsToArguments.put( spec, optionArguments ); } @@ -315,25 +322,22 @@ public class OptionSet { return false; OptionSet other = (OptionSet) that; - Map, List> thisOptionsToArguments = - new HashMap, List>( optionsToArguments ); - Map, List> otherOptionsToArguments = - new HashMap, List>( other.optionsToArguments ); + Map, List> thisOptionsToArguments = new HashMap<>( optionsToArguments ); + Map, List> otherOptionsToArguments = new HashMap<>( other.optionsToArguments ); return detectedOptions.equals( other.detectedOptions ) && thisOptionsToArguments.equals( otherOptionsToArguments ); } @Override public int hashCode() { - Map, List> thisOptionsToArguments = - new HashMap, List>( optionsToArguments ); + Map, List> thisOptionsToArguments = new HashMap<>( optionsToArguments ); return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode(); } @SuppressWarnings( "unchecked" ) private List defaultValuesFor( String option ) { if ( defaultValues.containsKey( option ) ) - return (List) defaultValues.get( option ); + return unmodifiableList( (List) defaultValues.get( option ) ); return emptyList(); } @@ -343,7 +347,7 @@ public class OptionSet { } private static Map> defaultValues( Map> recognizedSpecs ) { - Map> defaults = new HashMap>(); + Map> defaults = new HashMap<>(); for ( Map.Entry> each : recognizedSpecs.entrySet() ) defaults.put( each.getKey(), each.getValue().defaultValues() ); return defaults; diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java index 666230b05d4..030e6f7a5a0 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,6 @@ package jdk.internal.joptsimple; -import java.util.Collection; import java.util.List; /** @@ -116,7 +115,7 @@ public interface OptionSpec { /** * @return the string representations of this option */ - Collection options(); + List options(); /** * Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java index 4f171091ec0..d7d02f00a87 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -56,7 +56,6 @@ package jdk.internal.joptsimple; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -90,7 +89,7 @@ import java.util.List; public class OptionSpecBuilder extends NoArgumentOptionSpec { private final OptionParser parser; - OptionSpecBuilder( OptionParser parser, Collection options, String description ) { + OptionSpecBuilder( OptionParser parser, List options, String description ) { super( options, description ); this.parser = parser; @@ -107,8 +106,7 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec { * @return a specification for the option */ public ArgumentAcceptingOptionSpec withRequiredArg() { - ArgumentAcceptingOptionSpec newSpec = - new RequiredArgumentOptionSpec( options(), description() ); + ArgumentAcceptingOptionSpec newSpec = new RequiredArgumentOptionSpec<>( options(), description() ); parser.recognize( newSpec ); return newSpec; @@ -121,7 +119,7 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec { */ public ArgumentAcceptingOptionSpec withOptionalArg() { ArgumentAcceptingOptionSpec newSpec = - new OptionalArgumentOptionSpec( options(), description() ); + new OptionalArgumentOptionSpec<>( options(), description() ); parser.recognize( newSpec ); return newSpec; @@ -141,9 +139,8 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec { */ public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) { List dependents = validatedDependents( dependent, otherDependents ); - for ( String each : dependents ) { + for ( String each : dependents ) parser.requiredIf( options(), each ); - } return this; } @@ -210,8 +207,91 @@ public class OptionSpecBuilder extends NoArgumentOptionSpec { return this; } + /** + *

    Informs an option parser that this builder's option is allowed if the given option is present on the command + * line.

    + * + *

    For a given option, you should not mix this with {@link #availableUnless(String, String...) + * availableUnless} to avoid conflicts.

    + * + * @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 dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) + parser.availableIf( options(), each ); + + return this; + } + + /** + *

    Informs an option parser that this builder's option is allowed if the given option is present on the command + * line.

    + * + *

    For a given option, you should not mix this with {@link #availableUnless(OptionSpec, OptionSpec[]) + * requiredUnless} to avoid conflicts.

    + * + *

    This method recognizes only instances of options returned from the fluent interface methods.

    + * + * @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; + } + + /** + *

    Informs an option parser that this builder's option is allowed if the given option is absent on the command + * line.

    + * + *

    For a given option, you should not mix this with {@link #availableIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.

    + * + * @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 dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) + parser.availableUnless( options(), each ); + + return this; + } + + /** + *

    Informs an option parser that this builder's option is allowed if the given option is absent on the command + * line.

    + * + *

    For a given option, you should not mix this with {@link #availableIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.

    + * + *

    This method recognizes only instances of options returned from the fluent interface methods.

    + * + * @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 validatedDependents( String dependent, String... otherDependents ) { - List dependents = new ArrayList(); + List dependents = new ArrayList<>(); dependents.add( dependent ); Collections.addAll( dependents, otherDependents ); diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java index d878daba6eb..9b45354f621 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java index 894e00e3a29..7e20779b962 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ package jdk.internal.joptsimple; -import java.util.Collection; +import java.util.List; /** * Specification of an option that accepts an optional argument. @@ -68,7 +68,7 @@ class OptionalArgumentOptionSpec extends ArgumentAcceptingOptionSpec { super( option, false ); } - OptionalArgumentOptionSpec( Collection options, String description ) { + OptionalArgumentOptionSpec( List options, String description ) { super( options, false, description ); } @@ -77,7 +77,7 @@ class OptionalArgumentOptionSpec extends ArgumentAcceptingOptionSpec { if ( arguments.hasMore() ) { String nextArgument = arguments.peek(); - if ( !parser.looksLikeAnOption( nextArgument ) ) + if ( !parser.looksLikeAnOption( nextArgument ) && canConvertArgument( nextArgument ) ) handleOptionArgument( parser, detectedOptions, arguments ); else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) ) addArguments( detectedOptions, arguments.next() ); diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java index e981d878adc..dae98e3b008 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ package jdk.internal.joptsimple; -import java.util.Collection; +import java.util.List; import static java.lang.Character.*; @@ -97,7 +97,7 @@ final class ParserRules { ensureLegalOptionCharacter( option.charAt( i ) ); } - static void ensureLegalOptions( Collection options ) { + static void ensureLegalOptions( List options ) { for ( String each : options ) ensureLegalOption( each ); } @@ -108,7 +108,7 @@ final class ParserRules { } private static boolean isAllowedPunctuation( char option ) { - String allowedPunctuation = "?." + HYPHEN_CHAR; + String allowedPunctuation = "?._" + HYPHEN_CHAR; return allowedPunctuation.indexOf( option ) != -1; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README index ad0d0f64db5..fccb4f62f52 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README @@ -1,3 +1,3 @@ -JOpt Simple, Version 4.6 +JOpt Simple, Version 5.0.4 https://pholser.github.io/jopt-simple/ diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java index 9972f8d1cff..26608a827c7 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ package jdk.internal.joptsimple; -import java.util.Collection; +import java.util.List; /** * Specification of an option that accepts a required argument. @@ -68,14 +68,14 @@ class RequiredArgumentOptionSpec extends ArgumentAcceptingOptionSpec { super( option, true ); } - RequiredArgumentOptionSpec( Collection options, String description ) { + RequiredArgumentOptionSpec( List options, String description ) { super( options, true, description ); } @Override protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { if ( !arguments.hasMore() ) - throw new OptionMissingRequiredArgumentException( options() ); + throw new OptionMissingRequiredArgumentException( this ); addArguments( detectedOptions, arguments.next() ); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnavailableOptionException.java similarity index 74% rename from src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java rename to src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnavailableOptionException.java index c5775fb3458..d4d0655ebe6 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnavailableOptionException.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,30 +55,21 @@ 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 - * non-option arguments}. - * - * @author Paul Holser + * Thrown when options marked as allowed are specified on the command line, but the options they depend upon are + * present/not present. */ -class UnacceptableNumberOfNonOptionsException extends OptionException { +class UnavailableOptionException extends OptionException { 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 ) { - super( singletonList( NonOptionArgumentSpec.NAME ) ); - - this.minimum = minimum; - this.maximum = maximum; - this.actual = actual; + UnavailableOptionException( List> forbiddenOptions ) { + super( forbiddenOptions ); } @Override - public String getMessage() { - return String.format( "actual = %d, minimum = %d, maximum = %d", actual, minimum, maximum ); + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java index 0783b7a684b..6f66ee8bccb 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,7 +55,7 @@ package jdk.internal.joptsimple; -import java.util.Collection; +import java.util.List; import static java.util.Collections.*; @@ -71,12 +71,12 @@ class UnconfiguredOptionException extends OptionException { this( singletonList( option ) ); } - UnconfiguredOptionException( Collection options ) { + UnconfiguredOptionException( List options ) { super( options ); } @Override - public String getMessage() { - return "Option " + multipleOptionMessage() + " has not been configured on this parser"; + Object[] messageArguments() { + return new Object[] { multipleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java index b9ec16abb0a..cbf93943aa4 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -70,7 +70,7 @@ class UnrecognizedOptionException extends OptionException { } @Override - public String getMessage() { - return singleOptionMessage() + " is not a recognized option"; + Object[] messageArguments() { + return new Object[] { singleOptionString() }; } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java index 3ea4938d21c..767b994fd8e 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java index db08b2550d1..2a761262c27 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -76,7 +76,7 @@ public interface ValueConverter { * * @return the target class for conversion */ - Class valueType(); + Class valueType(); /** * Gives a string that describes the pattern of the values this converter expects, if any. For example, a date diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java index 2646b7372b7..8df4556b02e 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -84,37 +84,41 @@ import java.util.TreeMap; * * @param a constraint on the types of the values in the map * @author Paul Holser - * @see Perl's Text::Abbrev module + * @see Perl's Text::Abbrev module + * @see Radix tree */ -public class AbbreviationMap { +public class AbbreviationMap implements OptionNameMap { + private final Map> children = new TreeMap<>(); + private String key; private V value; - private final Map> children = new TreeMap>(); private int keysBeyond; /** *

    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.

    * - * @param aKey key to look up + * @param key key to look up * @return {@code true} if {@code key} is present in the map * @throws NullPointerException if {@code key} is {@code null} */ - public boolean contains( String aKey ) { - return get( aKey ) != null; + @Override + public boolean contains(String key) { + return get(key) != null; } /** *

    Answers the value associated with the given key. The key can be a unique * abbreviation of a key that is in the map.

    * - * @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 * such value or {@code aKey} is not a unique abbreviation of a key in the map * @throws NullPointerException if {@code aKey} is {@code null} */ - public V get( String aKey ) { - char[] chars = charsOf( aKey ); + @Override + public V get( String key ) { + char[] chars = charsOf( key ); AbbreviationMap child = this; for ( char each : chars ) { @@ -130,18 +134,19 @@ public class AbbreviationMap { *

    Associates a given value with a given key. If there was a previous * association, the old value is replaced with the new one.

    * - * @param aKey key to create in the map + * @param key key to create in the map * @param newValue value to associate with the key * @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null} * @throws IllegalArgumentException if {@code aKey} is a zero-length string */ - public void put( String aKey, V newValue ) { + @Override + public void put( String key, V newValue ) { if ( newValue == null ) throw new NullPointerException(); - if ( aKey.length() == 0 ) + if ( key.length() == 0 ) throw new IllegalArgumentException(); - char[] chars = charsOf( aKey ); + char[] chars = charsOf(key); add( chars, newValue, 0, chars.length ); } @@ -154,6 +159,7 @@ public class AbbreviationMap { * @throws NullPointerException if {@code keys} or {@code newValue} is {@code null} * @throws IllegalArgumentException if any of {@code keys} is a zero-length string */ + @Override public void putAll( Iterable keys, V newValue ) { for ( String each : keys ) put( each, newValue ); @@ -170,7 +176,7 @@ public class AbbreviationMap { char nextChar = chars[ offset ]; AbbreviationMap child = children.get( nextChar ); if ( child == null ) { - child = new AbbreviationMap(); + child = new AbbreviationMap<>(); children.put( nextChar, child ); } @@ -188,15 +194,16 @@ public class AbbreviationMap { /** *

    If the map contains the given key, dissociates the key from its value.

    * - * @param aKey key to remove + * @param key key to remove * @throws NullPointerException if {@code aKey} is {@code null} * @throws IllegalArgumentException if {@code aKey} is a zero-length string */ - public void remove( String aKey ) { - if ( aKey.length() == 0 ) + @Override + public void remove( String key ) { + if ( key.length() == 0 ) throw new IllegalArgumentException(); - char[] keyChars = charsOf( aKey ); + char[] keyChars = charsOf(key); remove( keyChars, 0, keyChars.length ); } @@ -242,8 +249,9 @@ public class AbbreviationMap { * * @return a Java map corresponding to this abbreviation map */ + @Override public Map toJavaUtilMap() { - Map mappings = new TreeMap(); + Map mappings = new TreeMap<>(); addToMappings( mappings ); return mappings; } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java index f75025ccd19..e5e47469789 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -62,7 +62,7 @@ import java.util.Map; * @author Paul Holser */ public final class Classes { - private static final Map, Class> WRAPPERS = new HashMap, Class>( 13 ); + private static final Map, Class> WRAPPERS = new HashMap<>( 13 ); static { WRAPPERS.put( boolean.class, Boolean.class ); diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java index a3859f7d1cf..283f102e0d4 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java @@ -31,7 +31,7 @@ * * 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 * 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.util.ArrayList; import java.util.List; -import java.util.Locale; import static java.text.BreakIterator.*; @@ -82,7 +81,7 @@ class Columns { List options = piecesOf( row.option, optionWidth ); List descriptions = piecesOf( row.description, descriptionWidth ); - List rows = new ArrayList(); + List rows = new ArrayList<>(); for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i ) rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) ); @@ -94,7 +93,7 @@ class Columns { } private List piecesOf( String raw, int width ) { - List pieces = new ArrayList(); + List pieces = new ArrayList<>(); for ( String each : raw.trim().split( LINE_SEPARATOR ) ) pieces.addAll( piecesOfEmbeddedLine( each, width ) ); @@ -103,9 +102,9 @@ class Columns { } private List piecesOfEmbeddedLine( String line, int width ) { - List pieces = new ArrayList(); + List pieces = new ArrayList<>(); - BreakIterator words = BreakIterator.getLineInstance( Locale.US ); + BreakIterator words = BreakIterator.getLineInstance(); words.setText( line ); StringBuilder nextPiece = new StringBuilder(); diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java index 720c6e4b8c2..5ff8f7ce55d 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Messages.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Messages.java new file mode 100644 index 00000000000..05c593e1ac9 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Messages.java @@ -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 Paul Holser + */ +public class Messages { + private Messages() { + throw new UnsupportedOperationException(); + } + + public static String message( Locale locale, String bundleName, Class type, String key, Object... args ) { + ResourceBundle bundle = ResourceBundle.getBundle( bundleName, locale ); + String template = bundle.getString( type.getName() + '.' + key ); + MessageFormat format = new MessageFormat( template ); + format.setLocale( locale ); + return format.format( args ); + } +} diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java index 599728bb67b..1546110f7fb 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/OptionNameMap.java similarity index 80% rename from src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java rename to src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/OptionNameMap.java index 2c2b696cd0a..606f5111454 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/OptionNameMap.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,22 +55,23 @@ package jdk.internal.joptsimple.internal; -/** - * @author Paul Holser - */ -public final class Objects { - private Objects() { - throw new UnsupportedOperationException(); - } +import java.util.Map; - /** - * Rejects {@code null} references. - * - * @param target reference to check - * @throws NullPointerException if {@code target} is {@code null} - */ - public static void ensureNotNull( Object target ) { - if ( target == null ) - throw new NullPointerException(); - } +/** + * Map-like interface for storing String-value pairs. + * + * @param type of values stored in the map + */ +public interface OptionNameMap { + boolean contains( String key ); + + V get( String key ); + + void put( String key, V newValue ); + + void putAll( Iterable keys, V newValue ); + + void remove( String key ); + + Map toJavaUtilMap(); } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java index 240ad24394c..16237447e37 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -98,22 +98,20 @@ public final class Reflection { private static ValueConverter valueOfConverter( Class clazz ) { try { - Method valueOf = clazz.getDeclaredMethod( "valueOf", String.class ); + Method valueOf = clazz.getMethod( "valueOf", String.class ); if ( meetsConverterRequirements( valueOf, clazz ) ) - return new MethodInvokingValueConverter( valueOf, clazz ); + return new MethodInvokingValueConverter<>( valueOf, clazz ); return null; - } - catch ( NoSuchMethodException ignored ) { + } catch ( NoSuchMethodException ignored ) { return null; } } private static ValueConverter constructorConverter( Class clazz ) { try { - return new ConstructorInvokingValueConverter( clazz.getConstructor( String.class ) ); - } - catch ( NoSuchMethodException ignored ) { + return new ConstructorInvokingValueConverter<>( clazz.getConstructor( String.class ) ); + } catch ( NoSuchMethodException ignored ) { return null; } } @@ -130,8 +128,7 @@ public final class Reflection { public static T instantiate( Constructor constructor, Object... args ) { try { return constructor.newInstance( args ); - } - catch ( Exception ex ) { + } catch ( Exception ex ) { throw reflectionException( ex ); } } @@ -147,8 +144,7 @@ public final class Reflection { public static Object invoke( Method method, Object... args ) { try { return method.invoke( null, args ); - } - catch ( Exception ex ) { + } catch ( Exception ex ) { throw reflectionException( ex ); } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java index 3e98d8f244c..5a62a18e235 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java index 0ce8bcf0cc9..dfce9b70d22 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java index 0d0e4c2d0e0..a6552e6d63c 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,8 +55,8 @@ package jdk.internal.joptsimple.internal; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; import static java.lang.Math.*; @@ -68,7 +68,8 @@ import static jdk.internal.joptsimple.internal.Strings.*; public class Rows { private final int overallWidth; private final int columnSeparatorWidth; - private final Set rows = new LinkedHashSet(); + private final List rows = new ArrayList<>(); + private int widthOfWidestOption; private int widthOfWidestDescription; @@ -87,7 +88,7 @@ public class Rows { widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() ); } - private void reset() { + public void reset() { rows.clear(); widthOfWidestOption = 0; widthOfWidestDescription = 0; @@ -96,7 +97,7 @@ public class Rows { public void fitToWidth() { Columns columns = new Columns( optionWidth(), descriptionWidth() ); - Set fitted = new LinkedHashSet(); + List fitted = new ArrayList<>(); for ( Row each : rows ) fitted.addAll( columns.fit( each ) ); @@ -122,7 +123,7 @@ public class Rows { } private int descriptionWidth() { - return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestDescription ); + return min( overallWidth - optionWidth() - columnSeparatorWidth, widthOfWidestDescription ); } private StringBuilder pad( StringBuilder buffer, String s, int length ) { diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/SimpleOptionNameMap.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/SimpleOptionNameMap.java new file mode 100644 index 00000000000..860937794d0 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/SimpleOptionNameMap.java @@ -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; + +/** + *

    An {@code OptionNameMap} which wraps and behaves like {@code HashMap}.

    + */ +public class SimpleOptionNameMap implements OptionNameMap { + private final Map 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 keys, V newValue ) { + for ( String each : keys ) + map.put( each, newValue ); + } + + @Override + public void remove( String key ) { + map.remove( key ); + } + + @Override + public Map toJavaUtilMap() { + return new HashMap<>( map ); + } +} diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java index 038b3f0ce6b..e989e0cd5da 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -56,7 +56,6 @@ package jdk.internal.joptsimple.internal; import java.util.Iterator; -import java.util.List; import static java.lang.System.*; import static java.util.Arrays.*; @@ -66,7 +65,6 @@ import static java.util.Arrays.*; */ public final class Strings { public static final String EMPTY = ""; - public static final String SINGLE_QUOTE = "'"; public static final String LINE_SEPARATOR = getProperty( "line.separator" ); private Strings() { @@ -96,7 +94,7 @@ public final class Strings { * @return {@code true} if the target string is null or empty */ 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 * @return the joined string */ - public static String join( List pieces, String separator ) { + public static String join( Iterable pieces, String separator ) { StringBuilder buffer = new StringBuilder(); for ( Iterator iter = pieces.iterator(); iter.hasNext(); ) { diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java index f90585300d1..0f3cabed5f5 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java @@ -31,7 +31,7 @@ * * 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 * 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.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import jdk.internal.joptsimple.ValueConversionException; import jdk.internal.joptsimple.ValueConverter; +import jdk.internal.joptsimple.internal.Messages; /** * Converts values to {@link Date}s using a {@link DateFormat} object. @@ -121,10 +123,22 @@ public class DateConverter implements ValueConverter { } private String message( String value ) { - String message = "Value [" + value + "] does not match date/time pattern"; - if ( formatter instanceof SimpleDateFormat ) - message += " [" + ( (SimpleDateFormat) formatter ).toPattern() + ']'; + String key; + Object[] arguments; - 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 ); } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/EnumConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/EnumConverter.java new file mode 100644 index 00000000000..7d2a2388a68 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/EnumConverter.java @@ -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 Christian Ohr + */ +public abstract class EnumConverter> implements ValueConverter { + private final Class 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 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 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 values = EnumSet.allOf( valueType() ); + + StringBuilder builder = new StringBuilder(); + builder.append( delimiters.charAt(0) ); + for ( Iterator 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 ); + } +} diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java index c6c7366509c..6d7056cd616 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java @@ -31,7 +31,7 @@ * * 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 * 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.UnknownHostException; +import java.util.Locale; import jdk.internal.joptsimple.ValueConversionException; import jdk.internal.joptsimple.ValueConverter; +import jdk.internal.joptsimple.internal.Messages; /** * Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}. @@ -70,8 +72,9 @@ public class InetAddressConverter implements ValueConverter { public InetAddress convert( String value ) { try { 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 { public String valuePattern() { return null; } + + private String message( String value ) { + return Messages.message( + Locale.getDefault(), + "jdk.internal.joptsimple.ExceptionMessages", + InetAddressConverter.class, + "message", + value ); + } } diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java index 430e0c89b75..47603adfca4 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -60,7 +60,7 @@ import static jdk.internal.joptsimple.internal.Strings.*; /** *

    A simple string key/string value pair.

    * - *

    This is useful as an argument type for options whose values take on the form key=value, such as JVM + *

    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.

    * * @author Paul Holser @@ -75,7 +75,7 @@ public final class KeyValuePair { } /** - * Parses a string assumed to be of the form key=value into its parts. + * Parses a string assumed to be of the form {@code key=value} into its parts. * * @param asString key-value string * @return a key-value pair @@ -84,7 +84,7 @@ public final class KeyValuePair { public static KeyValuePair valueOf( String asString ) { int equalsIndex = asString.indexOf( '=' ); if ( equalsIndex == -1 ) - return new KeyValuePair( asString, EMPTY ); + return new KeyValuePair( asString, null ); String aKey = asString.substring( 0, equalsIndex ); String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 ); diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathConverter.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathConverter.java new file mode 100644 index 00000000000..f542e8e0a65 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathConverter.java @@ -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 { + 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 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 ); + } +} diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathProperties.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathProperties.java new file mode 100644 index 00000000000..22066da2bc2 --- /dev/null +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathProperties.java @@ -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; + } +} diff --git a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java index b6ceee5557e..f51b375d86f 100644 --- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java @@ -31,7 +31,7 @@ * * 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 * a copy of this software and associated documentation files (the @@ -55,9 +55,11 @@ package jdk.internal.joptsimple.util; +import java.util.Locale; import 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.ValueConverter; @@ -96,8 +98,7 @@ public class RegexMatcher implements ValueConverter { public String convert( String value ) { if ( !pattern.matcher( value ).matches() ) { - throw new ValueConversionException( - "Value [" + value + "] did not match regex [" + pattern.pattern() + ']' ); + raiseValueConversionFailure( value ); } return value; @@ -110,4 +111,15 @@ public class RegexMatcher implements ValueConverter { public String valuePattern() { 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 ); + } } diff --git a/src/jdk.internal.opt/share/legal/jopt-simple.md b/src/jdk.internal.opt/share/legal/jopt-simple.md index 0d40507edaf..c08b3b4b94c 100644 --- a/src/jdk.internal.opt/share/legal/jopt-simple.md +++ b/src/jdk.internal.opt/share/legal/jopt-simple.md @@ -1,4 +1,4 @@ -## jopt-simple v4.6 +## jopt-simple v5.0.4 ### MIT License
    diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
    index eca78e675a2..0f6b488bf5e 100644
    --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
    +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
    @@ -1224,7 +1224,7 @@ public class JmodTask {
     
                 all.put(CMD_FILENAME, new OptionDescriptor() {
                     @Override
    -                public Collection options() {
    +                public List options() {
                         List ret = new ArrayList<>();
                         ret.add(CMD_FILENAME);
                         return ret;
    @@ -1314,7 +1314,7 @@ public class JmodTask {
                             .withValuesConvertedBy(new PatternConverter());
     
             OptionSpec help
    -                = parser.acceptsAll(Set.of("h", "help", "?"), getMessage("main.opt.help"))
    +                = parser.acceptsAll(List.of("h", "help", "?"), getMessage("main.opt.help"))
                             .forHelp();
     
             OptionSpec helpExtra
    @@ -1347,7 +1347,7 @@ public class JmodTask {
                             .withValuesConvertedBy(DirPathConverter.INSTANCE);
     
             OptionSpec> modulePath
    -                = parser.acceptsAll(Set.of("p", "module-path"),
    +                = parser.acceptsAll(List.of("p", "module-path"),
                                         getMessage("main.opt.module-path"))
                             .withRequiredArg()
                             .withValuesConvertedBy(DirPathConverter.INSTANCE);
    diff --git a/test/jdk/tools/jmod/JmodNegativeTest.java b/test/jdk/tools/jmod/JmodNegativeTest.java
    index 30205067b0e..e150d447f39 100644
    --- a/test/jdk/tools/jmod/JmodNegativeTest.java
    +++ b/test/jdk/tools/jmod/JmodNegativeTest.java
    @@ -100,7 +100,7 @@ public class JmodNegativeTest {
             jmod("--badOption")
                 .assertFailure()
                 .resultChecker(r ->
    -                assertContains(r.output, "Error: 'badOption' is not a recognized option")
    +                assertContains(r.output, "Error: badOption is not a recognized option")
                 );
         }
     
    diff --git a/test/jdk/tools/jmod/JmodTest.java b/test/jdk/tools/jmod/JmodTest.java
    index 5038dea0465..ca489634a70 100644
    --- a/test/jdk/tools/jmod/JmodTest.java
    +++ b/test/jdk/tools/jmod/JmodTest.java
    @@ -111,7 +111,7 @@ public class JmodTest {
     
             Path jmod = MODS_DIR.resolve("apa.jmod");
             jmod("create",
    -             "--libs=", libDir.toString(),
    +             "--libs=" + libDir.toString(),
                  "--class-path", classesDir.toString(),
                  jmod.toString())
                 .assertSuccess();
    @@ -310,7 +310,7 @@ public class JmodTest {
             Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
     
             jmod("create",
    -             "--libs=", lp.toString(),
    +             "--libs=" + lp.toString(),
                  "--class-path", cp.toString(),
                  jmod.toString())
                 .assertSuccess()
    @@ -335,8 +335,8 @@ public class JmodTest {
     
             jmod("create",
                  "--conf", cf.toString(),
    -             "--cmds=", bp.toString(),
    -             "--libs=", lp.toString(),
    +             "--cmds=" + bp.toString(),
    +             "--libs=" + lp.toString(),
                  "--class-path", cp.toString(),
                  jmod.toString())
                 .assertSuccess()
    @@ -361,7 +361,7 @@ public class JmodTest {
             Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
     
             jmod("create",
    -             "--libs=", lp.toString(),
    +             "--libs=" + lp.toString(),
                  "--class-path", cp.toString(),
                  "--exclude", "**internal**",
                  "--exclude", "first.so",