/* CommandLineOptionsParser.java * * You may use and distribute under the terms of either the GNU Lesser * General Public License, either version 2 of the license or, * at your choice, any later version. Alternatively, you may use and * distribute under the terms of the XPL. * * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of * the licenses. * * This software 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. See the README * file for more details. * */ /* * Written by Antti-Juhani Kaijanaho */ package org.gzigzag; import java.util.*; /** Command line options parser. */ class CommandLineOptionsParser { /** Objects of this class or of descendants of this class * represent valid command-line options. By default, this option * does nothing except note that the option was seen. Subclasses * can override action to provide functionality to an * option. * * @see HelpOption */ public static class Option { /** The name of this option. A dash will be automatically * appended to this name to produce the string that is matched * against in command line. */ public final String name; /** A list of argument names for this option. The option will * take as many mandatory arguments as there are elements in * this array. The names of the arguments are purely * documentary and are used in help screens. * * @see org.gzigzag.CommandLineOptionsParser.HelpOption */ public final String[] argNames; /** A help text for this option. The text will be * word-wrapped; newlines embedded in the text are * honoured. * * @see org.gzigzag.CommandLineOptionsParser.HelpOption */ public final String helpText; /** The action for this option. This method will be invoked * when this option is noticed. * * @param clop The instance of * CommandLineOptionsParser that is running this * parse. * @param args The arguments given on the command line to this * option. This array will have exactly as many elements as * the argNames attribute. */ public void action(CommandLineOptionsParser clop, String[] args) {} /** Constructs an option. * * @param name The value to be given to the name * attribute. * @param argNames The value to be given to the * argNames attribute. * @param helpText The value to be given to the * helpText attribute. */ public Option(String name, String[] argNames, String helpText) { this.name = name; this.argNames = argNames; this.helpText = helpText; } } /** A command-line option for showing help about command-line * options. */ public static class HelpOption extends Option { /** Constructs a HelpOption. * @param name The name for this option (a dash will be * automatically prepended to create the string that is * matched against the command line). * @param helpText The help text for this option. This text * will be word-wrapped. Embedded newlines are honoured. * @param exitAfter Should the program be exited after showing * the help? * @param prologue Text to be shown before the list of * options. This text will be word-wrapped. Embedded * newlines are honoured. * @param epilogue Text to be shown before the list of * options. This text will be word-wrapped. Embedded * newlines are honoured. */ public HelpOption(String name, String helpText, boolean exitAfter, String prologue, String epilogue) { super(name, new String[0], helpText); this.exitAfter = exitAfter; this.prologue = prologue; this.epilogue = epilogue; } public void action(CommandLineOptionsParser clop, String[] args) { int rightmargin = 75; System.out.println(breakToLines(prologue, rightmargin, 0)); for (Enumeration e = clop.options_in_order.elements(); e.hasMoreElements();) { Option opt = (Option)e.nextElement(); int expltab = 15; int nametab = 3; int seplen = 2; String help = breakToLines(opt.helpText, rightmargin, expltab + nametab + seplen); String name = "-" + opt.name; for (int i = 0; i < opt.argNames.length; i++) { name += " " + opt.argNames[i]; } if (name.length() > expltab) { help = spaces(nametab) + name + '\n' + help; } else { help = spaces(nametab) + name + spaces(seplen + expltab - name.length()) + help.substring(expltab + nametab + seplen); } System.out.println(help); } System.out.println(breakToLines(epilogue, rightmargin, 0)); if (exitAfter) SafeExit.exit(0); } private String spaces(int n) { StringBuffer sb = new StringBuffer(n); for (int i = 0; i < n; i++) sb.append(' '); return new String(sb); } private int breakpoint(String s, int start, int maxlen) { if (s.length() - start < maxlen) return s.length(); int bp = start + maxlen < s.length() ? start + maxlen : s.length(); for (int i = 0; i < maxlen && i + start < s.length(); i++) { int c = s.charAt(start + i); if (c == '\n') return start + i; if (c == '\t' || c == ' ') bp = start + i; } return bp; } private String breakToLines(String s, int rmargin, int indent) { int maxlen = rmargin - indent; StringBuffer sb = new StringBuffer(); String ind = spaces(indent); int a = 0; while (a < s.length()) { int b = breakpoint(s, a, maxlen); sb.append(ind); sb.append(s.substring(a, b)); sb.append('\n'); if (b < s.length() && (s.charAt(b) == '\n' || s.charAt(b) == ' ' || s.charAt(b) == '\t')) { ++b; } a = b; } return new String(sb); } private final boolean exitAfter; private final String prologue; private final String epilogue; } /** Constructs a command line options parser. * @param options An array of preconstructed options. * @see #put(Option) */ public CommandLineOptionsParser(Option[] options) { for (int i = 0; i < options.length; i++) { put(options[i]); } } /** Constructs a command line options parser with an initially * empty set of acceptable options. */ public CommandLineOptionsParser() {} /** Adds option to the list of valid options. */ public void put(Option option) { options.put(option.name, option); options_in_order.addElement(option); } /** Adds a new option to the list of valid options. The option * object will be a new instance of class Option. * The arguments of this method are passed unchanged to the * constructor. * @see Option */ public void put(String name, String[] argNames, String helpText) { put(new Option(name, argNames, helpText)); } /** Adds a help option to the list of valid options. The option * object will be a new instance of HelpOption. The * arguments of this method are passed unchanged to the * constructor. * @see HelpOption */ public void putHelp(String name, String helpText, boolean exitAfter, String prologue, String epilogue) { put(new HelpOption(name, helpText, exitAfter, prologue, epilogue)); } /** Marks all options unseen. */ public void clearArgs() { optargs = new Hashtable(); } /** Gets the list of arguments for the option specified. * @param name The name of the option whose arguments are to be returned. * @return null, if the option has not been seen, otherwise the * same array or a copy of the same array that the * action method of Option gets. */ public String[] getArgs(String name) { Object o = optargs.get(name); if (o == null) return null; return (String[]) o; } /** Gets a specific argument for the option specified. * @param name The name of the option whose argument is to be * returned * @param i The ordinal number of the argument to be returned (0 * for the first argument, 1 for the second and so on) * @return null, if the option has not seen, otherwise the * ith (0-based) argument to the option. */ public String getArg(String name, int i) { return getArg(name, i, null); } /** Gets a specific argument for the option specified. * @param name The name of the option whose argument is to be * returned * @param i The ordinal number of the argument to be returned (0 * for the first argument, 1 for the second and so on) * @param deflt The object to be returned if the option has not * been seen. * @return deflt, if the option has not seen, otherwise the * ith (0-based) argument to the option. */ public String getArg(String name, int i, String deflt) { String[] args = getArgs(name); if (args == null) return deflt; return args[i]; } /** Determines whether the specified option was seen in parses * since the arguments were last cleared. */ public boolean seen(String name) { return optargs.containsKey(name); } /** Parse command-line options from args and return the first * index to attrs that is not an option, or attrs.length if there * are none such . */ public int parse(String[] args) { int i; for (i = 0; i < args.length; i++) { if (args[i].length() == 0 || args[i].charAt(0) != '-') { return i; } if (!options.containsKey(args[i].substring(1))) { throw new SyntaxError("unknown option: " + args[i]); } Option opt = (Option)options.get(args[i].substring(1)); String[] oargs = new String[opt.argNames.length]; for (int j = 0; j < oargs.length; j++) { ++i; if (i >= args.length) { throw new SyntaxError("too few arguments to option: -" + opt.name); } oargs[j] = args[i]; } optargs.put(opt.name, oargs); opt.action(this, oargs); } return i; } private Hashtable options = new Hashtable(); private Vector options_in_order = new Vector(); private Hashtable optargs = new Hashtable(); }