package js.tinyvm.util; import java.io.File; import java.io.PrintWriter; import js.tinyvm.TinyVMException; import js.tinyvm.RunTimeOptions; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; /** * CommandLineParser */ public class TinyVMCommandLineParser { protected final Options options = new Options(); protected CommandLine result; private final boolean reqoutput; private boolean bigendian; private String bp; private String cp; public TinyVMCommandLineParser(boolean reqoutput) { this.reqoutput = reqoutput; options.addOption("h", "help", false, "show this help"); options.addOption("a", "all", false, "do not filter classes"); options.addOption("g", "debug", false, "include debug monitor"); options.addOption("v", "verbose", false, "print class and signature information"); options.addOption("ea", "enableassert", false, "enable assertions"); options.addOption("ec", "enablechecks", false, "enable run time checks"); Option bclasspathOption = new Option("bp", "bootclasspath", true, "where to find leJOS classes"); bclasspathOption.setArgName("classpath"); options.addOption(bclasspathOption); Option classpathOption = new Option("cp", "classpath", true, "where to find user's classes"); classpathOption.setArgName("classpath"); options.addOption(classpathOption); Option outputOption = new Option("o", "output", true, "dump binary to file"); outputOption.setArgName("path to file"); options.addOption(outputOption); Option writeOrderOption = new Option("wo", "writeorder", true, "endianness (BE or LE)"); writeOrderOption.setArgName("write order"); options.addOption(writeOrderOption); //Option deviceOption = new Option("tty", "device", true,"device used (USB, COM1, etc)"); //deviceOption.setArgName("device"); //options.addOption(deviceOption); } protected static String getLastOptVal(CommandLine cmdline, String key) { return getLastOptVal(cmdline, key, null); } protected static String getLastOptVal(CommandLine cmdline, String key, String def) { String[] vals = cmdline.getOptionValues(key); if (vals == null || vals.length <= 0) return def; return vals[vals.length - 1]; } private static String mangleClassPath(String cp) throws ParseException { StringBuilder sb = new StringBuilder(); int start = 0; int len = cp.length(); while (start < len) { int end = cp.indexOf(File.pathSeparatorChar, start); if (end < 0) end = len; String file = cp.substring(start, end); File f = new File(file); if (!f.exists()) throw new ParseException("File does not exist: "+file); if (start > 0) sb.append(File.pathSeparatorChar); //sb.append(f.getAbsolutePath()); //sb.append(f.getCanonicalPath()); sb.append(file); start = end+1; } return sb.toString(); } public boolean isHelp() { return this.result.hasOption("h"); } public boolean isAll() { return this.result.hasOption("a"); } public boolean isDebug() { return this.result.hasOption("g"); } public boolean isVerbose() { return this.result.hasOption("v"); } public boolean isEnableAssert() { return this.result.hasOption("ea"); } public boolean isEnableChecks() { return this.result.hasOption("ec"); } public String getOutput() { return getLastOptVal(this.result, "o"); } public String getBP() { return this.bp; } public String getCP() { return this.cp; } public boolean isBigEndian() { return this.bigendian; } public String[] getRestArgs() { return this.result.getArgs(); } public int getRunTimeOptions() { int opt = 0; if (isEnableAssert()) opt |= RunTimeOptions.EnableAssert.getValue(); if (isEnableChecks()) opt |= RunTimeOptions.EnableTypeChecks.getValue(); return opt; } /** * Parse commandline. * * @param args command line * @throws TinyVMException */ public void parse (String[] args) throws ParseException { assert args != null: "Precondition: args != null"; result = new GnuParser().parse(options, args); if (!result.hasOption("bp")) { //throw new ParseException("No bootclasspath defined"); System.err.println("No bootclasspath specified. Update your build scripts."); System.err.println("The bootclasspath parameter will be required in future releases."); } if (!result.hasOption("cp")) throw new ParseException("No classpath specified"); if (reqoutput && !result.hasOption("o")) throw new ParseException("No output file specified"); if (!result.hasOption("wo")) throw new ParseException("No write order specified"); String[] args2 = result.getArgs(); if (args2.length == 0) throw new ParseException("No classes specified"); String writeOrder = getLastOptVal(result, "wo").toLowerCase(); this.bigendian = "be".equals(writeOrder); if (!this.bigendian && !"le".equals(writeOrder)) throw new ParseException("Invalid write order: " + writeOrder); this.bp = mangleClassPath(getLastOptVal(result, "bp", "")); this.cp = mangleClassPath(getLastOptVal(result, "cp")); } public boolean parseOrHelp(Class<?> mainclass, String[] args) { try { this.parse(args); } catch (ParseException e) { System.out.println(e.getMessage()); this.printHelp(mainclass); return false; } if (this.isHelp()) { this.printHelp(mainclass); return false; } return true; } public void printHelp(Class<?> mainclass) { String commandName = System.getProperty("COMMAND_NAME"); if (commandName == null) commandName = "java "+mainclass.getName(); //String linesep = System.getProperty("line.separator", "\n\r"); String header = "options:"; String footer = ""; String usage = commandName + " [options] class1 [class2 ...]"; PrintWriter out = new PrintWriter(System.out, false); out.println(); new HelpFormatter().printHelp(out, 80, usage, header, options, 0, 2, footer); out.println(); out.flush(); } }