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