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