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