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.Collections; 024import java.util.HashSet; 025import java.util.LinkedHashMap; 026import java.util.List; 027import java.util.Map; 028 029/** 030 * Main entry-point into the library. 031 * <p> 032 * Options represents a collection of {@link Option} objects, which 033 * describe the possible options for a command-line. 034 * <p> 035 * It may flexibly parse long and short options, with or without 036 * values. Additionally, it may parse only a portion of a commandline, 037 * allowing for flexible multi-stage parsing. 038 * 039 * @see org.apache.commons.cli.CommandLine 040 * 041 * @version $Id: Options.java 1754332 2016-07-27 18:47:57Z britter $ 042 */ 043public class Options implements Serializable 044{ 045 /** The serial version UID. */ 046 private static final long serialVersionUID = 1L; 047 048 /** a map of the options with the character key */ 049 private final Map<String, Option> shortOpts = new LinkedHashMap<String, Option>(); 050 051 /** a map of the options with the long key */ 052 private final Map<String, Option> longOpts = new LinkedHashMap<String, Option>(); 053 054 /** a map of the required options */ 055 // N.B. This can contain either a String (addOption) or an OptionGroup (addOptionGroup) 056 // TODO this seems wrong 057 private final List<Object> requiredOpts = new ArrayList<Object>(); 058 059 /** a map of the option groups */ 060 private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<String, OptionGroup>(); 061 062 /** 063 * Add the specified option group. 064 * 065 * @param group the OptionGroup that is to be added 066 * @return the resulting Options instance 067 */ 068 public Options addOptionGroup(OptionGroup group) 069 { 070 if (group.isRequired()) 071 { 072 requiredOpts.add(group); 073 } 074 075 for (Option option : group.getOptions()) 076 { 077 // an Option cannot be required if it is in an 078 // OptionGroup, either the group is required or 079 // nothing is required 080 option.setRequired(false); 081 addOption(option); 082 083 optionGroups.put(option.getKey(), group); 084 } 085 086 return this; 087 } 088 089 /** 090 * Lists the OptionGroups that are members of this Options instance. 091 * 092 * @return a Collection of OptionGroup instances. 093 */ 094 Collection<OptionGroup> getOptionGroups() 095 { 096 return new HashSet<OptionGroup>(optionGroups.values()); 097 } 098 099 /** 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 * Retrieve the {@link Option} matching the long name specified. 269 * The leading hyphens in the name are ignored (up to 2). 270 * 271 * @param opt long name of the {@link Option} 272 * @return the option represented by opt 273 */ 274 Option getLongOption(String opt) 275 { 276 opt = Util.stripLeadingHyphens(opt); 277 278 return longOpts.get(opt); 279 } 280 281 /** 282 * Returns the options with a long name starting with the name specified. 283 * 284 * @param opt the partial name of the option 285 * @return the options matching the partial name specified, or an empty list if none matches 286 * @since 1.3 287 */ 288 public List<String> getMatchingOptions(String opt) 289 { 290 opt = Util.stripLeadingHyphens(opt); 291 292 List<String> matchingOpts = new ArrayList<String>(); 293 294 // for a perfect match return the single option only 295 if (longOpts.keySet().contains(opt)) 296 { 297 return Collections.singletonList(opt); 298 } 299 300 for (String longOpt : longOpts.keySet()) 301 { 302 if (longOpt.startsWith(opt)) 303 { 304 matchingOpts.add(longOpt); 305 } 306 } 307 308 return matchingOpts; 309 } 310 311 /** 312 * Returns whether the named {@link Option} is a member of this {@link Options}. 313 * 314 * @param opt short or long name of the {@link Option} 315 * @return true if the named {@link Option} is a member of this {@link Options} 316 */ 317 public boolean hasOption(String opt) 318 { 319 opt = Util.stripLeadingHyphens(opt); 320 321 return shortOpts.containsKey(opt) || longOpts.containsKey(opt); 322 } 323 324 /** 325 * Returns whether the named {@link Option} is a member of this {@link Options}. 326 * 327 * @param opt long 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 hasLongOption(String opt) 332 { 333 opt = Util.stripLeadingHyphens(opt); 334 335 return longOpts.containsKey(opt); 336 } 337 338 /** 339 * Returns whether the named {@link Option} is a member of this {@link Options}. 340 * 341 * @param opt short name of the {@link Option} 342 * @return true if the named {@link Option} is a member of this {@link Options} 343 * @since 1.3 344 */ 345 public boolean hasShortOption(String opt) 346 { 347 opt = Util.stripLeadingHyphens(opt); 348 349 return shortOpts.containsKey(opt); 350 } 351 352 /** 353 * Returns the OptionGroup the <code>opt</code> belongs to. 354 * 355 * @param opt the option whose OptionGroup is being queried. 356 * @return the OptionGroup if <code>opt</code> is part of an OptionGroup, otherwise return null 357 */ 358 public OptionGroup getOptionGroup(Option opt) 359 { 360 return optionGroups.get(opt.getKey()); 361 } 362 363 /** 364 * Dump state, suitable for debugging. 365 * 366 * @return Stringified form of this object 367 */ 368 @Override 369 public String toString() 370 { 371 StringBuilder buf = new StringBuilder(); 372 373 buf.append("[ Options: [ short "); 374 buf.append(shortOpts.toString()); 375 buf.append(" ] [ long "); 376 buf.append(longOpts); 377 buf.append(" ]"); 378 379 return buf.toString(); 380 } 381}