package org.kisst.gft; import java.util.LinkedHashMap; public class Cli { public class Option { public final String shortName; public final String longName; public final String desc; //private final Object defaultValue; protected Object value; private boolean isSet; public Option(String shortName, String longName, String desc, Object defaultValue) { this.shortName=shortName; this.longName=longName; this.desc=desc; //this.defaultValue=defaultValue; value=defaultValue; add(this); } public void set(Object value) { this.value=value; isSet=true;} public boolean isSet() { return isSet; } public int parse(String[] args, int index) { if (index+1>=args.length) throw new RuntimeException("option "+getNames()+" should have argument"); set(args[index+1]); return index+2; } public String getNames() { if (longName==null) return "-"+shortName; else if (shortName==null) return " --"+longName; else return "-"+shortName+",--"+longName; } } public class StringOption extends Option { private StringOption(String shortName, String longName, String desc, String defaultValue) { super(shortName, longName, desc, defaultValue); } public String get() { return (String) value; } @Override public String getNames() { return super.getNames()+" <str>"; } } public class BooleanOption extends Option { private BooleanOption(String shortName, String longName, String desc, boolean defaultValue) { super(shortName, longName, desc, ""+defaultValue); } public boolean get() { return Boolean.getBoolean((String) value); } @Override public String getNames() { return super.getNames()+" <bool>"; } } public class Flag extends Option { private Flag(String shortName, String longName, String desc) { super(shortName, longName, desc, null); } @Override public int parse(String[] args, int index) { set("true"); return index+1; } } public class SubCommand { private final String desc; private boolean isSet=false; private SubCommand(String name, String desc) { this.desc=desc; subCommands.put(name,this); } public boolean isSet() { return isSet;} } private final LinkedHashMap<String, Option> options=new LinkedHashMap<String, Option>(); private final LinkedHashMap<String,SubCommand> subCommands = new LinkedHashMap<String,SubCommand>(); public SubCommand subCommand(String name, String syntax) { return new SubCommand(name, syntax); } private void add(Option o) { if (o.shortName!=null) options.put(o.shortName, o); if (o.longName!=null) options.put(o.longName, o); } public StringOption stringOption(String shortName, String longName, String desc, String defaultValue) { return new StringOption(shortName, longName, desc, defaultValue); } public BooleanOption booleanOption(String shortName, String longName, String desc, boolean defaultValue) { return new BooleanOption(shortName, longName, desc, defaultValue); } public Flag flag(String shortName, String longName, String desc) { return new Flag(shortName, longName, desc); } public String[] parse(String[] args) { int index=0; while (index<args.length) { String arg=args[index]; Option o=null; // Note: short options and long options are all stored in same hashtable // They should never clash, since a long option should be longer than 1 character if (arg.startsWith("--")) o=options.get(arg.substring(2)); else if (arg.startsWith("-") || arg.startsWith("+")) o=options.get(arg.substring(1)); else if (subCommands.get(arg)!=null) { SubCommand cmd = subCommands.get(arg); cmd.isSet=true; return subArgs(args, index+1); } else return subArgs(args, index); if (o==null) throw new RuntimeException("Unknown option "+arg); index=o.parse(args, index); } return new String[]{}; } public static String[] subArgs(String[] args, int pos) { String result[]= new String[args.length-pos]; for (int i=pos; i<args.length; i++) result[i-pos]=args[i]; return result; } public String getSyntax(String prefix) { int maxlen=0; for (Option opt:options.values()) { if (opt.longName!=null && opt.longName.length()>maxlen) maxlen=opt.longName.length(); } StringBuilder result=new StringBuilder(); Option last=null; for (Option opt:options.values()) { if (opt==last) continue; String name=opt.getNames(); while (name.length()<maxlen+5) name+=" "; result.append(prefix+name+" "+opt.desc+"\n"); last=opt; } for (String name: subCommands.keySet()) { while (name.length()<maxlen+5) name+=" "; result.append(name+" "+subCommands.get(name.trim()).desc+"\n"); } return result.toString(); } }