View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.cli;
19  
20  import java.io.Serializable;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  /**
30   * Main entry-point into the library.
31   * <p>
32   * Options represents a collection of {@link Option} objects, which
33   * describe the possible options for a command-line.
34   * <p>
35   * It may flexibly parse long and short options, with or without
36   * values.  Additionally, it may parse only a portion of a commandline,
37   * allowing for flexible multi-stage parsing.
38   *
39   * @see org.apache.commons.cli.CommandLine
40   *
41   * @version $Id: Options.java 1754332 2016-07-27 18:47:57Z britter $
42   */
43  public class Options implements Serializable
44  {
45      /** The serial version UID. */
46      private static final long serialVersionUID = 1L;
47  
48      /** a map of the options with the character key */
49      private final Map<String, Option> shortOpts = new LinkedHashMap<String, Option>();
50  
51      /** a map of the options with the long key */
52      private final Map<String, Option> longOpts = new LinkedHashMap<String, Option>();
53  
54      /** a map of the required options */
55      // N.B. This can contain either a String (addOption) or an OptionGroup (addOptionGroup)
56      // TODO this seems wrong
57      private final List<Object> requiredOpts = new ArrayList<Object>();
58  
59      /** a map of the option groups */
60      private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<String, OptionGroup>();
61  
62      /**
63       * Add the specified option group.
64       *
65       * @param group the OptionGroup that is to be added
66       * @return the resulting Options instance
67       */
68      public Options addOptionGroup(OptionGroup group)
69      {
70          if (group.isRequired())
71          {
72              requiredOpts.add(group);
73          }
74  
75          for (Option option : group.getOptions())
76          {
77              // an Option cannot be required if it is in an
78              // OptionGroup, either the group is required or
79              // nothing is required
80              option.setRequired(false);
81              addOption(option);
82  
83              optionGroups.put(option.getKey(), group);
84          }
85  
86          return this;
87      }
88  
89      /**
90       * Lists the OptionGroups that are members of this Options instance.
91       *
92       * @return a Collection of OptionGroup instances.
93       */
94      Collection<OptionGroup> getOptionGroups()
95      {
96          return new HashSet<OptionGroup>(optionGroups.values());
97      }
98  
99      /**
100      * Add an option that only contains a short name.
101      * 
102      * <p>
103      * The option does not take an argument.
104      * </p>
105      *
106      * @param opt Short single-character name of the option.
107      * @param description Self-documenting description
108      * @return the resulting Options instance
109      * @since 1.3
110      */
111     public Options addOption(String opt, String description)
112     {
113         addOption(opt, null, false, description);
114         return this;
115     }
116 
117     /**
118      * Add an option that only contains a short-name.
119      *
120      * <p>
121      * It may be specified as requiring an argument.
122      * </p>
123      *
124      * @param opt Short single-character name of the option.
125      * @param hasArg flag signally if an argument is required after this option
126      * @param description Self-documenting description
127      * @return the resulting Options instance
128      */
129     public Options addOption(String opt, boolean hasArg, String description)
130     {
131         addOption(opt, null, hasArg, description);
132         return this;
133     }
134 
135     /**
136      * Add an option that contains a short-name and a long-name.
137      *
138      * <p>
139      * It may be specified as requiring an argument.
140      * </p>
141      *
142      * @param opt Short single-character name of the option.
143      * @param longOpt Long multi-character name of the option.
144      * @param hasArg flag signally if an argument is required after this option
145      * @param description Self-documenting description
146      * @return the resulting Options instance
147      */
148     public Options addOption(String opt, String longOpt, boolean hasArg, String description)
149     {
150         addOption(new Option(opt, longOpt, hasArg, description));
151         return this;
152     }
153 
154     /**
155      * Add an option that contains a short-name and a long-name.
156      * 
157      * <p>
158      * The added option is set as required. It may be specified as requiring an argument. This method is a shortcut for:
159      * </p>
160      *
161      * <pre>
162      * <code>
163      * Options option = new Option(opt, longOpt, hasArg, description);
164      * option.setRequired(true);
165      * options.add(option);
166      * </code>
167      * </pre>
168      *
169      * @param opt Short single-character name of the option.
170      * @param longOpt Long multi-character name of the option.
171      * @param hasArg flag signally if an argument is required after this option
172      * @param description Self-documenting description
173      * @return the resulting Options instance
174      * @since 1.4
175      */
176     public Options addRequiredOption(String opt, String longOpt, boolean hasArg, String description)
177     {
178         Option option = new Option(opt, longOpt, hasArg, description);
179         option.setRequired(true);
180         addOption(option);
181         return this;
182     }
183 
184     /**
185      * Adds an option instance
186      *
187      * @param opt the option that is to be added
188      * @return the resulting Options instance
189      */
190     public Options addOption(Option opt)
191     {
192         String key = opt.getKey();
193 
194         // add it to the long option list
195         if (opt.hasLongOpt())
196         {
197             longOpts.put(opt.getLongOpt(), opt);
198         }
199 
200         // if the option is required add it to the required list
201         if (opt.isRequired())
202         {
203             if (requiredOpts.contains(key))
204             {
205                 requiredOpts.remove(requiredOpts.indexOf(key));
206             }
207             requiredOpts.add(key);
208         }
209 
210         shortOpts.put(key, opt);
211 
212         return this;
213     }
214 
215     /**
216      * Retrieve a read-only list of options in this set
217      *
218      * @return read-only Collection of {@link Option} objects in this descriptor
219      */
220     public Collection<Option> getOptions()
221     {
222         return Collections.unmodifiableCollection(helpOptions());
223     }
224 
225     /**
226      * Returns the Options for use by the HelpFormatter.
227      *
228      * @return the List of Options
229      */
230     List<Option> helpOptions()
231     {
232         return new ArrayList<Option>(shortOpts.values());
233     }
234 
235     /**
236      * Returns the required options.
237      *
238      * @return read-only List of required options
239      */
240     public List getRequiredOptions()
241     {
242         return Collections.unmodifiableList(requiredOpts);
243     }
244 
245     /**
246      * Retrieve the {@link Option} matching the long or short name specified.
247      *
248      * <p>
249      * The leading hyphens in the name are ignored (up to 2).
250      * </p>
251      *
252      * @param opt short or long name of the {@link Option}
253      * @return the option represented by opt
254      */
255     public Option getOption(String opt)
256     {
257         opt = Util.stripLeadingHyphens(opt);
258 
259         if (shortOpts.containsKey(opt))
260         {
261             return shortOpts.get(opt);
262         }
263 
264         return longOpts.get(opt);
265     }
266 
267     /**
268      * Returns the options with a long name starting with the name specified.
269      * 
270      * @param opt the partial name of the option
271      * @return the options matching the partial name specified, or an empty list if none matches
272      * @since 1.3
273      */
274     public List<String> getMatchingOptions(String opt)
275     {
276         opt = Util.stripLeadingHyphens(opt);
277         
278         List<String> matchingOpts = new ArrayList<String>();
279 
280         // for a perfect match return the single option only
281         if (longOpts.keySet().contains(opt))
282         {
283             return Collections.singletonList(opt);
284         }
285 
286         for (String longOpt : longOpts.keySet())
287         {
288             if (longOpt.startsWith(opt))
289             {
290                 matchingOpts.add(longOpt);
291             }
292         }
293         
294         return matchingOpts;
295     }
296 
297     /**
298      * Returns whether the named {@link Option} is a member of this {@link Options}.
299      *
300      * @param opt short or long name of the {@link Option}
301      * @return true if the named {@link Option} is a member of this {@link Options}
302      */
303     public boolean hasOption(String opt)
304     {
305         opt = Util.stripLeadingHyphens(opt);
306 
307         return shortOpts.containsKey(opt) || longOpts.containsKey(opt);
308     }
309 
310     /**
311      * Returns whether the named {@link Option} is a member of this {@link Options}.
312      *
313      * @param opt long name of the {@link Option}
314      * @return true if the named {@link Option} is a member of this {@link Options}
315      * @since 1.3
316      */
317     public boolean hasLongOption(String opt)
318     {
319         opt = Util.stripLeadingHyphens(opt);
320 
321         return longOpts.containsKey(opt);
322     }
323 
324     /**
325      * Returns whether the named {@link Option} is a member of this {@link Options}.
326      *
327      * @param opt short name of the {@link Option}
328      * @return true if the named {@link Option} is a member of this {@link Options}
329      * @since 1.3
330      */
331     public boolean hasShortOption(String opt)
332     {
333         opt = Util.stripLeadingHyphens(opt);
334 
335         return shortOpts.containsKey(opt);
336     }
337 
338     /**
339      * Returns the OptionGroup the <code>opt</code> belongs to.
340      *
341      * @param opt the option whose OptionGroup is being queried.
342      * @return the OptionGroup if <code>opt</code> is part of an OptionGroup, otherwise return null
343      */
344     public OptionGroup getOptionGroup(Option opt)
345     {
346         return optionGroups.get(opt.getKey());
347     }
348 
349     /**
350      * Dump state, suitable for debugging.
351      *
352      * @return Stringified form of this object
353      */
354     @Override
355     public String toString()
356     {
357         StringBuilder buf = new StringBuilder();
358 
359         buf.append("[ Options: [ short ");
360         buf.append(shortOpts.toString());
361         buf.append(" ] [ long ");
362         buf.append(longOpts);
363         buf.append(" ]");
364 
365         return buf.toString();
366     }
367 }