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