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