    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 static org.apache.commons.cli.Util.EMPTY_STRING_ARRAY;
    021
    022import java.io.Serializable;
    023import java.util.ArrayList;
    024import java.util.List;
    025import java.util.Objects;
    026import java.util.function.Supplier;
    027
    028/**
    029 * Describes a single command-line option. It maintains information regarding the short-name of the option, the long-name, if any exists, a flag indicating if
    030 * an argument is required for this option, and a self-documenting description of the option.
    031 * <p>
    032 * An Option is not created independently, but is created through an instance of {@link Options}. An Option is required to have at least a short or a long-name.
    033 * </p>
    034 * <p>
    035 * <strong>Note:</strong> once an {@link Option} has been added to an instance of {@link Options}, its required flag cannot be changed.
    036 * </p>
    037 *
    038 * @see org.apache.commons.cli.Options
    039 * @see org.apache.commons.cli.CommandLine
    040 */
    041public class Option implements Cloneable, Serializable {
    042
    043    /**
    044     * Builds {@code Option} instances using descriptive methods.
    045     * <p>
    046     * Example usage:
    047     * </p>
    048     *
    049     * <pre>
    050     * Option option = Option.builder("a").required(true).longOpt("arg-name").build();
    051     * </pre>
    052     *
    053     * @since 1.3
    054     */
    055    public static final class Builder implements Supplier<Option> {
    056
    057        /** The default type. */
    058        private static final Class<String> DEFAULT_TYPE = String.class;
    059
    060        /**
    061         * Returns the input Class or the default type (String) if null.
    062         *
    063         * @param type the candidate Class.
    064         * @return the input Class or the default type (String) if null.
    065         */
    066        private static Class<?> toType(final Class<?> type) {
    067            return type != null ? type : DEFAULT_TYPE;
    068        }
    069
    070        /** The number of argument values this option can have. */
    071        private int argCount = UNINITIALIZED;
    072
    073        /** The name of the argument for this option. */
    074        private String argName;
    075
    076        /** The converter to convert to type. **/
    077        private Converter<?, ?> converter;
    078
    079        /** Specifies whether this option is deprecated. */
    080        private DeprecatedAttributes deprecated;
    081
    082        /** Description of the option. */
    083        private String description;
    084
    085        /** The long representation of the option. */
    086        private String longOption;
    087
    088        /** The name of the option. */
    089        private String option;
    090
    091        /** Specifies whether the argument value of this Option is optional. */
    092        private boolean optionalArg;
    093
    094        /** Specifies whether this option is required to be present. */
    095        private boolean required;
    096
    097        /** Specifies the version when this option was added.  May be null */
    098        private String since;
    099
    100        /** The type of this Option. */
    101        private Class<?> type = DEFAULT_TYPE;
    102
    103        /** The character that is the value separator. */
    104        private char valueSeparator;
    105
    106        /**
    107         * Constructs a new {@code Builder} with the minimum required parameters for an {@code Option} instance.
    108         *
    109         * @param option short representation of the option.
    110         * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    111         */
    112        private Builder(final String option) throws IllegalArgumentException {
    113            option(option);
    114        }
    115
    116        /**
    117         * Sets the display name for the argument value.
    118         *
    119         * @param argName the display name for the argument value.
    120         * @return {@code this} instance..
    121         */
    122        public Builder argName(final String argName) {
    123            this.argName = argName;
    124            return this;
    125        }
    126
    127        /**
    128         * Constructs an Option with the values declared by this {@link Builder}.
    129         *
    130         * @return the new {@link Option}.
    131         * @throws IllegalArgumentException if neither {@code opt} or {@code longOpt} has been set.
    132         * @deprecated Use {@link #get()}.
    133         */
    134        @Deprecated
    135        public Option build() {
    136            return get();
    137        }
    138
    139        /**
    140         * Sets the converter for the option.
    141         * <p>
    142         * Note: See {@link TypeHandler} for serialization discussion.
    143         * </p>
    144         *
    145         * @param converter the Converter to use.
    146         * @return {@code this} instance..
    147         * @since 1.7.0
    148         */
    149        public Builder converter(final Converter<?, ?> converter) {
    150            this.converter = converter;
    151            return this;
    152        }
    153
    154        /**
    155         * Marks this Option as deprecated.
    156         *
    157         * @return this builder.
    158         * @since 1.7.0
    159         */
    160        public Builder deprecated() {
    161            return deprecated(DeprecatedAttributes.DEFAULT);
    162        }
    163
    164        /**
    165         * Sets whether the Option is deprecated.
    166         *
    167         * @param deprecated specifies whether the Option is deprecated.
    168         * @return this builder.
    169         * @since 1.7.0
    170         */
    171        public Builder deprecated(final DeprecatedAttributes deprecated) {
    172            this.deprecated = deprecated;
    173            return this;
    174        }
    175
    176        /**
    177         * Sets the description for this option.
    178         *
    179         * @param description the description of the option.
    180         * @return {@code this} instance..
    181         */
    182        public Builder desc(final String description) {
    183            this.description = description;
    184            return this;
    185        }
    186
    187        /**
    188         * Constructs an Option with the values declared by this {@link Builder}.
    189         *
    190         * @return the new {@link Option}.
    191         * @throws IllegalStateException if neither {@code opt} or {@code longOpt} has been set.
    192         */
    193        @Override
    194        public Option get() {
    195            return new Option(this);
    196        }
    197
    198        /**
    199         * Tests whether the Option will require an argument.
    200         *
    201         * @return {@code this} instance..
    202         */
    203        public Builder hasArg() {
    204            return hasArg(true);
    205        }
    206
    207        /**
    208         * Tests whether the Option has an argument or not.
    209         *
    210         * @param hasArg specifies whether the Option takes an argument or not.
    211         * @return {@code this} instance..
    212         */
    213        public Builder hasArg(final boolean hasArg) {
    214            // set to UNINITIALIZED when no arg is specified to be compatible with OptionBuilder
    215            argCount = hasArg ? 1 : UNINITIALIZED;
    216            return this;
    217        }
    218
    219        /**
    220         * Tests whether the Option can have unlimited argument values.
    221         *
    222         * @return this builder.
    223         */
    224        public Builder hasArgs() {
    225            argCount = UNLIMITED_VALUES;
    226            return this;
    227        }
    228
    229        /**
    230         * Sets the long name of the Option.
    231         *
    232         * @param longOption the long name of the Option
    233         * @return this builder.
    234         */
    235        public Builder longOpt(final String longOption) {
    236            this.longOption = longOption;
    237            return this;
    238        }
    239
    240        /**
    241         * Sets the number of argument values the Option can take.
    242         *
    243         * @param argCount the number of argument values
    244         * @return this builder.
    245         */
    246        public Builder numberOfArgs(final int argCount) {
    247            this.argCount = argCount;
    248            return this;
    249        }
    250
    251        /**
    252         * Sets the name of the Option.
    253         *
    254         * @param option the name of the Option.
    255         * @return this builder.
    256         * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    257         * @since 1.5.0
    258         */
    259        public Builder option(final String option) throws IllegalArgumentException {
    260            this.option = OptionValidator.validate(option);
    261            return this;
    262        }
    263
    264        /**
    265         * Sets whether the Option can have an optional argument.
    266         *
    267         * @param optionalArg specifies whether the Option can have an optional argument.
    268         * @return this builder.
    269         */
    270        public Builder optionalArg(final boolean optionalArg) {
    271            if (optionalArg && argCount == UNINITIALIZED) {
    272                argCount = 1;
    273            }
    274            this.optionalArg = optionalArg;
    275            return this;
    276        }
    277
    278        /**
    279         * Marks this Option as required.
    280         *
    281         * @return this builder.
    282         */
    283        public Builder required() {
    284            return required(true);
    285        }
    286
    287        /**
    288         * Sets whether the Option is required.
    289         *
    290         * @param required specifies whether the Option is required.
    291         * @return this builder.
    292         */
    293        public Builder required(final boolean required) {
    294            this.required = required;
    295            return this;
    296        }
    297
    298        /** Sets the version number when this option was first defined."
    299         *
    300         * @param since the version number when this option was first defined.
    301         * @return this builder.
    302         */
    303        public Builder since(final String since) {
    304            this.since = since;
    305            return this;
    306        }
    307
    308        /**
    309         * Sets the type of the Option.
    310         *
    311         * @param type the type of the Option.
    312         * @return this builder.
    313         */
    314        public Builder type(final Class<?> type) {
    315            this.type = toType(type);
    316            return this;
    317        }
    318
    319        /**
    320         * The Option will use '=' as a means to separate argument value.
    321         *
    322         * @return this builder.
    323         */
    324        public Builder valueSeparator() {
    325            return valueSeparator(Char.EQUAL);
    326        }
    327
    328        /**
    329         * The Option will use {@code sep} as a means to separate argument values.
    330         * <p>
    331         * <strong>Example:</strong>
    332         * </p>
    333         *
    334         * <pre>
    335         * Option opt = Option.builder("D").hasArgs().valueSeparator('=').build();
    336         * Options options = new Options();
    337         * options.addOption(opt);
    338         * String[] args = { "-Dkey=value" };
    339         * CommandLineParser parser = new DefaultParser();
    340         * CommandLine line = parser.parse(options, args);
    341         * String propertyName = line.getOptionValues("D")[0]; // will be "key"
    342         * String propertyValue = line.getOptionValues("D")[1]; // will be "value"
    343         * </pre>
    344         *
    345         * @param valueSeparator The value separator.
    346         * @return this builder.
    347         */
    348        public Builder valueSeparator(final char valueSeparator) {
    349            this.valueSeparator = valueSeparator;
    350            return this;
    351        }
    352
    353    }
    354
    355    /** Empty array. */
    356    static final Option[] EMPTY_ARRAY = {};
    357
    358    /** The serial version UID. */
    359    private static final long serialVersionUID = 1L;
    360
    361    /** Specifies the number of argument values has not been specified. */
    362    public static final int UNINITIALIZED = -1;
    363
    364    /** Specifies the number of argument values is infinite. */
    365    public static final int UNLIMITED_VALUES = -2;
    366
    367    /**
    368     * Returns a {@link Builder} to create an {@link Option} using descriptive methods.
    369     *
    370     * @return a new {@link Builder} instance.
    371     * @since 1.3
    372     */
    373    public static Builder builder() {
    374        return builder(null);
    375    }
    376
    377    /**
    378     * Returns a {@link Builder} to create an {@link Option} using descriptive methods.
    379     *
    380     * @param option short representation of the option.
    381     * @return a new {@link Builder} instance.
    382     * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    383     * @since 1.3
    384     */
    385    public static Builder builder(final String option) {
    386        return new Builder(option);
    387    }
    388
    389    /** The number of argument values this option can have. */
    390    private int argCount = UNINITIALIZED;
    391
    392    /** The name of the argument for this option. */
    393    private String argName;
    394
    395    /** The explicit converter for this option. May be null. */
    396    private transient Converter<?, ?> converter;
    397
    398    /**
    399     * Specifies whether this option is deprecated, may be null.
    400     * <p>
    401     * If you want to serialize this field, use a serialization proxy.
    402     * </p>
    403     */
    404    private final transient DeprecatedAttributes deprecated;
    405
    406    /** Description of the option. */
    407    private String description;
    408
    409    /** The long representation of the option. */
    410    private String longOption;
    411
    412    /** The name of the option. */
    413    private final String option;
    414
    415    /** Specifies whether the argument value of this Option is optional. */
    416    private boolean optionalArg;
    417
    418    /** Specifies whether this option is required to be present. */
    419    private boolean required;
    420
    421    /** Specifies the version when this option was added.  May be null */
    422    private String since;
    423
    424    /** The type of this Option. */
    425    private Class<?> type = String.class;
    426
    427    /** The list of argument values. **/
    428    private List<String> values = new ArrayList<>();
    429
    430    /** The character that is the value separator. */
    431    private char valueSeparator;
    432
    433    /**
    434     * Private constructor used by the nested Builder class.
    435     *
    436     * @param builder builder used to create this option.
    437     * @throws IllegalStateException if neither {@code opt} or {@code longOpt} has been set.
    438     */
    439    private Option(final Builder builder) {
    440        if (builder.option == null && builder.longOption == null) {
    441            throw new IllegalStateException("Either opt or longOpt must be specified");
    442        }
    443        this.argName = builder.argName;
    444        this.description = builder.description;
    445        this.longOption = builder.longOption;
    446        this.argCount = builder.argCount;
    447        this.option = builder.option;
    448        this.optionalArg = builder.optionalArg;
    449        this.deprecated = builder.deprecated;
    450        this.required = builder.required;
    451        this.since = builder.since;
    452        this.type = builder.type;
    453        this.valueSeparator = builder.valueSeparator;
    454        this.converter = builder.converter;
    455    }
    456
    457    /**
    458     * Creates an Option using the specified parameters.
    459     *
    460     * @param option      short representation of the option.
    461     * @param hasArg      specifies whether the Option takes an argument or not.
    462     * @param description describes the function of the option.
    463     * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    464     */
    465    public Option(final String option, final boolean hasArg, final String description) throws IllegalArgumentException {
    466        this(option, null, hasArg, description);
    467    }
    468
    469    /**
    470     * Creates an Option using the specified parameters. The option does not take an argument.
    471     *
    472     * @param option      short representation of the option.
    473     * @param description describes the function of the option.
    474     * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    475     */
    476    public Option(final String option, final String description) throws IllegalArgumentException {
    477        this(option, null, false, description);
    478    }
    479
    480    /**
    481     * Creates an Option using the specified parameters.
    482     *
    483     * @param option      short representation of the option.
    484     * @param longOption  the long representation of the option.
    485     * @param hasArg      specifies whether the Option takes an argument or not.
    486     * @param description describes the function of the option.
    487     * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
    488     */
    489    public Option(final String option, final String longOption, final boolean hasArg, final String description) throws IllegalArgumentException {
    490        // ensure that the option is valid
    491        this.deprecated = null;
    492        this.option = OptionValidator.validate(option);
    493        this.longOption = longOption;
    494        // if hasArg is set then the number of arguments is 1
    495        if (hasArg) {
    496            this.argCount = 1;
    497        }
    498        this.description = description;
    499    }
    500
    501    /**
    502     * Tests whether the option can accept more arguments.
    503     *
    504     * @return false if the maximum number of arguments is reached.
    505     * @since 1.3
    506     */
    507    boolean acceptsArg() {
    508        return (hasArg() || hasArgs() || hasOptionalArg()) && (argCount <= 0 || values.size() < argCount);
    509    }
    510
    511    /**
    512     * Adds the value to this Option. If the number of arguments is greater than zero and there is enough space in the list then add the value. Otherwise, throw
    513     * a runtime exception.
    514     *
    515     * @param value The value to be added to this Option.
    516     */
    517    private void add(final String value) {
    518        if (!acceptsArg()) {
    519            throw new IllegalArgumentException("Cannot add value, list full.");
    520        }
    521        // store value
    522        values.add(value);
    523    }
    524
    525    /**
    526     * This method is not intended to be used. It was a piece of internal API that was made public in 1.0. It currently throws an UnsupportedOperationException.
    527     *
    528     * @param value the value to add.
    529     * @return always throws an {@link UnsupportedOperationException}.
    530     * @throws UnsupportedOperationException always.
    531     * @deprecated Unused.
    532     */
    533    @Deprecated
    534    public boolean addValue(final String value) {
    535        throw new UnsupportedOperationException("The addValue method is not intended for client use. Subclasses should use the processValue method instead.");
    536    }
    537
    538    /**
    539     * Clears the Option values. After a parse is complete, these are left with data in them and they need clearing if another parse is done.
    540     *
    541     * See: <a href="https://issues.apache.org/jira/browse/CLI-71">CLI-71</a>
    542     */
    543    void clearValues() {
    544        values.clear();
    545    }
    546
    547    /**
    548     * A rather odd clone method - due to incorrect code in 1.0 it is public and in 1.1 rather than throwing a CloneNotSupportedException it throws a
    549     * RuntimeException so as to maintain backwards compatible at the API level.
    550     *
    551     * After calling this method, it is very likely you will want to call clearValues().
    552     *
    553     * @return a clone of this Option instance.
    554     * @throws RuntimeException if a {@link CloneNotSupportedException} has been thrown by {@code super.clone()}.
    555     */
    556    @Override
    557    public Object clone() {
    558        try {
    559            final Option option = (Option) super.clone();
    560            option.values = new ArrayList<>(values);
    561            return option;
    562        } catch (final CloneNotSupportedException e) {
    563            throw new UnsupportedOperationException(e.getMessage(), e);
    564        }
    565    }
    566
    567    @Override
    568    public boolean equals(final Object obj) {
    569        if (this == obj) {
    570            return true;
    571        }
    572        if (!(obj instanceof Option)) {
    573            return false;
    574        }
    575        final Option other = (Option) obj;
    576        return Objects.equals(longOption, other.longOption) && Objects.equals(option, other.option);
    577    }
    578
    579    /**
    580     * Gets the display name for the argument value.
    581     *
    582     * @return the display name for the argument value.
    583     */
    584    public String getArgName() {
    585        return argName;
    586    }
    587
    588    /**
    589     * Gets the number of argument values this Option can take.
    590     *
    591     * <p>
    592     * A value equal to the constant {@link #UNINITIALIZED} (= -1) indicates the number of arguments has not been specified. A value equal to the constant
    593     * {@link #UNLIMITED_VALUES} (= -2) indicates that this options takes an unlimited amount of values.
    594     * </p>
    595     *
    596     * @return num the number of argument values.
    597     * @see #UNINITIALIZED
    598     * @see #UNLIMITED_VALUES
    599     */
    600    public int getArgs() {
    601        return argCount;
    602    }
    603
    604    /**
    605     * Gets the value to type converter.
    606     *
    607     * @return the value to type converter.
    608     * @since 1.7.0
    609     */
    610    public Converter<?, ?> getConverter() {
    611        return converter == null ? TypeHandler.getDefault().getConverter(type) : converter;
    612    }
    613
    614    /**
    615     * Gets deprecated attributes if any.
    616     *
    617     * @return boolean deprecated attributes or null.
    618     * @since 1.7.0
    619     */
    620    public DeprecatedAttributes getDeprecated() {
    621        return deprecated;
    622    }
    623
    624    /**
    625     * Gets the self-documenting description of this Option.
    626     *
    627     * @return The string description of this option.
    628     */
    629    public String getDescription() {
    630        return description;
    631    }
    632
    633    /**
    634     * Gets the id of this Option. This is only set when the Option shortOpt is a single character. This is used for switch statements.
    635     *
    636     * @return the id of this Option.
    637     */
    638    public int getId() {
    639        return getKey().charAt(0);
    640    }
    641
    642    /**
    643     * Gets the 'unique' Option identifier. This is the option value if set or the long value if the options value is not set.
    644     *
    645     * @return the 'unique' Option identifier.
    646     * @since 1.7.0
    647     */
    648    public String getKey() {
    649        // if 'opt' is null, then it is a 'long' option
    650        return option == null ? longOption : option;
    651    }
    652
    653    /**
    654     * Gets the long name of this Option.
    655     *
    656     * @return Long name of this option, or null, if there is no long name.
    657     */
    658    public String getLongOpt() {
    659        return longOption;
    660    }
    661
    662    /**
    663     * Gets the name of this Option.
    664     *
    665     * It is this String which can be used with {@link CommandLine#hasOption(String opt)} and {@link CommandLine#getOptionValue(String opt)} to check for
    666     * existence and argument.
    667     *
    668     * @return The name of this option.
    669     */
    670    public String getOpt() {
    671        return option;
    672    }
    673
    674    /**
    675     * Gets the version when this option was added.
    676     * @return the version when this option was added, or {@code null} if not set.
    677     */
    678    public String getSince() {
    679        return since;
    680    }
    681
    682    /**
    683     * Gets the type of this Option.
    684     *
    685     * @return The type of this option.
    686     */
    687    public Object getType() {
    688        return type;
    689    }
    690
    691    /**
    692     * Gets the specified value of this Option or {@code null} if there is no value.
    693     *
    694     * @return the value/first value of this Option or {@code null} if there is no value.
    695     */
    696    public String getValue() {
    697        return hasNoValues() ? null : values.get(0);
    698    }
    699
    700    /**
    701     * Gets the specified value of this Option or {@code null} if there is no value.
    702     *
    703     * @param index The index of the value to be returned.
    704     * @return the specified value of this Option or {@code null} if there is no value.
    705     * @throws IndexOutOfBoundsException if index is less than 1 or greater than the number of the values for this Option.
    706     */
    707    public String getValue(final int index) throws IndexOutOfBoundsException {
    708        return hasNoValues() ? null : values.get(index);
    709    }
    710
    711    /**
    712     * Gets the value/first value of this Option or the {@code defaultValue} if there is no value.
    713     *
    714     * @param defaultValue The value to be returned if there is no value.
    715     * @return the value/first value of this Option or the {@code defaultValue} if there are no values.
    716     */
    717    public String getValue(final String defaultValue) {
    718        final String value = getValue();
    719        return value != null ? value : defaultValue;
    720    }
    721
    722    /**
    723     * Gets the values of this Option as a String array or an empty array if there are no values.
    724     *
    725     * @return the values of this Option as a String array or an empty array if there are no values.
    726     */
    727    public String[] getValues() {
    728        return hasNoValues() ? null : values.toArray(EMPTY_STRING_ARRAY);
    729    }
    730
    731    /**
    732     * Gets the value separator character.
    733     *
    734     * @return the value separator character.
    735     */
    736    public char getValueSeparator() {
    737        return valueSeparator;
    738    }
    739
    740    /**
    741     * Gets the values of this Option as a List.  Will return an empty list if there are no values.
    742     *
    743     * @return the values of this Option as a List or an empty List if there are no values.
    744     */
    745    public List<String> getValuesList() {
    746        return values;
    747    }
    748
    749    /**
    750     * Tests whether this Option requires an argument.
    751     *
    752     * @return boolean flag indicating if an argument is required.
    753     */
    754    public boolean hasArg() {
    755        return argCount > 0 || argCount == UNLIMITED_VALUES;
    756    }
    757
    758    /**
    759     * Tests whether the display name for the argument value has been set.
    760     *
    761     * @return if the display name for the argument value has been set.
    762     */
    763    public boolean hasArgName() {
    764        return argName != null && !argName.isEmpty();
    765    }
    766
    767    /**
    768     * Tests whether this Option can take many values.
    769     *
    770     * @return boolean flag indicating if multiple values are allowed.
    771     */
    772    public boolean hasArgs() {
    773        return argCount > 1 || argCount == UNLIMITED_VALUES;
    774    }
    775
    776    @Override
    777    public int hashCode() {
    778        return Objects.hash(longOption, option);
    779    }
    780
    781    /**
    782     * Tests whether this Option has a long name.
    783     *
    784     * @return boolean flag indicating existence of a long name.
    785     */
    786    public boolean hasLongOpt() {
    787        return longOption != null;
    788    }
    789
    790    /**
    791     * Tests whether this Option has any values.
    792     *
    793     * @return whether this Option has any values.
    794     */
    795    private boolean hasNoValues() {
    796        return values.isEmpty();
    797    }
    798
    799    /**
    800     * Tests whether this Option can have an optional argument.
    801     *
    802     * @return whether this Option can have an optional argument.
    803     */
    804    public boolean hasOptionalArg() {
    805        return optionalArg;
    806    }
    807
    808    /**
    809     * Tests whether this Option has specified a value separator.
    810     *
    811     * @return whether this Option has specified a value separator.
    812     * @since 1.1
    813     */
    814    public boolean hasValueSeparator() {
    815        return valueSeparator > 0;
    816    }
    817
    818    /**
    819     * Tests whether this Option is deprecated.
    820     *
    821     * @return boolean flag indicating whether this Option is deprecated.
    822     * @since 1.7.0
    823     */
    824    public boolean isDeprecated() {
    825        return deprecated != null;
    826    }
    827
    828    /**
    829     * Tests whether this Option is required.
    830     *
    831     * @return boolean flag indicating whether this Option is required.
    832     */
    833    public boolean isRequired() {
    834        return required;
    835    }
    836
    837    /**
    838     * Processes the value. If this Option has a value separator the value will have to be parsed into individual tokens. When n-1 tokens have been processed
    839     * and there are more value separators in the value, parsing is ceased and the remaining characters are added as a single token.
    840     *
    841     * @param value The String to be processed.
    842     */
    843    void processValue(final String value) {
    844        if (argCount == UNINITIALIZED) {
    845            throw new IllegalStateException("NO_ARGS_ALLOWED");
    846        }
    847        String add = Objects.requireNonNull(value, "value");
    848        // this Option has a separator character
    849        if (hasValueSeparator()) {
    850            // get the separator character
    851            final char sep = getValueSeparator();
    852            // store the index for the value separator
    853            int index = add.indexOf(sep);
    854            // while there are more value separators
    855            while (index != -1) {
    856                // next value to be added
    857                if (values.size() == argCount - 1) {
    858                    break;
    859                }
    860                // store
    861                add(add.substring(0, index));
    862                // parse
    863                add = add.substring(index + 1);
    864                // get new index
    865                index = add.indexOf(sep);
    866            }
    867        }
    868        // store the actual value or the last value that has been parsed
    869        add(add);
    870    }
    871
    872    /**
    873     * Tests whether the option requires more arguments to be valid.
    874     *
    875     * @return false if the option doesn't require more arguments.
    876     */
    877    boolean requiresArg() {
    878        if (optionalArg) {
    879            return false;
    880        }
    881        if (argCount == UNLIMITED_VALUES) {
    882            return values.isEmpty();
    883        }
    884        return acceptsArg();
    885    }
    886
    887    /**
    888     * Sets the display name for the argument value.
    889     *
    890     * @param argName the display name for the argument value.
    891     */
    892    public void setArgName(final String argName) {
    893        this.argName = argName;
    894    }
    895
    896    /**
    897     * Sets the number of argument values this Option can take.
    898     *
    899     * @param num the number of argument values.
    900     */
    901    public void setArgs(final int num) {
    902        this.argCount = num;
    903    }
    904
    905    /**
    906     * Sets the value to type converter.
    907     *
    908     * @param converter The converter to convert the string value to the type.
    909     * @since 1.7.0
    910     */
    911    public void setConverter(final Converter<?, ?> converter) {
    912        this.converter = converter;
    913    }
    914
    915    /**
    916     * Sets the self-documenting description of this Option.
    917     *
    918     * @param description The description of this option.
    919     * @since 1.1
    920     */
    921    public void setDescription(final String description) {
    922        this.description = description;
    923    }
    924
    925    /**
    926     * Sets the long name of this Option.
    927     *
    928     * @param longOpt the long name of this Option.
    929     */
    930    public void setLongOpt(final String longOpt) {
    931        this.longOption = longOpt;
    932    }
    933
    934    /**
    935     * Sets whether this Option can have an optional argument.
    936     *
    937     * @param optionalArg specifies whether the Option can have an optional argument.
    938     */
    939    public void setOptionalArg(final boolean optionalArg) {
    940        this.optionalArg = optionalArg;
    941    }
    942
    943    /**
    944     * Sets whether this Option is mandatory.
    945     *
    946     * @param required specifies whether this Option is mandatory.
    947     */
    948    public void setRequired(final boolean required) {
    949        this.required = required;
    950    }
    951
    952    /**
    953     * Sets the type of this Option.
    954     *
    955     * @param type the type of this Option.
    956     * @since 1.3
    957     */
    958    public void setType(final Class<?> type) {
    959        this.type = Builder.toType(type);
    960    }
    961
    962    /**
    963     * Sets the type of this Option.
    964     * <p>
    965     * <strong>Note:</strong> this method is kept for binary compatibility and the input type is supposed to be a {@link Class} object.
    966     * </p>
    967     *
    968     * @param type the type of this Option.
    969     * @deprecated since 1.3, use {@link #setType(Class)} instead.
    970     */
    971    @Deprecated
    972    public void setType(final Object type) {
    973        setType((Class<?>) type);
    974    }
    975
    976    /**
    977     * Sets the value separator. For example if the argument value was a Java property, the value separator would be '='.
    978     *
    979     * @param valueSeparator The value separator.
    980     */
    981    public void setValueSeparator(final char valueSeparator) {
    982        this.valueSeparator = valueSeparator;
    983    }
    984
    985    String toDeprecatedString() {
    986        if (!isDeprecated()) {
    987            return "";
    988        }
    989        // @formatter:off
    990        final StringBuilder buf = new StringBuilder()
    991                .append("Option '")
    992                .append(option)
    993                .append(Char.APOS);
    994        // @formatter:on
    995        if (longOption != null) {
    996            buf.append(Char.APOS).append(longOption).append(Char.APOS);
    997        }
    998        buf.append(": ").append(deprecated);
    999        return buf.toString();
    1000    }
    1001
    1002    /**
    1003     * Creates a String suitable for debugging.
    1004     *
    1005     * @return a String suitable for debugging.
    1006     */
    1007    @Override
    1008    public String toString() {
    1009        final StringBuilder buf = new StringBuilder().append("[ ");
    1010        buf.append("Option ");
    1011        buf.append(option);
    1012        if (longOption != null) {
    1013            buf.append(Char.SP).append(longOption);
    1014        }
    1015        if (isDeprecated()) {
    1016            buf.append(Char.SP);
    1017            buf.append(deprecated.toString());
    1018        }
    1019        if (hasArgs()) {
    1020            buf.append("[ARG...]");
    1021        } else if (hasArg()) {
    1022            buf.append(" [ARG]");
    1023        }
    1024        // @formatter:off
    1025        return buf.append(" :: ")
    1026            .append(description)
    1027            .append(" :: ")
    1028            .append(type)
    1029            .append(" ]")
    1030            .toString();
    1031        // @formatter:on
    1032    }
    1033}