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 *
031 * <p>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.</p>
034 *
035 * <p>Additionally, any left-over or unrecognized arguments,
036 * are available for further processing.</p>
037 *
038 * @author bob mcwhirter (bob @ werken.com)
039 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
040 * @author John Keyes (john at integralsource.com)
041 * @version $Revision: 735247 $, $Date: 2009-01-17 00:23:35 -0800 (Sat, 17 Jan 2009) $
042 */
043public class CommandLine implements Serializable
044{
045    private static final long serialVersionUID = 1L;
046
047    /** the unrecognised options/arguments */
048    private List args = new LinkedList();
049
050    /** the processed options */
051    private List options = new ArrayList();
052
053    /**
054     * Creates a command line.
055     */
056    CommandLine()
057    {
058        // nothing to do
059    }
060
061    /** 
062     * Query to see if an option has been set.
063     *
064     * @param opt Short name of the option
065     * @return true if set, false if not
066     */
067    public boolean hasOption(String opt)
068    {
069        return options.contains(resolveOption(opt));
070    }
071
072    /** 
073     * Query to see if an option has been set.
074     *
075     * @param opt character name of the option
076     * @return true if set, false if not
077     */
078    public boolean hasOption(char opt)
079    {
080        return hasOption(String.valueOf(opt));
081    }
082
083    /**
084     * Return the <code>Object</code> type of this <code>Option</code>.
085     *
086     * @param opt the name of the option
087     * @return the type of this <code>Option</code>
088     * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
089     */
090    public Object getOptionObject(String opt)
091    {
092        try {
093            return getParsedOptionValue(opt);
094        } catch(ParseException pe) {
095            System.err.println("Exception found converting " + opt + " to desired type: " + 
096                pe.getMessage() );
097            return null;
098        }
099    }
100
101    /**
102     * Return a version of this <code>Option</code> converted to a particular type. 
103     *
104     * @param opt the name of the option
105     * @return the value parsed into a particluar object
106     * @throws ParseException if there are problems turning the option value into the desired type
107     * @see PatternOptionBuilder
108     */
109    public Object getParsedOptionValue(String opt)
110    throws ParseException
111    {
112        String res = getOptionValue(opt);
113
114        Option option = resolveOption(opt);
115        if (option == null)
116        {
117            return null;
118        }
119
120        Object type = option.getType();
121
122        return (res == null)        ? null : TypeHandler.createValue(res, type);
123    }
124
125    /**
126     * Return the <code>Object</code> type of this <code>Option</code>.
127     *
128     * @param opt the name of the option
129     * @return the type of opt
130     */
131    public Object getOptionObject(char opt)
132    {
133        return getOptionObject(String.valueOf(opt));
134    }
135
136    /** 
137     * Retrieve the argument, if any, of this option.
138     *
139     * @param opt the name of the option
140     * @return Value of the argument if option is set, and has an argument,
141     * otherwise null.
142     */
143    public String getOptionValue(String opt)
144    {
145        String[] values = getOptionValues(opt);
146
147        return (values == null) ? null : values[0];
148    }
149
150    /** 
151     * Retrieve the argument, if any, of this option.
152     *
153     * @param opt the character name of the option
154     * @return Value of the argument if option is set, and has an argument,
155     * otherwise null.
156     */
157    public String getOptionValue(char opt)
158    {
159        return getOptionValue(String.valueOf(opt));
160    }
161
162    /** 
163     * Retrieves the array of values, if any, of an option.
164     *
165     * @param opt string name of the option
166     * @return Values of the argument if option is set, and has an argument,
167     * otherwise null.
168     */
169    public String[] getOptionValues(String opt)
170    {
171        List values = new ArrayList();
172
173        for (Iterator it = options.iterator(); it.hasNext();)
174        {
175            Option option = (Option) it.next();
176            if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt()))
177            {
178                values.addAll(option.getValuesList());
179            }
180        }
181
182        return values.isEmpty() ? null : (String[]) values.toArray(new String[values.size()]);
183    }
184
185    /**
186     * Retrieves the option object given the long or short option as a String
187     * 
188     * @param opt short or long name of the option
189     * @return Canonicalized option
190     */
191    private Option resolveOption(String opt)
192    {
193        opt = Util.stripLeadingHyphens(opt);
194        for (Iterator it = options.iterator(); it.hasNext();)
195        {
196            Option option = (Option) it.next();
197            if (opt.equals(option.getOpt()))
198            {
199                return option;
200            }
201
202            if (opt.equals(option.getLongOpt()))
203            {
204                return option;
205            }
206
207        }
208        return null;
209    }
210
211    /** 
212     * Retrieves the array of values, if any, of an option.
213     *
214     * @param opt character name of the option
215     * @return Values of the argument if option is set, and has an argument,
216     * otherwise null.
217     */
218    public String[] getOptionValues(char opt)
219    {
220        return getOptionValues(String.valueOf(opt));
221    }
222
223    /** 
224     * Retrieve the argument, if any, of an option.
225     *
226     * @param opt name of the option
227     * @param defaultValue is the default value to be returned if the option
228     * is not specified
229     * @return Value of the argument if option is set, and has an argument,
230     * otherwise <code>defaultValue</code>.
231     */
232    public String getOptionValue(String opt, String defaultValue)
233    {
234        String answer = getOptionValue(opt);
235
236        return (answer != null) ? answer : defaultValue;
237    }
238
239    /** 
240     * Retrieve the argument, if any, of an option.
241     *
242     * @param opt character name of the option
243     * @param defaultValue is the default value to be returned if the option
244     * is not specified
245     * @return Value of the argument if option is set, and has an argument,
246     * otherwise <code>defaultValue</code>.
247     */
248    public String getOptionValue(char opt, String defaultValue)
249    {
250        return getOptionValue(String.valueOf(opt), defaultValue);
251    }
252
253    /**
254     * Retrieve the map of values associated to the option. This is convenient
255     * for options specifying Java properties like <tt>-Dparam1=value1
256     * -Dparam2=value2</tt>. The first argument of the option is the key, and
257     * the 2nd argument is the value. If the option has only one argument
258     * (<tt>-Dfoo</tt>) it is considered as a boolean flag and the value is
259     * <tt>"true"</tt>.
260     *
261     * @param opt name of the option
262     * @return The Properties mapped by the option, never <tt>null</tt>
263     *         even if the option doesn't exists
264     * @since 1.2
265     */
266    public Properties getOptionProperties(String opt)
267    {
268        Properties props = new Properties();
269
270        for (Iterator it = options.iterator(); it.hasNext();)
271        {
272            Option option = (Option) it.next();
273
274            if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt()))
275            {
276                List values = option.getValuesList();
277                if (values.size() >= 2)
278                {
279                    // use the first 2 arguments as the key/value pair
280                    props.put(values.get(0), values.get(1));
281                }
282                else if (values.size() == 1)
283                {
284                    // no explicit value, handle it as a boolean
285                    props.put(values.get(0), "true");
286                }
287            }
288        }
289
290        return props;
291    }
292
293    /** 
294     * Retrieve any left-over non-recognized options and arguments
295     *
296     * @return remaining items passed in but not parsed as an array
297     */
298    public String[] getArgs()
299    {
300        String[] answer = new String[args.size()];
301
302        args.toArray(answer);
303
304        return answer;
305    }
306
307    /** 
308     * Retrieve any left-over non-recognized options and arguments
309     *
310     * @return remaining items passed in but not parsed as a <code>List</code>.
311     */
312    public List getArgList()
313    {
314        return args;
315    }
316
317    /** 
318     * jkeyes
319     * - commented out until it is implemented properly
320     * <p>Dump state, suitable for debugging.</p>
321     *
322     * @return Stringified form of this object
323     */
324
325    /*
326    public String toString() {
327        StringBuffer buf = new StringBuffer();
328            
329        buf.append("[ CommandLine: [ options: ");
330        buf.append(options.toString());
331        buf.append(" ] [ args: ");
332        buf.append(args.toString());
333        buf.append(" ] ]");
334            
335        return buf.toString();
336    }
337    */
338
339    /**
340     * Add left-over unrecognized option/argument.
341     *
342     * @param arg the unrecognised option/argument.
343     */
344    void addArg(String arg)
345    {
346        args.add(arg);
347    }
348
349    /**
350     * Add an option to the command line.  The values of the option are stored.
351     *
352     * @param opt the processed option
353     */
354    void addOption(Option opt)
355    {
356        options.add(opt);
357    }
358
359    /**
360     * Returns an iterator over the Option members of CommandLine.
361     *
362     * @return an <code>Iterator</code> over the processed {@link Option}
363     * members of this {@link CommandLine}
364     */
365    public Iterator iterator()
366    {
367        return options.iterator();
368    }
369
370    /**
371     * Returns an array of the processed {@link Option}s.
372     *
373     * @return an array of the processed {@link Option}s.
374     */
375    public Option[] getOptions()
376    {
377        Collection processed = options;
378
379        // reinitialise array
380        Option[] optionsArray = new Option[processed.size()];
381
382        // return the array
383        return (Option[]) processed.toArray(optionsArray);
384    }
385}