| /* |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package org.apache.commons.cli; |
| |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Main entry-point into the library. |
| * <p> |
| * Options represents a collection of {@link Option} objects, which describe the possible options for a command-line. |
| * </p> |
| * <p> |
| * It may flexibly parse long and short options, with or without values. Additionally, it may parse only a portion of a |
| * commandline, allowing for flexible multi-stage parsing. |
| * </p> |
| * |
| * @see org.apache.commons.cli.CommandLine |
| */ |
| public class Options implements Serializable { |
| /** The serial version UID. */ |
| private static final long serialVersionUID = 1L; |
| |
| /** A map of the options with the character key */ |
| private final Map<String, Option> shortOpts = new LinkedHashMap<>(); |
| |
| /** A map of the options with the long key */ |
| private final Map<String, Option> longOpts = new LinkedHashMap<>(); |
| |
| /** A map of the required options */ |
| // N.B. This can contain either a String (addOption) or an OptionGroup (addOptionGroup) |
| // TODO this seems wrong |
| private final List<Object> requiredOpts = new ArrayList<>(); |
| |
| /** A map of the option groups */ |
| private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<>(); |
| |
| /** |
| * Adds an option instance |
| * |
| * @param opt the option that is to be added |
| * @return the resulting Options instance |
| */ |
| public Options addOption(final Option opt) { |
| final String key = opt.getKey(); |
| // add it to the long option list |
| if (opt.hasLongOpt()) { |
| longOpts.put(opt.getLongOpt(), opt); |
| } |
| // if the option is required add it to the required list |
| if (opt.isRequired()) { |
| if (requiredOpts.contains(key)) { |
| requiredOpts.remove(requiredOpts.indexOf(key)); |
| } |
| requiredOpts.add(key); |
| } |
| shortOpts.put(key, opt); |
| return this; |
| } |
| |
| /** |
| * Adds an option that only contains a short-name. |
| * <p> |
| * It may be specified as requiring an argument. |
| * </p> |
| * |
| * @param opt Short single-character name of the option. |
| * @param hasArg flag signalling if an argument is required after this option |
| * @param description Self-documenting description |
| * @return the resulting Options instance |
| */ |
| public Options addOption(final String opt, final boolean hasArg, final String description) { |
| addOption(opt, null, hasArg, description); |
| return this; |
| } |
| |
| /** |
| * Adds an option that only contains a short name. |
| * <p> |
| * The option does not take an argument. |
| * </p> |
| * |
| * @param opt Short single-character name of the option. |
| * @param description Self-documenting description |
| * @return the resulting Options instance |
| * @since 1.3 |
| */ |
| public Options addOption(final String opt, final String description) { |
| addOption(opt, null, false, description); |
| return this; |
| } |
| |
| /** |
| * Adds an option that contains a short-name and a long-name. |
| * <p> |
| * It may be specified as requiring an argument. |
| * </p> |
| * |
| * @param opt Short single-character name of the option. |
| * @param longOpt Long multi-character name of the option. |
| * @param hasArg flag signalling if an argument is required after this option |
| * @param description Self-documenting description |
| * @return the resulting Options instance |
| */ |
| public Options addOption(final String opt, final String longOpt, final boolean hasArg, final String description) { |
| addOption(new Option(opt, longOpt, hasArg, description)); |
| return this; |
| } |
| |
| /** |
| * Adds the specified option group. |
| * |
| * @param group the OptionGroup that is to be added |
| * @return the resulting Options instance |
| */ |
| public Options addOptionGroup(final OptionGroup group) { |
| if (group.isRequired()) { |
| requiredOpts.add(group); |
| } |
| for (final Option option : group.getOptions()) { |
| // an Option cannot be required if it is in an |
| // OptionGroup, either the group is required or |
| // nothing is required |
| option.setRequired(false); |
| addOption(option); |
| optionGroups.put(option.getKey(), group); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds options to this option. If any Option in {@code options} already exists |
| * in this Options an IllegalArgumentException is thrown |
| * |
| * @param options the options to add. |
| * @return The resulting Options instance. |
| * @since 1.7.0 |
| */ |
| public Options addOptions(final Options options) { |
| for (final Option opt : options.getOptions()) { |
| if (hasOption(opt.getKey())) { |
| throw new IllegalArgumentException("Duplicate key: " + opt.getKey()); |
| } |
| addOption(opt); |
| } |
| options.getOptionGroups().forEach(this::addOptionGroup); |
| return this; |
| } |
| |
| /** |
| * Adds an option that contains a short-name and a long-name. |
| * <p> |
| * The added option is set as required. It may be specified as requiring an argument. This method is a shortcut for: |
| * </p> |
| * <pre> |
| * <code> |
| * Options option = new Option(opt, longOpt, hasArg, description); |
| * option.setRequired(true); |
| * options.add(option); |
| * </code> |
| * </pre> |
| * |
| * @param opt Short single-character name of the option. |
| * @param longOpt Long multi-character name of the option. |
| * @param hasArg flag signalling if an argument is required after this option |
| * @param description Self-documenting description |
| * @return the resulting Options instance |
| * @since 1.4 |
| */ |
| public Options addRequiredOption(final String opt, final String longOpt, final boolean hasArg, final String description) { |
| final Option option = new Option(opt, longOpt, hasArg, description); |
| option.setRequired(true); |
| addOption(option); |
| return this; |
| } |
| |
| /** |
| * Gets the options with a long name starting with the name specified. |
| * |
| * @param opt the partial name of the option |
| * @return the options matching the partial name specified, or an empty list if none matches |
| * @since 1.3 |
| */ |
| public List<String> getMatchingOptions(final String opt) { |
| final String clean = Util.stripLeadingHyphens(opt); |
| final List<String> matchingOpts = new ArrayList<>(); |
| // for a perfect match return the single option only |
| if (longOpts.containsKey(clean)) { |
| return Collections.singletonList(clean); |
| } |
| for (final String longOpt : longOpts.keySet()) { |
| if (longOpt.startsWith(clean)) { |
| matchingOpts.add(longOpt); |
| } |
| } |
| return matchingOpts; |
| } |
| |
| /** |
| * Gets the {@link Option} matching the long or short name specified. |
| * <p> |
| * The leading hyphens in the name are ignored (up to 2). |
| * </p> |
| * |
| * @param opt short or long name of the {@link Option} |
| * @return the option represented by opt |
| */ |
| public Option getOption(final String opt) { |
| final String clean = Util.stripLeadingHyphens(opt); |
| final Option option = shortOpts.get(clean); |
| return option != null ? option : longOpts.get(clean); |
| } |
| |
| /** |
| * Gets the OptionGroup the {@code opt} belongs to. |
| * |
| * @param opt the option whose OptionGroup is being queried. |
| * @return the OptionGroup if {@code opt} is part of an OptionGroup, otherwise return null |
| */ |
| public OptionGroup getOptionGroup(final Option opt) { |
| return optionGroups.get(opt.getKey()); |
| } |
| |
| /** |
| * Gets the OptionGroups that are members of this Options instance. |
| * |
| * @return a Collection of OptionGroup instances. |
| */ |
| Collection<OptionGroup> getOptionGroups() { |
| /* The optionGroups map will have duplicates in the values() results. We |
| * use the HashSet to filter out duplicates and return a collection of |
| * OpitonGroup. The decision to return a Collection rather than a set |
| * was probably to keep symmetry with the getOptions() method. |
| */ |
| return new HashSet<>(optionGroups.values()); |
| } |
| |
| /** |
| * Gets a read-only list of options in this set |
| * |
| * @return read-only Collection of {@link Option} objects in this descriptor |
| */ |
| public Collection<Option> getOptions() { |
| return Collections.unmodifiableCollection(helpOptions()); |
| } |
| |
| /** |
| * Gets the required options. |
| * |
| * @return read-only List of required options |
| */ |
| public List<?> getRequiredOptions() { |
| return Collections.unmodifiableList(requiredOpts); |
| } |
| |
| /** |
| * Tests whether the named {@link Option} is a member of this {@link Options}. |
| * |
| * @param opt long name of the {@link Option} |
| * @return true if the named {@link Option} is a member of this {@link Options} |
| * @since 1.3 |
| */ |
| public boolean hasLongOption(final String opt) { |
| return longOpts.containsKey(Util.stripLeadingHyphens(opt)); |
| } |
| |
| /** |
| * Tests whether the named {@link Option} is a member of this {@link Options}. |
| * |
| * @param opt short or long name of the {@link Option} |
| * @return true if the named {@link Option} is a member of this {@link Options} |
| */ |
| public boolean hasOption(final String opt) { |
| final String clean = Util.stripLeadingHyphens(opt); |
| return shortOpts.containsKey(clean) || longOpts.containsKey(clean); |
| } |
| |
| /** |
| * Tests whether the named {@link Option} is a member of this {@link Options}. |
| * |
| * @param opt short name of the {@link Option} |
| * @return true if the named {@link Option} is a member of this {@link Options} |
| * @since 1.3 |
| */ |
| public boolean hasShortOption(final String opt) { |
| final String clean = Util.stripLeadingHyphens(opt); |
| return shortOpts.containsKey(clean); |
| } |
| |
| /** |
| * Returns the Options for use by the HelpFormatter. |
| * |
| * @return the List of Options |
| */ |
| List<Option> helpOptions() { |
| return new ArrayList<>(shortOpts.values()); |
| } |
| |
| /** |
| * Dump state, suitable for debugging. |
| * |
| * @return Stringified form of this object |
| */ |
| @Override |
| public String toString() { |
| final StringBuilder buf = new StringBuilder(); |
| buf.append("[ Options: [ short "); |
| buf.append(shortOpts.toString()); |
| buf.append(" ] [ long "); |
| buf.append(longOpts); |
| buf.append(" ]"); |
| return buf.toString(); |
| } |
| } |