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.Properties;
028
029/**
030 * Represents list of arguments parsed against a {@link Options} descriptor.
031 * <p>
032 * It allows querying of a boolean {@link #hasOption(String opt)}, in addition to retrieving the
033 * {@link #getOptionValue(String opt)} for options requiring arguments.
034 * <p>
035 * Additionally, any left-over or unrecognized arguments, are available for further processing.
036 */
037public class CommandLine implements Serializable {
038
039    /**
040     * A nested builder class to create {@code CommandLine} instance using descriptive methods.
041     *
042     * @since 1.4
043     */
044    public static final class Builder {
045
046        /**
047         * CommandLine that is being build by this Builder.
048         */
049        private final CommandLine commandLine = new CommandLine();
050
051        /**
052         * Adds left-over unrecognized option/argument.
053         *
054         * @param arg the unrecognized option/argument.
055         *
056         * @return this Builder instance for method chaining.
057         */
058        public Builder addArg(final String arg) {
059            commandLine.addArg(arg);
060            return this;
061        }
062
063        /**
064         * Adds an option to the command line. The values of the option are stored.
065         *
066         * @param opt the processed option.
067         *
068         * @return this Builder instance for method chaining.
069         */
070        public Builder addOption(final Option opt) {
071            commandLine.addOption(opt);
072            return this;
073        }
074
075        /**
076         * Returns the new instance.
077         *
078         * @return the new instance.
079         */
080        public CommandLine build() {
081            return commandLine;
082        }
083    }
084
085    /** The serial version UID. */
086    private static final long serialVersionUID = 1L;
087
088    /** The unrecognized options/arguments */
089    private final List<String> args = new LinkedList<>();
090
091    /** The processed options */
092    private final List<Option> options = new ArrayList<>();
093
094    /**
095     * Creates a command line.
096     */
097    protected CommandLine() {
098        // nothing to do
099    }
100
101    /**
102     * Adds left-over unrecognized option/argument.
103     *
104     * @param arg the unrecognized option/argument.
105     */
106    protected void addArg(final String arg) {
107        if (arg != null) {
108            args.add(arg);
109        }
110    }
111
112    /**
113     * Adds an option to the command line. The values of the option are stored.
114     *
115     * @param opt the processed option.
116     */
117    protected void addOption(final Option opt) {
118        if (opt != null) {
119            options.add(opt);
120        }
121    }
122
123    /**
124     * Gets any left-over non-recognized options and arguments
125     *
126     * @return remaining items passed in but not parsed as a {@code List}.
127     */
128    public List<String> getArgList() {
129        return args;
130    }
131
132    /**
133     * Gets any left-over non-recognized options and arguments
134     *
135     * @return remaining items passed in but not parsed as an array.
136     */
137    public String[] getArgs() {
138        return args.toArray(Util.EMPTY_STRING_ARRAY);
139    }
140
141    /**
142     * Gets the {@code Object} type of this {@code Option}.
143     *
144     * @deprecated due to System.err message. Instead use getParsedOptionValue(char)
145     * @param opt the name of the option.
146     * @return the type of opt.
147     */
148    @Deprecated
149    public Object getOptionObject(final char opt) {
150        return getOptionObject(String.valueOf(opt));
151    }
152
153    /**
154     * Gets the {@code Object} type of this {@code Option}.
155     *
156     * @param opt the name of the option.
157     * @return the type of this {@code Option}.
158     * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
159     */
160    @Deprecated
161    public Object getOptionObject(final String opt) {
162        try {
163            return getParsedOptionValue(opt);
164        } catch (final ParseException pe) {
165            System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage());
166            return null;
167        }
168    }
169
170    /**
171     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
172     * <code>-Dparam1=value1
173     * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
174     * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
175     *
176     * @param option name of the option.
177     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
178     * @since 1.5.0
179     */
180    public Properties getOptionProperties(final Option option) {
181        final Properties props = new Properties();
182
183        for (final Option processedOption : options) {
184            if (processedOption.equals(option)) {
185                final List<String> values = processedOption.getValuesList();
186                if (values.size() >= 2) {
187                    // use the first 2 arguments as the key/value pair
188                    props.put(values.get(0), values.get(1));
189                } else if (values.size() == 1) {
190                    // no explicit value, handle it as a boolean
191                    props.put(values.get(0), "true");
192                }
193            }
194        }
195
196        return props;
197    }
198
199    /**
200     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
201     * <code>-Dparam1=value1
202     * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
203     * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
204     *
205     * @param opt name of the option.
206     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
207     * @since 1.2
208     */
209    public Properties getOptionProperties(final String opt) {
210        final Properties props = new Properties();
211
212        for (final Option option : options) {
213            if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
214                final List<String> values = option.getValuesList();
215                if (values.size() >= 2) {
216                    // use the first 2 arguments as the key/value pair
217                    props.put(values.get(0), values.get(1));
218                } else if (values.size() == 1) {
219                    // no explicit value, handle it as a boolean
220                    props.put(values.get(0), "true");
221                }
222            }
223        }
224
225        return props;
226    }
227
228    /**
229     * Gets an array of the processed {@link Option}s.
230     *
231     * @return an array of the processed {@link Option}s.
232     */
233    public Option[] getOptions() {
234        return options.toArray(Option.EMPTY_ARRAY);
235    }
236
237    /**
238     * Gets the first argument, if any, of this option.
239     *
240     * @param opt the character name of the option.
241     * @return Value of the argument if option is set, and has an argument, otherwise null.
242     */
243    public String getOptionValue(final char opt) {
244        return getOptionValue(String.valueOf(opt));
245    }
246
247    /**
248     * Gets the argument, if any, of an option.
249     *
250     * @param opt character name of the option
251     * @param defaultValue is the default value to be returned if the option is not specified.
252     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
253     */
254    public String getOptionValue(final char opt, final String defaultValue) {
255        return getOptionValue(String.valueOf(opt), defaultValue);
256    }
257
258    /**
259     * Gets the first argument, if any, of this option.
260     *
261     * @param option the name of the option.
262     * @return Value of the argument if option is set, and has an argument, otherwise null.
263     * @since 1.5.0
264     */
265    public String getOptionValue(final Option option) {
266        if (option == null) {
267            return null;
268        }
269        final String[] values = getOptionValues(option);
270        return values == null ? null : values[0];
271    }
272
273    /**
274     * Gets the first argument, if any, of an option.
275     *
276     * @param option name of the option.
277     * @param defaultValue is the default value to be returned if the option is not specified.
278     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
279     * @since 1.5.0
280     */
281    public String getOptionValue(final Option option, final String defaultValue) {
282        final String answer = getOptionValue(option);
283        return answer != null ? answer : defaultValue;
284    }
285
286    /**
287     * Gets the first argument, if any, of this option.
288     *
289     * @param opt the name of the option.
290     * @return Value of the argument if option is set, and has an argument, otherwise null.
291     */
292    public String getOptionValue(final String opt) {
293        return getOptionValue(resolveOption(opt));
294    }
295
296    /**
297     * Gets the first argument, if any, of an option.
298     *
299     * @param opt name of the option.
300     * @param defaultValue is the default value to be returned if the option is not specified.
301     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
302     */
303    public String getOptionValue(final String opt, final String defaultValue) {
304        return getOptionValue(resolveOption(opt), defaultValue);
305    }
306
307    /**
308     * Gets the array of values, if any, of an option.
309     *
310     * @param opt character name of the option.
311     * @return Values of the argument if option is set, and has an argument, otherwise null.
312     */
313    public String[] getOptionValues(final char opt) {
314        return getOptionValues(String.valueOf(opt));
315    }
316
317    /**
318     * Gets the array of values, if any, of an option.
319     *
320     * @param option string name of the option.
321     * @return Values of the argument if option is set, and has an argument, otherwise null.
322     * @since 1.5.0
323     */
324    public String[] getOptionValues(final Option option) {
325        final List<String> values = new ArrayList<>();
326
327        for (final Option processedOption : options) {
328            if (processedOption.equals(option)) {
329                values.addAll(processedOption.getValuesList());
330            }
331        }
332
333        return values.isEmpty() ? null : values.toArray(EMPTY_STRING_ARRAY);
334    }
335
336    /**
337     * Gets the array of values, if any, of an option.
338     *
339     * @param opt string name of the option.
340     * @return Values of the argument if option is set, and has an argument, otherwise null.
341     */
342    public String[] getOptionValues(final String opt) {
343        return getOptionValues(resolveOption(opt));
344    }
345
346    /**
347     * Gets a version of this {@code Option} converted to a particular type.
348     *
349     * @param opt the name of the option.
350     * @return the value parsed into a particular object.
351     * @throws ParseException if there are problems turning the option value into the desired type
352     * @see PatternOptionBuilder
353     * @since 1.5.0
354     */
355    public Object getParsedOptionValue(final char opt) throws ParseException {
356        return getParsedOptionValue(String.valueOf(opt));
357    }
358
359    /**
360     * Gets a version of this {@code Option} converted to a particular type.
361     *
362     * @param option the name of the option.
363     * @return the value parsed into a particular object.
364     * @throws ParseException if there are problems turning the option value into the desired type
365     * @see PatternOptionBuilder
366     * @since 1.5.0
367     */
368    public Object getParsedOptionValue(final Option option) throws ParseException {
369        if (option == null) {
370            return null;
371        }
372        final String res = getOptionValue(option);
373        if (res == null) {
374            return null;
375        }
376        return TypeHandler.createValue(res, option.getType());
377    }
378
379    /**
380     * Gets a version of this {@code Option} converted to a particular type.
381     *
382     * @param opt the name of the option.
383     * @return the value parsed into a particular object.
384     * @throws ParseException if there are problems turning the option value into the desired type
385     * @see PatternOptionBuilder
386     * @since 1.2
387     */
388    public Object getParsedOptionValue(final String opt) throws ParseException {
389        return getParsedOptionValue(resolveOption(opt));
390    }
391
392    /**
393     * jkeyes - commented out until it is implemented properly
394     * <p>
395     * Dump state, suitable for debugging.
396     * </p>
397     *
398     * @return Stringified form of this object.
399     */
400
401    /*
402     * public String toString() { StringBuilder buf = new StringBuilder();
403     *
404     * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
405     * buf.append(args.toString()); buf.append(" ] ]");
406     *
407     * return buf.toString(); }
408     */
409
410    /**
411     * Tests to see if an option has been set.
412     *
413     * @param opt character name of the option.
414     * @return true if set, false if not.
415     */
416    public boolean hasOption(final char opt) {
417        return hasOption(String.valueOf(opt));
418    }
419
420    /**
421     * Tests to see if an option has been set.
422     *
423     * @param opt the option to check.
424     * @return true if set, false if not.
425     * @since 1.5.0
426     */
427    public boolean hasOption(final Option opt) {
428        return options.contains(opt);
429    }
430
431    /**
432     * Tests to see if an option has been set.
433     *
434     * @param opt Short name of the option.
435     * @return true if set, false if not.
436     */
437    public boolean hasOption(final String opt) {
438        return hasOption(resolveOption(opt));
439    }
440
441    /**
442     * Returns an iterator over the Option members of CommandLine.
443     *
444     * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
445     */
446    public Iterator<Option> iterator() {
447        return options.iterator();
448    }
449
450    /**
451     * Retrieves the option object given the long or short option as a String
452     *
453     * @param opt short or long name of the option, may be null.
454     * @return Canonicalized option.
455     */
456    private Option resolveOption(final String opt) {
457        final String actual = Util.stripLeadingHyphens(opt);
458        if (actual != null) {
459            for (final Option option : options) {
460                if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) {
461                    return option;
462                }
463            }
464        }
465        return null;
466    }
467}