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