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