    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      https://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 java.io.Serializable;
    021import java.lang.reflect.Array;
    022import java.util.ArrayList;
    023import java.util.Iterator;
    024import java.util.LinkedList;
    025import java.util.List;
    026import java.util.Objects;
    027import java.util.Properties;
    028import java.util.function.Consumer;
    029import java.util.function.Supplier;
    030
    031/**
    032 * Represents list of arguments parsed against a {@link Options} descriptor.
    033 * <p>
    034 * It allows querying of a boolean {@link #hasOption(String optionName)}, in addition to retrieving the
    035 * {@link #getOptionValue(String optionName)} for options requiring arguments.
    036 * </p>
    037 * <p>
    038 * Additionally, any left-over or unrecognized arguments, are available for further processing.
    039 * </p>
    040 */
    041public class CommandLine implements Serializable {
    042
    043    /**
    044     * A nested builder class to create {@code CommandLine} instance using descriptive methods.
    045     *
    046     * @since 1.4
    047     */
    048    public static final class Builder implements Supplier<CommandLine> {
    049
    050        /**
    051         * Prints an Option to {@link System#out}.
    052         */
    053        static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString());
    054
    055        /** The unrecognized options/arguments */
    056        private final List<String> args = new LinkedList<>();
    057
    058        /** The processed options */
    059        private final List<Option> options = new ArrayList<>();
    060
    061        /**
    062         * Deprecated Option handler.
    063         */
    064        private Consumer<Option> deprecatedHandler = DEPRECATED_HANDLER;
    065
    066        /**
    067         * Constructs a new instance.
    068         *
    069         * @deprecated Use {@link #builder()}.
    070         */
    071        @Deprecated
    072        public Builder() {
    073            // empty
    074        }
    075
    076        /**
    077         * Adds left-over unrecognized option/argument.
    078         *
    079         * @param arg the unrecognized option/argument.
    080         * @return this Builder instance for method chaining.
    081         */
    082        public Builder addArg(final String arg) {
    083            if (arg != null) {
    084                args.add(arg);
    085            }
    086            return this;
    087        }
    088
    089        /**
    090         * Adds an option to the command line. The values of the option are stored.
    091         *
    092         * @param option the processed option.
    093         * @return this Builder instance for method chaining.
    094         */
    095        public Builder addOption(final Option option) {
    096            if (option != null) {
    097                options.add(option);
    098            }
    099            return this;
    100        }
    101
    102        /**
    103         * Creates a new instance.
    104         *
    105         * @return a new instance.
    106         * @deprecated Use {@link #get()}.
    107         */
    108        @Deprecated
    109        public CommandLine build() {
    110            return get();
    111        }
    112
    113        /**
    114         * Creates a new instance.
    115         *
    116         * @return a new instance.
    117         * @since 1.10.0
    118         */
    119        @Override
    120        public CommandLine get() {
    121            return new CommandLine(args, options, deprecatedHandler);
    122        }
    123
    124        /**
    125         * Sets the deprecated option handler.
    126         *
    127         * @param deprecatedHandler the deprecated option handler.
    128         * @return {@code this} instance.
    129         * @since 1.7.0
    130         */
    131        public Builder setDeprecatedHandler(final Consumer<Option> deprecatedHandler) {
    132            this.deprecatedHandler = deprecatedHandler;
    133            return this;
    134        }
    135    }
    136
    137    /** The serial version UID. */
    138    private static final long serialVersionUID = 1L;
    139
    140    /**
    141     * Creates a new builder.
    142     *
    143     * @return a new builder.
    144     * @since 1.7.0
    145     */
    146    public static Builder builder() {
    147        return new Builder();
    148    }
    149
    150    /** The unrecognized options/arguments */
    151    private final List<String> args;
    152
    153    /** The processed options */
    154    private final List<Option> options;
    155
    156    /**
    157     * The deprecated option handler.
    158     * <p>
    159     * If you want to serialize this field, use a serialization proxy.
    160     * </p>
    161     */
    162    private final transient Consumer<Option> deprecatedHandler;
    163
    164    /**
    165     * Creates a command line.
    166     */
    167    protected CommandLine() {
    168        this(new LinkedList<>(), new ArrayList<>(), Builder.DEPRECATED_HANDLER);
    169    }
    170
    171    /**
    172     * Creates a command line.
    173     */
    174    private CommandLine(final List<String> args, final List<Option> options, final Consumer<Option> deprecatedHandler) {
    175        this.args = Objects.requireNonNull(args, "args");
    176        this.options = Objects.requireNonNull(options, "options");
    177        this.deprecatedHandler = deprecatedHandler;
    178    }
    179
    180    /**
    181     * Adds left-over unrecognized option/argument.
    182     *
    183     * @param arg the unrecognized option/argument.
    184     */
    185    protected void addArg(final String arg) {
    186        if (arg != null) {
    187            args.add(arg);
    188        }
    189    }
    190
    191    /**
    192     * Adds an option to the command line. The values of the option are stored.
    193     *
    194     * @param option the processed option.
    195     */
    196    protected void addOption(final Option option) {
    197        if (option != null) {
    198            options.add(option);
    199        }
    200    }
    201
    202    private <T> T get(final Supplier<T> supplier) {
    203        return supplier == null ? null : supplier.get();
    204    }
    205
    206    /**
    207     * Gets any left-over non-recognized options and arguments
    208     *
    209     * @return remaining items passed in but not parsed as a {@code List}.
    210     */
    211    public List<String> getArgList() {
    212        return args;
    213    }
    214
    215    /**
    216     * Gets any left-over non-recognized options and arguments
    217     *
    218     * @return remaining items passed in but not parsed as an array.
    219     */
    220    public String[] getArgs() {
    221        return args.toArray(Util.EMPTY_STRING_ARRAY);
    222    }
    223
    224    /**
    225     * Gets the {@code Object} type of this {@code Option}.
    226     *
    227     * @deprecated due to System.err message. Instead use getParsedOptionValue(char)
    228     * @param optionChar the name of the option.
    229     * @return the type of opt.
    230     */
    231    @Deprecated
    232    public Object getOptionObject(final char optionChar) {
    233        return getOptionObject(String.valueOf(optionChar));
    234    }
    235
    236    /**
    237     * Gets the {@code Object} type of this {@code Option}.
    238     *
    239     * @param optionName the name of the option.
    240     * @return the type of this {@code Option}.
    241     * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
    242     */
    243    @Deprecated
    244    public Object getOptionObject(final String optionName) {
    245        try {
    246            return getParsedOptionValue(optionName);
    247        } catch (final ParseException pe) {
    248            System.err.println("Exception found converting " + optionName + " to desired type: " + pe.getMessage());
    249            return null;
    250        }
    251    }
    252
    253    /**
    254     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    255     * <code>-Dparam1=value1
    256     * -Dparam2=value2</code>. All odd numbered values are property keys
    257     * and even numbered values are property values.  If there are an odd number of values
    258     * the last value is assumed to be a boolean flag and the value is "true".
    259     *
    260     * @param option 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.5.0
    263     */
    264    public Properties getOptionProperties(final Option option) {
    265        final Properties props = new Properties();
    266        for (final Option processedOption : options) {
    267            if (processedOption.equals(option)) {
    268                processPropertiesFromValues(props, processedOption.getValuesList());
    269            }
    270        }
    271        return props;
    272    }
    273
    274    /**
    275     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    276     * <code>-Dparam1=value1
    277     * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
    278     * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
    279     *
    280     * @param optionName name of the option.
    281     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
    282     * @since 1.2
    283     */
    284    public Properties getOptionProperties(final String optionName) {
    285        final Properties props = new Properties();
    286        for (final Option option : options) {
    287            if (optionName.equals(option.getOpt()) || optionName.equals(option.getLongOpt())) {
    288                processPropertiesFromValues(props, option.getValuesList());
    289            }
    290        }
    291        return props;
    292    }
    293
    294    /**
    295     * Gets an array of the processed {@link Option}s.
    296     *
    297     * @return an array of the processed {@link Option}s.
    298     */
    299    public Option[] getOptions() {
    300        return options.toArray(Option.EMPTY_ARRAY);
    301    }
    302
    303    /**
    304     * Gets the first argument, if any, of this option.
    305     *
    306     * @param optionChar the character name of the option.
    307     * @return Value of the argument if option is set, and has an argument, otherwise null.
    308     */
    309    public String getOptionValue(final char optionChar) {
    310        return getOptionValue(String.valueOf(optionChar));
    311    }
    312
    313    /**
    314     * Gets the argument, if any, of an option.
    315     *
    316     * @param optionChar character name of the option
    317     * @param defaultValue is the default value to be returned if the option is not specified.
    318     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    319     */
    320    public String getOptionValue(final char optionChar, final String defaultValue) {
    321        return getOptionValue(String.valueOf(optionChar), () -> defaultValue);
    322    }
    323
    324    /**
    325     * Gets the argument, if any, of an option.
    326     *
    327     * @param optionChar character name of the option
    328     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    329     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    330     * @since 1.7.0
    331     */
    332    public String getOptionValue(final char optionChar, final Supplier<String> defaultValue) {
    333        return getOptionValue(String.valueOf(optionChar), defaultValue);
    334    }
    335
    336    /**
    337     * Gets the first argument, if any, of this option.
    338     *
    339     * @param option the option.
    340     * @return Value of the argument if option is set, and has an argument, otherwise null.
    341     * @since 1.5.0
    342     */
    343    public String getOptionValue(final Option option) {
    344        final String[] values = getOptionValues(option);
    345        return values == null ? null : values[0];
    346    }
    347
    348    /**
    349     * Gets the first argument, if any, of an option.
    350     *
    351     * @param option the option.
    352     * @param defaultValue is the default value to be returned if the option is not specified.
    353     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    354     * @since 1.5.0
    355     */
    356    public String getOptionValue(final Option option, final String defaultValue) {
    357        return getOptionValue(option, () -> defaultValue);
    358    }
    359
    360    /**
    361     * Gets the first argument, if any, of an option.
    362     *
    363     * @param option the option.
    364     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    365     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    366     * @since 1.7.0
    367     */
    368    public String getOptionValue(final Option option, final Supplier<String> defaultValue) {
    369        final String answer = getOptionValue(option);
    370        return answer != null ? answer : get(defaultValue);
    371    }
    372
    373    /**
    374     * Gets the first argument, if any, of this option group.
    375     *
    376     * @param optionGroup the option group.
    377     * @return Value of the argument if option group is selected, and has an argument, otherwise null.
    378     * @since 1.9.0
    379     */
    380    public String getOptionValue(final OptionGroup optionGroup) {
    381        final String[] values = getOptionValues(optionGroup);
    382        return values == null ? null : values[0];
    383    }
    384
    385    /**
    386     * Gets the first argument, if any, of an option group.
    387     *
    388     * @param optionGroup the option group.
    389     * @param defaultValue is the default value to be returned if the option group is not selected.
    390     * @return Value of the argument if option group is selected, and has an argument, otherwise {@code defaultValue}.
    391     * @since 1.9.0
    392     */
    393    public String getOptionValue(final OptionGroup optionGroup, final String defaultValue) {
    394        return getOptionValue(optionGroup, () -> defaultValue);
    395    }
    396
    397    /**
    398     * Gets the first argument, if any, of an option group.
    399     *
    400     * @param optionGroup the option group.
    401     * @param defaultValue is a supplier for the default value to be returned if the option group is not selected.
    402     * @return Value of the argument if option group is selected, and has an argument, otherwise {@code defaultValue}.
    403     * @since 1.9.0
    404     */
    405    public String getOptionValue(final OptionGroup optionGroup, final Supplier<String> defaultValue) {
    406        final String answer = getOptionValue(optionGroup);
    407        return answer != null ? answer : get(defaultValue);
    408    }
    409
    410    /**
    411     * Gets the first argument, if any, of this option.
    412     *
    413     * @param optionName the name of the option.
    414     * @return Value of the argument if option is set, and has an argument, otherwise null.
    415     */
    416    public String getOptionValue(final String optionName) {
    417        return getOptionValue(resolveOption(optionName));
    418    }
    419
    420    /**
    421     * Gets the first argument, if any, of an option.
    422     *
    423     * @param optionName name of the option.
    424     * @param defaultValue is the default value to be returned if the option is not specified.
    425     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    426     */
    427    public String getOptionValue(final String optionName, final String defaultValue) {
    428        return getOptionValue(resolveOption(optionName), () -> defaultValue);
    429    }
    430
    431    /**
    432     * Gets the first argument, if any, of an option.
    433     *
    434     * @param optionName name of the option.
    435     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    436     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    437     * @since 1.7.0
    438     */
    439    public String getOptionValue(final String optionName, final Supplier<String> defaultValue) {
    440        return getOptionValue(resolveOption(optionName), defaultValue);
    441    }
    442
    443    /**
    444     * Gets the array of values, if any, of an option.
    445     *
    446     * @param optionChar character name of the option.
    447     * @return Values of the argument if option is set, and has an argument, otherwise null.
    448     */
    449    public String[] getOptionValues(final char optionChar) {
    450        return getOptionValues(String.valueOf(optionChar));
    451    }
    452
    453    /**
    454     * Gets the array of values, if any, of an option.
    455     *
    456     * @param option the option.
    457     * @return Values of the argument if option is set, and has an argument, otherwise null.
    458     * @since 1.5.0
    459     */
    460    public String[] getOptionValues(final Option option) {
    461        if (option == null) {
    462            return null;
    463        }
    464        final List<String> values = new ArrayList<>();
    465        for (final Option processedOption : options) {
    466            if (processedOption.equals(option)) {
    467                if (option.isDeprecated()) {
    468                    handleDeprecated(option);
    469                }
    470                values.addAll(processedOption.getValuesList());
    471            }
    472        }
    473        return values.isEmpty() ? null : values.toArray(Util.EMPTY_STRING_ARRAY);
    474    }
    475
    476    /**
    477     * Gets the array of values, if any, of an option group.
    478     *
    479     * @param optionGroup the option group.
    480     * @return Values of the argument if option group is selected, and has an argument, otherwise null.
    481     * @since 1.9.0
    482     */
    483    public String[] getOptionValues(final OptionGroup optionGroup) {
    484        if (optionGroup == null || !optionGroup.isSelected()) {
    485            return null;
    486        }
    487        return getOptionValues(optionGroup.getSelected());
    488    }
    489
    490    /**
    491     * Gets the array of values, if any, of an option.
    492     *
    493     * @param optionName string name of the option.
    494     * @return Values of the argument if option is set, and has an argument, otherwise null.
    495     */
    496    public String[] getOptionValues(final String optionName) {
    497        return getOptionValues(resolveOption(optionName));
    498    }
    499
    500    /**
    501     * Gets a version of this {@code Option} converted to a particular type.
    502     *
    503     * @param optionChar the name of the option.
    504     * @param <T> The return type for the method.
    505     * @return the value parsed into a particular object or null if the option is not set.
    506     * @throws ParseException if there are problems turning the option value into the desired type
    507     * @see PatternOptionBuilder
    508     * @since 1.5.0
    509     */
    510    public <T> T getParsedOptionValue(final char optionChar) throws ParseException {
    511        return getParsedOptionValue(String.valueOf(optionChar));
    512    }
    513
    514    /**
    515     * Gets a version of this {@code Option} converted to a particular type.
    516     *
    517     * @param optionChar the name of the option.
    518     * @param defaultValue the default value to return if opt is not set.
    519     * @param <T> The return type for the method.
    520     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    521     * @throws ParseException if there are problems turning the option value into the desired type
    522     * @see PatternOptionBuilder
    523     * @since 1.7.0
    524     */
    525    public <T> T getParsedOptionValue(final char optionChar, final Supplier<T> defaultValue) throws ParseException {
    526        return getParsedOptionValue(String.valueOf(optionChar), defaultValue);
    527    }
    528
    529    /**
    530     * Gets a version of this {@code Option} converted to a particular type.
    531     *
    532     * @param optionChar the name of the option.
    533     * @param defaultValue the default value to return if opt is not set.
    534     * @param <T> The return type for the method.
    535     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    536     * @throws ParseException if there are problems turning the option value into the desired type
    537     * @see PatternOptionBuilder
    538     * @since 1.7.0
    539     */
    540    public <T> T getParsedOptionValue(final char optionChar, final T defaultValue) throws ParseException {
    541        return getParsedOptionValue(String.valueOf(optionChar), defaultValue);
    542    }
    543
    544    /**
    545     * Gets a version of this {@code Option} converted to a particular type.
    546     *
    547     * @param option the option.
    548     * @param <T> The return type for the method.
    549     * @return the value parsed into a particular object or null if the option is not set.
    550     * @throws ParseException if there are problems turning the option value into the desired type
    551     * @see PatternOptionBuilder
    552     * @since 1.5.0
    553     */
    554    public <T> T getParsedOptionValue(final Option option) throws ParseException {
    555        return getParsedOptionValue(option, () -> null);
    556    }
    557
    558    /**
    559     * Gets a version of this {@code Option} converted to a particular type.
    560     *
    561     * @param option the option.
    562     * @param defaultValue the default value to return if opt is not set.
    563     * @param <T> The return type for the method.
    564     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    565     * @throws ParseException if there are problems turning the option value into the desired type
    566     * @see PatternOptionBuilder
    567     * @since 1.7.0
    568     */
    569    @SuppressWarnings("unchecked")
    570    public <T> T getParsedOptionValue(final Option option, final Supplier<T> defaultValue) throws ParseException {
    571        if (option == null) {
    572            return get(defaultValue);
    573        }
    574        final String res = getOptionValue(option);
    575        try {
    576            if (res == null) {
    577                return get(defaultValue);
    578            }
    579            return (T) option.getConverter().apply(res);
    580        } catch (final Exception e) {
    581            throw ParseException.wrap(e);
    582        }
    583    }
    584
    585    /**
    586     * Gets a version of this {@code Option} converted to a particular type.
    587     *
    588     * @param option the option.
    589     * @param defaultValue the default value to return if opt is not set.
    590     * @param <T> The return type for the method.
    591     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    592     * @throws ParseException if there are problems turning the option value into the desired type
    593     * @see PatternOptionBuilder
    594     * @since 1.7.0
    595     */
    596    public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException {
    597        return getParsedOptionValue(option, () -> defaultValue);
    598    }
    599
    600    /**
    601     * Gets a version of this {@code OptionGroup} converted to a particular type.
    602     *
    603     * @param optionGroup the option group.
    604     * @param <T> The return type for the method.
    605     * @return the value parsed into a particular object or null if no option in the OptionGroup is set.
    606     * @throws ParseException if there are problems turning the selected option value into the desired type
    607     * @see PatternOptionBuilder
    608     * @since 1.9.0
    609     */
    610    public <T> T getParsedOptionValue(final OptionGroup optionGroup) throws ParseException {
    611        return getParsedOptionValue(optionGroup, () -> null);
    612    }
    613
    614    /**
    615     * Gets a version of this {@code OptionGroup} converted to a particular type.
    616     *
    617     * @param optionGroup the option group.
    618     * @param defaultValue the default value to return if opt is not set.
    619     * @param <T> The return type for the method.
    620     * @return the value parsed into a particular object or the defaultValue if no option in the OptionGroup is set.
    621     * @throws ParseException if there are problems turning the selected option value into the desired type
    622     * @see PatternOptionBuilder
    623     * @since 1.9.0
    624     */
    625    public <T> T getParsedOptionValue(final OptionGroup optionGroup, final Supplier<T> defaultValue) throws ParseException {
    626        if (optionGroup == null || !optionGroup.isSelected()) {
    627            return get(defaultValue);
    628        }
    629        return getParsedOptionValue(optionGroup.getSelected(), defaultValue);
    630    }
    631
    632    /**
    633     * Gets a version of this {@code OptionGroup} converted to a particular type.
    634     *
    635     * @param optionGroup the option group.
    636     * @param defaultValue the default value to return if an option is not selected.
    637     * @param <T> The return type for the method.
    638     * @return the value parsed into a particular object or the defaultValue if no option in the OptionGroup is set.
    639     * @throws ParseException if there are problems turning the option value into the desired type
    640     * @see PatternOptionBuilder
    641     * @since 1.9.0
    642     */
    643    public <T> T getParsedOptionValue(final OptionGroup optionGroup, final T defaultValue) throws ParseException {
    644        return getParsedOptionValue(optionGroup, () -> defaultValue);
    645    }
    646
    647    /**
    648     * Gets a version of this {@code Option} converted to a particular type.
    649     *
    650     * @param optionName the name of the option.
    651     * @param <T> The return type for the method.
    652     * @return the value parsed into a particular object or null if the option is not set.
    653     * @throws ParseException if there are problems turning the option value into the desired type
    654     * @see PatternOptionBuilder
    655     * @since 1.2
    656     */
    657    public <T> T getParsedOptionValue(final String optionName) throws ParseException {
    658        return getParsedOptionValue(resolveOption(optionName));
    659    }
    660
    661    /**
    662     * Gets a version of this {@code Option} converted to a particular type.
    663     *
    664     * @param optionName the name of the option.
    665     * @param defaultValue the default value to return if opt is not set.
    666     * @param <T> The return type for the method.
    667     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    668     * @throws ParseException if there are problems turning the option value into the desired type
    669     * @see PatternOptionBuilder
    670     * @since 1.7.0
    671     */
    672    public <T> T getParsedOptionValue(final String optionName, final Supplier<T> defaultValue) throws ParseException {
    673        return getParsedOptionValue(resolveOption(optionName), defaultValue);
    674    }
    675
    676    /**
    677     * Gets a version of this {@code Option} converted to a particular type.
    678     *
    679     * @param optionName the name of the option.
    680     * @param defaultValue the default value to return if opt is not set.
    681     * @param <T> The return type for the method.
    682     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    683     * @throws ParseException if there are problems turning the option value into the desired type
    684     * @see PatternOptionBuilder
    685     * @since 1.7.0
    686     */
    687    public <T> T getParsedOptionValue(final String optionName, final T defaultValue) throws ParseException {
    688        return getParsedOptionValue(resolveOption(optionName), defaultValue);
    689    }
    690
    691    /**
    692     * Gets a version of this {@code Option} converted to an array of a particular type.
    693     *
    694     * @param optionChar the name of the option.
    695     * @param <T> The array type for the return value.
    696     * @return the values parsed into an array of objects or null if the option is not set.
    697     * @throws ParseException if there are problems turning the option value into the desired type
    698     * @see PatternOptionBuilder
    699     * @since 1.10.0
    700     */
    701    public <T> T[] getParsedOptionValues(final char optionChar) throws ParseException {
    702        return getParsedOptionValues(String.valueOf(optionChar));
    703    }
    704
    705    /**
    706     * Gets a version of this {@code Option} converted to an array of a particular type.
    707     *
    708     * @param optionChar the name of the option.
    709     * @param defaultValue the default value to return if opt is not set.
    710     * @param <T> The array type for the return value.
    711     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    712     * @throws ParseException if there are problems turning the option value into the desired type
    713     * @see PatternOptionBuilder
    714     * @since 1.10.0
    715     */
    716    public <T> T[] getParsedOptionValues(final char optionChar, final Supplier<T[]> defaultValue) throws ParseException {
    717        return getParsedOptionValues(String.valueOf(optionChar), defaultValue);
    718    }
    719
    720    /**
    721     * Gets a version of this {@code Option} converted to an array of a particular type.
    722     *
    723     * @param optionChar the name of the option.
    724     * @param defaultValue the default value to return if opt is not set.
    725     * @param <T> The array type for the return value.
    726     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    727     * @throws ParseException if there are problems turning the option value into the desired type
    728     * @see PatternOptionBuilder
    729     * @since 1.10.0
    730     */
    731    public <T> T[] getParsedOptionValues(final char optionChar, final T[] defaultValue) throws ParseException {
    732        return getParsedOptionValues(String.valueOf(optionChar), defaultValue);
    733    }
    734
    735    /**
    736     * Gets a version of this {@code Option} converted to an array of a particular type.
    737     *
    738     * @param option the option.
    739     * @param <T> The array type for the return value.
    740     * @return the values parsed into an array of objects or null if the option is not set.
    741     * @throws ParseException if there are problems turning the option value into the desired type
    742     * @see PatternOptionBuilder
    743     * @since 1.10.0
    744     */
    745    public <T> T[] getParsedOptionValues(final Option option) throws ParseException {
    746        return getParsedOptionValues(option, () -> null);
    747    }
    748
    749    /**
    750     * Gets a version of this {@code Option} converted to an array of a particular type.
    751     *
    752     * @param option the option.
    753     * @param defaultValue the default value to return if opt is not set.
    754     * @param <T> The array type for the return value.
    755     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    756     * @throws ParseException if there are problems turning the option value into the desired type
    757     * @see PatternOptionBuilder
    758     * @since 1.10.0
    759     */
    760    @SuppressWarnings("unchecked")
    761    public <T> T[] getParsedOptionValues(final Option option, final Supplier<T[]> defaultValue) throws ParseException {
    762        if (option == null) {
    763            return get(defaultValue);
    764        }
    765        final Class<? extends T> clazz = (Class<? extends T>) option.getType();
    766        final String[] values = getOptionValues(option);
    767        if (values == null) {
    768            return get(defaultValue);
    769        }
    770        final T[] result = (T[]) Array.newInstance(clazz, values.length);
    771        try {
    772            for (int i = 0; i < values.length; i++) {
    773                result[i] = clazz.cast(option.getConverter().apply(values[i]));
    774            }
    775            return result;
    776        } catch (final Exception t) {
    777            throw ParseException.wrap(t);
    778        }
    779    }
    780
    781    /**
    782     * Gets a version of this {@code Option} converted to an array of a particular type.
    783     *
    784     * @param option the option.
    785     * @param defaultValue the default value to return if opt is not set.
    786     * @param <T> The array type for the return value.
    787     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    788     * @throws ParseException if there are problems turning the option value into the desired type
    789     * @see PatternOptionBuilder
    790     * @since 1.10.0
    791     */
    792    public <T> T[] getParsedOptionValues(final Option option, final T[] defaultValue) throws ParseException {
    793        return getParsedOptionValues(option, () -> defaultValue);
    794    }
    795
    796    /**
    797     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    798     *
    799     * @param optionGroup the option group.
    800     * @param <T> The array type for the return value.
    801     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    802     * @throws ParseException if there are problems turning the selected option value into the desired type
    803     * @see PatternOptionBuilder
    804     * @since 1.10.0
    805     */
    806    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup) throws ParseException {
    807        return getParsedOptionValues(optionGroup, () -> null);
    808    }
    809
    810    /**
    811     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    812     *
    813     * @param optionGroup the option group.
    814     * @param defaultValue the default value to return if opt is not set.
    815     * @param <T> The array type for the return value.
    816     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    817     * @throws ParseException if there are problems turning the selected option value into the desired type
    818     * @see PatternOptionBuilder
    819     * @since 1.10.0
    820     */
    821    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup, final Supplier<T[]> defaultValue) throws ParseException {
    822        if (optionGroup == null || !optionGroup.isSelected()) {
    823            return get(defaultValue);
    824        }
    825        return getParsedOptionValues(optionGroup.getSelected(), defaultValue);
    826    }
    827
    828    /**
    829     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    830     *
    831     * @param optionGroup the option group.
    832     * @param defaultValue the default value to return if an option is not selected.
    833     * @param <T> The array type for the return value.
    834     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    835     * @throws ParseException if there are problems turning the option value into the desired type
    836     * @see PatternOptionBuilder
    837     * @since 1.10.0
    838     */
    839    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup, final T[] defaultValue) throws ParseException {
    840        return getParsedOptionValues(optionGroup, () -> defaultValue);
    841    }
    842
    843    /**
    844     * Gets a version of this {@code Option} converted to an array of a particular type.
    845     *
    846     * @param optionName the name of the option.
    847     * @param <T> The array type for the return value.
    848     * @return the values parsed into an array of objects or null if the option is not set.
    849     * @throws ParseException if there are problems turning the option value into the desired type
    850     * @see PatternOptionBuilder
    851     * @since 1.10.0
    852     */
    853    public <T> T[] getParsedOptionValues(final String optionName) throws ParseException {
    854        return getParsedOptionValues(resolveOption(optionName));
    855    }
    856
    857    /**
    858     * Gets a version of this {@code Option} converted to an array of a particular type.
    859     *
    860     * @param optionName the name of the option.
    861     * @param defaultValue the default value to return if opt is not set.
    862     * @param <T> The array type for the return value.
    863     * @return the values parsed into an array of objects or defaultValues if the option is not set.
    864     * @throws ParseException if there are problems turning the option value into the desired type
    865     * @see PatternOptionBuilder
    866     * @since 1.10.0
    867     */
    868    public <T> T[] getParsedOptionValues(final String optionName, final Supplier<T[]> defaultValue) throws ParseException {
    869        return getParsedOptionValues(resolveOption(optionName), defaultValue);
    870    }
    871
    872    /**
    873     * Gets a version of this {@code Option} converted to an array of a particular type.
    874     *
    875     * @param optionName the name of the option.
    876     * @param defaultValue the default value to return if opt is not set.
    877     * @param <T> The array type for the return value.
    878     * @return the values parsed into an array of objects or defaultValues if the option is not set.
    879     * @throws ParseException if there are problems turning the option value into the desired type
    880     * @see PatternOptionBuilder
    881     * @since 1.10.0
    882     */
    883    public <T> T[] getParsedOptionValues(final String optionName, final T[] defaultValue) throws ParseException {
    884        return getParsedOptionValues(resolveOption(optionName), defaultValue);
    885    }
    886
    887    /**
    888     * Handles deprecated options.
    889     *
    890     * @param option a deprecated option.
    891     */
    892    private void handleDeprecated(final Option option) {
    893        if (deprecatedHandler != null) {
    894            deprecatedHandler.accept(option);
    895        }
    896    }
    897
    898    /**
    899     * jkeyes - commented out until it is implemented properly
    900     * <p>
    901     * Dump state, suitable for debugging.
    902     * </p>
    903     *
    904     * @return Stringified form of this object.
    905     */
    906
    907    /*
    908     * public String toString() { StringBuilder buf = new StringBuilder();
    909     *
    910     * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
    911     * buf.append(args.toString()); buf.append(" ] ]");
    912     *
    913     * return buf.toString(); }
    914     */
    915
    916    /**
    917     * Tests to see if an option has been set.
    918     *
    919     * @param optionChar character name of the option.
    920     * @return true if set, false if not.
    921     */
    922    public boolean hasOption(final char optionChar) {
    923        return hasOption(String.valueOf(optionChar));
    924    }
    925
    926    /**
    927     * Tests to see if an option has been set.
    928     *
    929     * @param option the option to check.
    930     * @return true if set, false if not.
    931     * @since 1.5.0
    932     */
    933    public boolean hasOption(final Option option) {
    934        final boolean result = options.contains(option);
    935        if (result && option.isDeprecated()) {
    936            handleDeprecated(option);
    937        }
    938        return result;
    939    }
    940
    941    /**
    942     * Tests to see if an option has been set.
    943     *
    944     * @param optionGroup the option group to check.
    945     * @return true if set, false if not.
    946     * @since 1.9.0
    947     */
    948    public boolean hasOption(final OptionGroup optionGroup) {
    949        if (optionGroup == null || !optionGroup.isSelected()) {
    950            return false;
    951        }
    952        return hasOption(optionGroup.getSelected());
    953    }
    954
    955    /**
    956     * Tests to see if an option has been set.
    957     *
    958     * @param optionName Short name of the option.
    959     * @return true if set, false if not.
    960     */
    961    public boolean hasOption(final String optionName) {
    962        return hasOption(resolveOption(optionName));
    963    }
    964
    965    /**
    966     * Returns an iterator over the Option members of CommandLine.
    967     *
    968     * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
    969     */
    970    public Iterator<Option> iterator() {
    971        return options.iterator();
    972    }
    973
    974    /**
    975     * Parses a list of values as properties.  All odd numbered values are property keys
    976     * and even numbered values are property values.  If there are an odd number of values
    977     * the last value is assumed to be a boolean with a value of "true".
    978     * @param props the properties to update.
    979     * @param values the list of values to parse.
    980     */
    981    private void processPropertiesFromValues(final Properties props, final List<String> values) {
    982        for (int i = 0; i < values.size(); i += 2) {
    983            if (i + 1 < values.size()) {
    984                props.put(values.get(i), values.get(i + 1));
    985            } else {
    986                props.put(values.get(i), "true");
    987            }
    988        }
    989    }
    990
    991    /**
    992     * Retrieves the option object given the long or short option as a String
    993     *
    994     * @param optionName short or long name of the option, may be null.
    995     * @return Canonicalized option.
    996     */
    997    private Option resolveOption(final String optionName) {
    998        final String actual = Util.stripLeadingHyphens(optionName);
    999        if (actual != null) {
    1000            for (final Option option : options) {
    1001                if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) {
    1002                    return option;
    1003                }
    1004            }
    1005        }
    1006        return null;
    1007    }
    1008}