package freeboogie; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import freeboogie.util.Err; /** * Parses options. Right now it supports simple boolean and integer * options. It prints a list of registered options when it sees "-help". * * In the future it might support arbitrary strings and perhaps * keep track of dependencies between options. * * TODO: Introduce the notion of legal values for integer options * * @author rgrig * @author reviewed by TODO */ public class Options { private class Opt<T> { /** Make a structure * @param n name * @param h help * @param d default */ public Opt(String n, String h, T d) { name = n; help = h; def = d; } /** name */ public String name; /** help */ public String help; /** default */ public T def; } // the following two are used to make the help message private ArrayList<Opt<Boolean>> boolOpt; // boolean options private ArrayList<Opt<Integer>> intOpt; // integer options private HashMap<String, Boolean> boolVal; // boolean values private HashMap<String, Integer> intVal; // integer values private LinkedList<String> otherVal; // things that don't look like options /** Constructs an object. Nothing fancy. */ public Options() { boolOpt = new ArrayList<Opt<Boolean>>(); intOpt = new ArrayList<Opt<Integer>>(); boolVal = new HashMap<String, Boolean>(); intVal = new HashMap<String, Integer>(); otherVal = new LinkedList<String>(); } /** * Register {@code name} as a boolean option. The default value is always * {@code false} and becomes {@code true} if {@code name} appears in the * arguments. * @param name the boolean option * @param help help string */ public void regBool(String name, String help) { boolOpt.add(new Opt<Boolean>(name, help, false)); boolVal.put(name, false); } /** * Register {@code name} as an integer option. * @param name the integer option * @param def the default value if none is specified by the user * @param help help string */ public void regInt(String name, int def, String help) { intOpt.add(new Opt<Integer>(name, help, def)); intVal.put(name, def); } /** * Query the value of the boolean option {@code name}. * @param name the boolean option to query * @return the value of {@code name} */ public boolean boolVal(String name) { return boolVal.get(name); } /** * Query the value of the integer option {@code name}. * @param name the integer option to query * @return the value of {@code name} */ public int intVal(String name) { return intVal.get(name); } /** * Query what non-option arguments appeared on the command line. * @return the non-option arguments (usually file names) */ public List<String> otherArgs() { return otherVal; } private void printHelp() { // TODO: better formatting for (Opt<Boolean> o : boolOpt) { System.out.print(o.name + "\t"); System.out.print(o.help + " "); System.out.println("(default: " + o.def + ")"); } for (Opt<Integer> o : intOpt) { System.out.print(o.name + "\t"); System.out.print(o.help + " "); System.out.println("(default: " + o.def + ")"); } } /** * Parse {@code args}. * @param args the arguments to parse */ public void parse(String[] args) { for (int i = 0; i < args.length; ++i) { if (args[i].equals("-help")) printHelp(); else if (boolVal.containsKey(args[i])) { boolVal.put(args[i], true); } else if (intVal.containsKey(args[i])) { if (i + 1 >= args.length) Err.fatal("Option " + args[i] + " should be followed by a number."); try { intVal.put(args[i], Integer.parseInt(args[i+1])); } catch (NumberFormatException fe) { Err.fatal("Option " + args[i] + " should be followed by a number."); } ++i; } else { otherVal.add(args[i]); } } } }