/* * JCarder -- cards Java programs to keep threads disentangled * * Copyright (C) 2006-2007 Enea AB * Copyright (C) 2007 Ulrik Svensson * Copyright (C) 2007 Joel Rosdahl * * This program is made available under the GNU GPL version 2, with a special * exception for linking with JUnit. See the accompanying file LICENSE.txt for * details. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package com.enea.jcarder.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class parses command-line options. */ public class OptionParser { private class OptionData { String valueName; String description; } private final List<String> mArguments = new ArrayList<String>(); private final Map<String, String> mParsedOptions = new HashMap<String, String>(); private final Map<String, OptionData> mValidOptions = new HashMap<String, OptionData>(); public OptionParser() { } /** * Tell the parser to recognize a new option. * * Options can be given on the following forms: * * <ul> * <li>-option</li> * <li>-option foo</li> * </ul> * * The first form specifies an option without a value and the second * specifies an option with a value. * * @param option * The option. * @param description * Description of the option. */ public void addOption(String option, String description) { final int spacePos = option.indexOf(' '); final String flag; final String valueName; if (spacePos == -1) { flag = option; valueName = null; } else { flag = option.substring(0, spacePos); valueName = option.substring(spacePos + 1); } OptionData data = new OptionData(); data.valueName = valueName; data.description = description; mValidOptions.put(flag, data); } /** * Get arguments remaining after options (and their values) have been * parsed. * * @return The arguments. */ public List<String> getArguments() { return mArguments; } /** * Get a string containing help text describing available options. * * @return The help text. */ public String getOptionHelp() { StringBuilder sb = new StringBuilder(); OptionFormatter formatter = new OptionFormatter(2, 23, 79); ArrayList<String> options = new ArrayList<String>(); options.addAll(mValidOptions.keySet()); Collections.sort(options); for (String option : options) { final OptionData data = mValidOptions.get(option); final String optAndVal; if (data.valueName == null) { optAndVal = option; } else { optAndVal = option + " " + data.valueName; } formatter.format(sb, optAndVal, data.description); } return sb.toString(); } /** * Get parsed options. * * The map is keyed on option and the values are the option values (null if * no parameter was expected). * * @return The option map. */ public Map<String, String> getOptions() { return mParsedOptions; } /** * Parse arguments. * * @param arguments * The arguments to parse. * @throws InvalidOptionException * If an invalid option is encountered. */ public void parse(String[] arguments) throws InvalidOptionException { mArguments.clear(); boolean reachedNonOption = false; for (int i = 0; i < arguments.length; ++i) { if (!reachedNonOption && (arguments[i].length() == 0 || arguments[i].charAt(0) != '-')) { reachedNonOption = true; } if (reachedNonOption) { mArguments.add(arguments[i]); } else { String option = arguments[i]; if (mValidOptions.containsKey(option)) { OptionData data = mValidOptions.get(option); String optionArgument; if (data.valueName != null) { ++i; if (i < arguments.length) { optionArgument = arguments[i]; } else { String message = "value missing to flag " + option; throw new InvalidOptionException(message); } } else { optionArgument = null; } mParsedOptions.put(option, optionArgument); } else { throw new InvalidOptionException("invalid flag: " + arguments[i]); } } } } }