    001/*
    002  Licensed to the Apache Software Foundation (ASF) under one or more
    003  contributor license agreements.  See the NOTICE file distributed with
    004  this work for additional information regarding copyright ownership.
    005  The ASF licenses this file to You under the Apache License, Version 2.0
    006  (the "License"); you may not use this file except in compliance with
    007  the License.  You may obtain a copy of the License at
    008
    009      http://www.apache.org/licenses/LICENSE-2.0
    010
    011  Unless required by applicable law or agreed to in writing, software
    012  distributed under the License is distributed on an "AS IS" BASIS,
    013  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014  See the License for the specific language governing permissions and
    015  limitations under the License.
    016 */
    017
    018package org.apache.commons.cli;
    019
    020import static org.apache.commons.cli.Util.EMPTY_STRING_ARRAY;
    021
    022import java.io.Serializable;
    023import java.util.ArrayList;
    024import java.util.Iterator;
    025import java.util.LinkedList;
    026import java.util.List;
    027import java.util.Objects;
    028import java.util.Properties;
    029import java.util.function.Consumer;
    030import java.util.function.Supplier;
    031
    032/**
    033 * Represents list of arguments parsed against a {@link Options} descriptor.
    034 * <p>
    035 * It allows querying of a boolean {@link #hasOption(String opt)}, in addition to retrieving the
    036 * {@link #getOptionValue(String opt)} for options requiring arguments.
    037 * </p>
    038 * <p>
    039 * Additionally, any left-over or unrecognized arguments, are available for further processing.
    040 * </p>
    041 */
    042public class CommandLine implements Serializable {
    043
    044    /**
    045     * A nested builder class to create {@code CommandLine} instance using descriptive methods.
    046     *
    047     * @since 1.4
    048     */
    049    public static final class Builder {
    050
    051        /**
    052         * Prints an Option to {@link System#out}.
    053         */
    054        static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString());
    055
    056        /** The unrecognized options/arguments */
    057        private final List<String> args = new LinkedList<>();
    058
    059        /** The processed options */
    060        private final List<Option> options = new ArrayList<>();
    061
    062        /**
    063         * Deprecated Option handler.
    064         */
    065        private Consumer<Option> deprecatedHandler = DEPRECATED_HANDLER;
    066
    067        /**
    068         * Adds left-over unrecognized option/argument.
    069         *
    070         * @param arg the unrecognized option/argument.
    071         *
    072         * @return this Builder instance for method chaining.
    073         */
    074        public Builder addArg(final String arg) {
    075            if (arg != null) {
    076                args.add(arg);
    077            }
    078            return this;
    079        }
    080
    081        /**
    082         * Adds an option to the command line. The values of the option are stored.
    083         *
    084         * @param opt the processed option.
    085         *
    086         * @return this Builder instance for method chaining.
    087         */
    088        public Builder addOption(final Option opt) {
    089            if (opt != null) {
    090                options.add(opt);
    091            }
    092            return this;
    093        }
    094
    095        /**
    096         * Creates the new instance.
    097         *
    098         * @return the new instance.
    099         */
    100        public CommandLine build() {
    101            return new CommandLine(args, options, deprecatedHandler);
    102        }
    103
    104        /**
    105         * Sets the deprecated option handler.
    106         *
    107         * @param deprecatedHandler the deprecated option handler.
    108         * @return this.
    109         * @since 1.7.0
    110         */
    111        public Builder setDeprecatedHandler(final Consumer<Option> deprecatedHandler) {
    112            this.deprecatedHandler = deprecatedHandler;
    113            return this;
    114        }
    115    }
    116
    117    /** The serial version UID. */
    118    private static final long serialVersionUID = 1L;
    119
    120    /**
    121     * Creates a new builder.
    122     *
    123     * @return a new builder.
    124     * @since 1.7.0
    125     */
    126    public static Builder builder() {
    127        return new Builder();
    128    }
    129
    130    /** The unrecognized options/arguments */
    131    private final List<String> args;
    132
    133    /** The processed options */
    134    private final List<Option> options;
    135
    136    /**
    137     * The deprecated option handler.
    138     * <p>
    139     * If you want to serialize this field, use a serialization proxy.
    140     * </p>
    141     */
    142    private final transient Consumer<Option> deprecatedHandler;
    143
    144    /**
    145     * Creates a command line.
    146     */
    147    protected CommandLine() {
    148        this(new LinkedList<>(), new ArrayList<>(), Builder.DEPRECATED_HANDLER);
    149    }
    150
    151    /**
    152     * Creates a command line.
    153     */
    154    private CommandLine(final List<String> args, final List<Option> options, final Consumer<Option> deprecatedHandler) {
    155        this.args = Objects.requireNonNull(args, "args");
    156        this.options = Objects.requireNonNull(options, "options");
    157        this.deprecatedHandler = deprecatedHandler;
    158    }
    159
    160    /**
    161     * Adds left-over unrecognized option/argument.
    162     *
    163     * @param arg the unrecognized option/argument.
    164     */
    165    protected void addArg(final String arg) {
    166        if (arg != null) {
    167            args.add(arg);
    168        }
    169    }
    170
    171    /**
    172     * Adds an option to the command line. The values of the option are stored.
    173     *
    174     * @param opt the processed option.
    175     */
    176    protected void addOption(final Option opt) {
    177        if (opt != null) {
    178            options.add(opt);
    179        }
    180    }
    181
    182    private <T> T get(final Supplier<T> supplier) {
    183        return supplier == null ? null : supplier.get();
    184    }
    185
    186    /**
    187     * Gets any left-over non-recognized options and arguments
    188     *
    189     * @return remaining items passed in but not parsed as a {@code List}.
    190     */
    191    public List<String> getArgList() {
    192        return args;
    193    }
    194
    195    /**
    196     * Gets any left-over non-recognized options and arguments
    197     *
    198     * @return remaining items passed in but not parsed as an array.
    199     */
    200    public String[] getArgs() {
    201        return args.toArray(Util.EMPTY_STRING_ARRAY);
    202    }
    203
    204    /**
    205     * Gets the {@code Object} type of this {@code Option}.
    206     *
    207     * @deprecated due to System.err message. Instead use getParsedOptionValue(char)
    208     * @param opt the name of the option.
    209     * @return the type of opt.
    210     */
    211    @Deprecated
    212    public Object getOptionObject(final char opt) {
    213        return getOptionObject(String.valueOf(opt));
    214    }
    215
    216    /**
    217     * Gets the {@code Object} type of this {@code Option}.
    218     *
    219     * @param opt the name of the option.
    220     * @return the type of this {@code Option}.
    221     * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
    222     */
    223    @Deprecated
    224    public Object getOptionObject(final String opt) {
    225        try {
    226            return getParsedOptionValue(opt);
    227        } catch (final ParseException pe) {
    228            System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage());
    229            return null;
    230        }
    231    }
    232
    233    /**
    234     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    235     * <code>-Dparam1=value1
    236     * -Dparam2=value2</code>. All odd numbered values are property keys
    237     * and even numbered values are property values.  If there are an odd number of values
    238     * the last value is assumed to be a boolean flag and the value is "true".
    239     *
    240     * @param option name of the option.
    241     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
    242     * @since 1.5.0
    243     */
    244    public Properties getOptionProperties(final Option option) {
    245        final Properties props = new Properties();
    246        for (final Option processedOption : options) {
    247            if (processedOption.equals(option)) {
    248                processPropertiesFromValues(props, processedOption.getValuesList());
    249            }
    250        }
    251        return props;
    252    }
    253
    254    /**
    255     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    256     * <code>-Dparam1=value1
    257     * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
    258     * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
    259     *
    260     * @param opt name of the option.
    261     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
    262     * @since 1.2
    263     */
    264    public Properties getOptionProperties(final String opt) {
    265        final Properties props = new Properties();
    266        for (final Option option : options) {
    267            if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
    268                processPropertiesFromValues(props, option.getValuesList());
    269            }
    270        }
    271        return props;
    272    }
    273
    274    /**
    275     * Gets an array of the processed {@link Option}s.
    276     *
    277     * @return an array of the processed {@link Option}s.
    278     */
    279    public Option[] getOptions() {
    280        return options.toArray(Option.EMPTY_ARRAY);
    281    }
    282
    283    /**
    284     * Gets the first argument, if any, of this option.
    285     *
    286     * @param opt the character name of the option.
    287     * @return Value of the argument if option is set, and has an argument, otherwise null.
    288     */
    289    public String getOptionValue(final char opt) {
    290        return getOptionValue(String.valueOf(opt));
    291    }
    292
    293    /**
    294     * Gets the argument, if any, of an option.
    295     *
    296     * @param opt character name of the option
    297     * @param defaultValue is the default value to be returned if the option is not specified.
    298     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    299     */
    300    public String getOptionValue(final char opt, final String defaultValue) {
    301        return getOptionValue(String.valueOf(opt), () -> defaultValue);
    302    }
    303
    304    /**
    305     * Gets the argument, if any, of an option.
    306     *
    307     * @param opt character name of the option
    308     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    309     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    310     * @since 1.7.0
    311     */
    312    public String getOptionValue(final char opt, final Supplier<String> defaultValue) {
    313        return getOptionValue(String.valueOf(opt), defaultValue);
    314    }
    315
    316    /**
    317     * Gets the first argument, if any, of this option.
    318     *
    319     * @param option the name of the option.
    320     * @return Value of the argument if option is set, and has an argument, otherwise null.
    321     * @since 1.5.0
    322     */
    323    public String getOptionValue(final Option option) {
    324        final String[] values = getOptionValues(option);
    325        return values == null ? null : values[0];
    326    }
    327
    328    /**
    329     * Gets the first argument, if any, of an option.
    330     *
    331     * @param option name of the option.
    332     * @param defaultValue is the default value to be returned if the option is not specified.
    333     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    334     * @since 1.5.0
    335     */
    336    public String getOptionValue(final Option option, final String defaultValue) {
    337        return getOptionValue(option, () -> defaultValue);
    338    }
    339
    340    /**
    341     * Gets the first argument, if any, of an option.
    342     *
    343     * @param option name of the option.
    344     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    345     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    346     * @since 1.7.0
    347     */
    348    public String getOptionValue(final Option option, final Supplier<String> defaultValue) {
    349        final String answer = getOptionValue(option);
    350        return answer != null ? answer : get(defaultValue);
    351    }
    352
    353    /**
    354     * Gets the first argument, if any, of this option.
    355     *
    356     * @param opt the name of the option.
    357     * @return Value of the argument if option is set, and has an argument, otherwise null.
    358     */
    359    public String getOptionValue(final String opt) {
    360        return getOptionValue(resolveOption(opt));
    361    }
    362
    363    /**
    364     * Gets the first argument, if any, of an option.
    365     *
    366     * @param opt name of the option.
    367     * @param defaultValue is the default value to be returned if the option is not specified.
    368     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    369     */
    370    public String getOptionValue(final String opt, final String defaultValue) {
    371        return getOptionValue(resolveOption(opt), () -> defaultValue);
    372    }
    373
    374    /**
    375     * Gets the first argument, if any, of an option.
    376     *
    377     * @param opt name of the option.
    378     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    379     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    380     * @since 1.7.0
    381     */
    382    public String getOptionValue(final String opt, final Supplier<String> defaultValue) {
    383        return getOptionValue(resolveOption(opt), defaultValue);
    384    }
    385
    386
    387    /**
    388     * Gets the array of values, if any, of an option.
    389     *
    390     * @param opt character name of the option.
    391     * @return Values of the argument if option is set, and has an argument, otherwise null.
    392     */
    393    public String[] getOptionValues(final char opt) {
    394        return getOptionValues(String.valueOf(opt));
    395    }
    396
    397    /**
    398     * Gets the array of values, if any, of an option.
    399     *
    400     * @param option string name of the option.
    401     * @return Values of the argument if option is set, and has an argument, otherwise null.
    402     * @since 1.5.0
    403     */
    404    public String[] getOptionValues(final Option option) {
    405        if (option == null) {
    406            return null;
    407        }
    408        final List<String> values = new ArrayList<>();
    409        for (final Option processedOption : options) {
    410            if (processedOption.equals(option)) {
    411                values.addAll(processedOption.getValuesList());
    412            }
    413        }
    414        return values.isEmpty() ? null : values.toArray(EMPTY_STRING_ARRAY);
    415    }
    416
    417    /**
    418     * Gets the array of values, if any, of an option.
    419     *
    420     * @param opt string name of the option.
    421     * @return Values of the argument if option is set, and has an argument, otherwise null.
    422     */
    423    public String[] getOptionValues(final String opt) {
    424        return getOptionValues(resolveOption(opt));
    425    }
    426
    427    /**
    428     * Gets a version of this {@code Option} converted to a particular type.
    429     *
    430     * @param opt the name of the option.
    431     * @param <T> The return type for the method.
    432     * @return the value parsed into a particular object.
    433     * @throws ParseException if there are problems turning the option value into the desired type
    434     * @see PatternOptionBuilder
    435     * @since 1.5.0
    436     */
    437    public <T> T getParsedOptionValue(final char opt) throws ParseException {
    438        return getParsedOptionValue(String.valueOf(opt));
    439    }
    440
    441    /**
    442     * Gets a version of this {@code Option} converted to a particular type.
    443     *
    444     * @param opt the name of the option.
    445     * @param defaultValue the default value to return if opt is not set.
    446     * @param <T> The return type for the method.
    447     * @return the value parsed into a particular object.
    448     * @throws ParseException if there are problems turning the option value into the desired type
    449     * @see PatternOptionBuilder
    450     * @since 1.7.0
    451     */
    452    public <T> T getParsedOptionValue(final char opt, final Supplier<T> defaultValue) throws ParseException {
    453        return getParsedOptionValue(String.valueOf(opt), defaultValue);
    454    }
    455
    456    /**
    457     * Gets a version of this {@code Option} converted to a particular type.
    458     *
    459     * @param opt the name of the option.
    460     * @param defaultValue the default value to return if opt is not set.
    461     * @param <T> The return type for the method.
    462     * @return the value parsed into a particular object.
    463     * @throws ParseException if there are problems turning the option value into the desired type
    464     * @see PatternOptionBuilder
    465     * @since 1.7.0
    466     */
    467    public <T> T getParsedOptionValue(final char opt, final T defaultValue) throws ParseException {
    468        return getParsedOptionValue(String.valueOf(opt), defaultValue);
    469    }
    470
    471    /**
    472     * Gets a version of this {@code Option} converted to a particular type.
    473     *
    474     * @param option the name of the option.
    475     * @param <T> The return type for the method.
    476     * @return the value parsed into a particular object.
    477     * @throws ParseException if there are problems turning the option value into the desired type
    478     * @see PatternOptionBuilder
    479     * @since 1.5.0
    480     */
    481    public <T> T getParsedOptionValue(final Option option) throws ParseException {
    482        return getParsedOptionValue(option, () -> null);
    483    }
    484
    485    /**
    486     * Gets a version of this {@code Option} converted to a particular type.
    487     *
    488     * @param option the name of the option.
    489     * @param defaultValue the default value to return if opt is not set.
    490     * @param <T> The return type for the method.
    491     * @return the value parsed into a particular object.
    492     * @throws ParseException if there are problems turning the option value into the desired type
    493     * @see PatternOptionBuilder
    494     * @since 1.7.0
    495     */
    496    @SuppressWarnings("unchecked")
    497    public <T> T getParsedOptionValue(final Option option, final Supplier<T> defaultValue) throws ParseException {
    498        if (option == null) {
    499            return get(defaultValue);
    500        }
    501        final String res = getOptionValue(option);
    502        try {
    503            if (res == null) {
    504                return get(defaultValue);
    505            }
    506            return (T) option.getConverter().apply(res);
    507        } catch (final Throwable e) {
    508            throw ParseException.wrap(e);
    509        }
    510    }
    511
    512    /**
    513     * Gets a version of this {@code Option} converted to a particular type.
    514     *
    515     * @param option the name of the option.
    516     * @param defaultValue the default value to return if opt is not set.
    517     * @param <T> The return type for the method.
    518     * @return the value parsed into a particular object.
    519     * @throws ParseException if there are problems turning the option value into the desired type
    520     * @see PatternOptionBuilder
    521     * @since 1.7.0
    522     */
    523    public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException {
    524        return getParsedOptionValue(option, () -> defaultValue);
    525    }
    526
    527    /**
    528     * Gets a version of this {@code Option} converted to a particular type.
    529     *
    530     * @param opt the name of the option.
    531     * @param <T> The return type for the method.
    532     * @return the value parsed into a particular object.
    533     * @throws ParseException if there are problems turning the option value into the desired type
    534     * @see PatternOptionBuilder
    535     * @since 1.2
    536     */
    537    public <T> T getParsedOptionValue(final String opt) throws ParseException {
    538        return getParsedOptionValue(resolveOption(opt));
    539    }
    540
    541    /**
    542     * Gets a version of this {@code Option} converted to a particular type.
    543     *
    544     * @param opt the name of the option.
    545     * @param defaultValue the default value to return if opt is not set.
    546     * @param <T> The return type for the method.
    547     * @return the value parsed into a particular object.
    548     * @throws ParseException if there are problems turning the option value into the desired type
    549     * @see PatternOptionBuilder
    550     * @since 1.7.0
    551     */
    552    public <T> T getParsedOptionValue(final String opt, final Supplier<T> defaultValue) throws ParseException {
    553        return getParsedOptionValue(resolveOption(opt), defaultValue);
    554    }
    555
    556    /**
    557     * Gets a version of this {@code Option} converted to a particular type.
    558     *
    559     * @param opt the name of the option.
    560     * @param defaultValue the default value to return if opt is not set.
    561     * @param <T> The return type for the method.
    562     * @return the value parsed into a particular object.
    563     * @throws ParseException if there are problems turning the option value into the desired type
    564     * @see PatternOptionBuilder
    565     * @since 1.7.0
    566     */
    567    public <T> T getParsedOptionValue(final String opt, final T defaultValue) throws ParseException {
    568        return getParsedOptionValue(resolveOption(opt), defaultValue);
    569    }
    570
    571    /**
    572     * Handles deprecated options.
    573     *
    574     * @param option a deprecated option.
    575     */
    576    private void handleDeprecated(final Option option) {
    577        if (deprecatedHandler != null) {
    578            deprecatedHandler.accept(option);
    579        }
    580    }
    581
    582    /**
    583     * jkeyes - commented out until it is implemented properly
    584     * <p>
    585     * Dump state, suitable for debugging.
    586     * </p>
    587     *
    588     * @return Stringified form of this object.
    589     */
    590
    591    /*
    592     * public String toString() { StringBuilder buf = new StringBuilder();
    593     *
    594     * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
    595     * buf.append(args.toString()); buf.append(" ] ]");
    596     *
    597     * return buf.toString(); }
    598     */
    599
    600    /**
    601     * Tests to see if an option has been set.
    602     *
    603     * @param opt character name of the option.
    604     * @return true if set, false if not.
    605     */
    606    public boolean hasOption(final char opt) {
    607        return hasOption(String.valueOf(opt));
    608    }
    609
    610    /**
    611     * Tests to see if an option has been set.
    612     *
    613     * @param opt the option to check.
    614     * @return true if set, false if not.
    615     * @since 1.5.0
    616     */
    617    public boolean hasOption(final Option opt) {
    618        return options.contains(opt);
    619    }
    620
    621    /**
    622     * Tests to see if an option has been set.
    623     *
    624     * @param opt Short name of the option.
    625     * @return true if set, false if not.
    626     */
    627    public boolean hasOption(final String opt) {
    628        return hasOption(resolveOption(opt));
    629    }
    630
    631    /**
    632     * Returns an iterator over the Option members of CommandLine.
    633     *
    634     * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
    635     */
    636    public Iterator<Option> iterator() {
    637        return options.iterator();
    638    }
    639
    640    /**
    641     * Parses a list of values as properties.  All odd numbered values are property keys
    642     * and even numbered values are property values.  If there are an odd number of values
    643     * the last value is assumed to be a boolean with a value of "true".
    644     * @param props the properties to update.
    645     * @param values the list of values to parse.
    646     */
    647    private void processPropertiesFromValues(final Properties props, final List<String> values) {
    648        for (int i = 0; i < values.size(); i += 2) {
    649            if (i + 1 < values.size()) {
    650                props.put(values.get(i), values.get(i + 1));
    651            } else {
    652                props.put(values.get(i), "true");
    653            }
    654        }
    655    }
    656
    657    /**
    658     * Retrieves the option object given the long or short option as a String
    659     *
    660     * @param opt short or long name of the option, may be null.
    661     * @return Canonicalized option.
    662     */
    663    private Option resolveOption(final String opt) {
    664        final String actual = Util.stripLeadingHyphens(opt);
    665        if (actual != null) {
    666            for (final Option option : options) {
    667                if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) {
    668                    if (option.isDeprecated()) {
    669                        handleDeprecated(option);
    670                    }
    671                    return option;
    672                }
    673            }
    674        }
    675        return null;
    676    }
    677}