X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2Fargparser%2FArgParser.java;h=e6bd9176aefd32fab099e8986afb0f43b3ae6d89;hb=167f4222520be1ec49277dab1e5350d236ed6292;hp=42868ae5903f247791d82564a4eadb8dfcfe5699;hpb=c373422471a5a5e4c38db580fbc4a7519dedc35b;p=jalview.git diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 42868ae..e6bd917 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -55,6 +55,9 @@ public class ArgParser // the linkedId string used to match all linkedIds seen so far protected static final String MATCHALLLINKEDIDS = "*"; + // the linkedId string used to match all of the last --open'ed linkedIds + protected static final String MATCHOPENEDLINKEDIDS = "open*"; + // the counter added to the default linked id prefix private int defaultLinkedIdCounter = 0; @@ -78,6 +81,11 @@ public class ArgParser // the linked id substitution string used to use the idCounter private static final String LINKEDIDAUTOCOUNTER = "{n}"; + // the linked id substitution string used to use the filename extension of + // --append + // or --open + private static final String LINKEDIDEXTENSION = "{extension}"; + // the linked id substitution string used to use the base filename of --append // or --open private static final String LINKEDIDBASENAME = "{basename}"; @@ -97,6 +105,10 @@ public class ArgParser // --argfile name private static final String ARGFILEDIRNAME = "{argfiledirname}"; + // an output file wildcard to signify --output=*.ext is really --all --output + // {basename}.ext + private static final String OUTPUTWILDCARD = "*."; + // flag to say whether {n} subtitutions in output filenames should be made. // Turn on and off with --substitutions and --nosubstitutions // Start with it on @@ -106,18 +118,26 @@ public class ArgParser // or ALL linkedIds private boolean allLinkedIds = false; + // flag to say whether the default linkedId is the current default linked id + // or OPENED linkedIds + private boolean openedLinkedIds = false; + protected static final Map argMap; protected Map linkedArgs = new HashMap<>(); protected List linkedOrder = new ArrayList<>(); + protected List storedLinkedIds = new ArrayList<>(); + protected List argList = new ArrayList<>(); private static final char ARGFILECOMMENT = '#'; private int argIndex = 0; + private BootstrapArgs bootstrapArgs = null; + static { argMap = new HashMap<>(); @@ -147,10 +167,11 @@ public class ArgParser public ArgParser(String[] args) { - this(args, false); + this(args, false, null); } - public ArgParser(String[] args, boolean initsubstitutions) + public ArgParser(String[] args, boolean initsubstitutions, + BootstrapArgs bsa) { // Make a mutable new ArrayList so that shell globbing parser works. // (When shell file globbing is used, there are a sequence of non-Arg @@ -158,16 +179,17 @@ public class ArgParser // consumed by the --append/--argfile/etc Arg which is most easily done by // removing these filenames from the list one at a time. This can't be done // with an ArrayList made with only Arrays.asList(String[] args). ) - this(new ArrayList<>(Arrays.asList(args)), initsubstitutions); + this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false, + bsa); } public ArgParser(List args, boolean initsubstitutions) { - this(args, initsubstitutions, false); + this(args, initsubstitutions, false, null); } public ArgParser(List args, boolean initsubstitutions, - boolean allowPrivate) + boolean allowPrivate, BootstrapArgs bsa) { // do nothing if there are no "--" args and (some "-" args || >0 arg is // "open") @@ -191,6 +213,10 @@ public class ArgParser parse(new ArrayList(), false, false); return; } + if (bsa != null) + this.bootstrapArgs = bsa; + else + this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args); parse(args, initsubstitutions, allowPrivate); } @@ -262,8 +288,10 @@ public class ArgParser { // arg not found Console.error("Argument '" + arg + "' not recognised. Exiting."); - Jalview.exit("Unrecognised command line argument '" + arg + "'", - 13); + Jalview.exit("Invalid argument used." + System.lineSeparator() + + "Use" + System.lineSeparator() + "jalview " + + Arg.HELP.argString() + System.lineSeparator() + + "for a usage statement.", 13); continue; } if (a.hasOption(Opt.PRIVATE) && !allowPrivate) @@ -366,6 +394,18 @@ public class ArgParser else if (a == Arg.ALL) { allLinkedIds = !negated; + openedLinkedIds = false; + } + else if (a == Arg.OPENED) + { + openedLinkedIds = !negated; + allLinkedIds = false; + } + + if (a.hasOption(Opt.STORED)) + { + // reset the lastOpenedLinkedIds list + this.storedLinkedIds = new ArrayList<>(); } // this is probably only Arg.NEW and Arg.OPEN @@ -383,10 +423,37 @@ public class ArgParser { if (linkedId == null) { - if (allLinkedIds && a.hasOption(Opt.ALLOWALL)) + if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL) + && val.startsWith(MATCHALLLINKEDIDS)) + { + // --output=*.ext is shorthand for --all --output {basename}.ext + // (or --image=*.ext) + allLinkedIds = true; + openedLinkedIds = false; + linkedId = MATCHALLLINKEDIDS; + val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME + + val.substring(MATCHALLLINKEDIDS.length()); + } + else if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL) + && val.startsWith(MATCHOPENEDLINKEDIDS)) + { + // --output=open*.ext is shorthand for --opened --output + // {basename}.ext + // (or --image=open*.ext) + openedLinkedIds = true; + allLinkedIds = false; + linkedId = MATCHOPENEDLINKEDIDS; + val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME + + val.substring(MATCHOPENEDLINKEDIDS.length()); + } + else if (allLinkedIds && a.hasOption(Opt.ALLOWALL)) { linkedId = MATCHALLLINKEDIDS; } + else if (openedLinkedIds && a.hasOption(Opt.ALLOWALL)) + { + linkedId = MATCHOPENEDLINKEDIDS; + } else { // use default linkedId for linked arguments @@ -422,10 +489,7 @@ public class ArgParser if (a.hasOption(Opt.NOACTION)) continue; - if (!linkedArgs.containsKey(linkedId)) - linkedArgs.put(linkedId, new ArgValuesMap()); - - ArgValuesMap avm = linkedArgs.get(linkedId); + ArgValuesMap avm = getOrCreateLinkedArgValuesMap(linkedId); // not dealing with both NODUPLICATEVALUES and GLOB if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val)) @@ -492,9 +556,12 @@ public class ArgParser setBoolean(linkedId, avs, true, argIndex); } - // remove the '*' linkedId that should be empty if it was created - if (MATCHALLLINKEDIDS.equals(linkedId) + // remove the '*' or 'open*' linkedId that should be empty if it was + // created + if ((MATCHALLLINKEDIDS.equals(linkedId) && linkedArgs.containsKey(linkedId)) + || (MATCHOPENEDLINKEDIDS.equals(linkedId) + && linkedArgs.containsKey(linkedId))) { linkedArgs.remove(linkedId); } @@ -535,8 +602,7 @@ public class ArgParser .toString(); } } - if (!linkedArgs.containsKey(defaultLinkedId)) - linkedArgs.put(defaultLinkedId, new ArgValuesMap()); + getOrCreateLinkedArgValuesMap(defaultLinkedId); return defaultLinkedId; } @@ -576,6 +642,10 @@ public class ArgParser { rest = rest.replace(LINKEDIDBASENAME, avm.getBasename()); } + if (rest.contains(LINKEDIDEXTENSION)) + { + rest = rest.replace(LINKEDIDEXTENSION, avm.getExtension()); + } if (rest.contains(LINKEDIDDIRNAME)) { rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname()); @@ -620,9 +690,24 @@ public class ArgParser return vals; } + public BootstrapArgs getBootstrapArgs() + { + return bootstrapArgs; + } + public boolean isSet(Arg a) { - return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a); + return a.hasOption(Opt.LINKED) ? isSetAtAll(a) : isSet(null, a); + } + + public boolean isSetAtAll(Arg a) + { + for (String linkedId : linkedOrder) + { + if (isSet(linkedId, a)) + return true; + } + return false; } public boolean isSet(String linkedId, Arg a) @@ -631,7 +716,7 @@ public class ArgParser return avm == null ? false : avm.containsArg(a); } - public boolean getBool(Arg a) + public boolean getBoolean(Arg a) { if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY)) { @@ -698,7 +783,7 @@ public class ArgParser } public static ArgParser parseArgFiles(List argFilenameGlobs, - boolean initsubstitutions) + boolean initsubstitutions, BootstrapArgs bsa) { List argFiles = new ArrayList<>(); @@ -708,11 +793,11 @@ public class ArgParser argFiles.addAll(FileUtils.getFilesFromGlob(pattern)); } - return parseArgFileList(argFiles, initsubstitutions); + return parseArgFileList(argFiles, initsubstitutions, bsa); } public static ArgParser parseArgFileList(List argFiles, - boolean initsubstitutions) + boolean initsubstitutions, BootstrapArgs bsa) { List argsList = new ArrayList<>(); for (File argFile : argFiles) @@ -740,7 +825,7 @@ public class ArgParser } // Third param "true" uses Opt.PRIVATE args --setargile=argfile and // --unsetargfile - return new ArgParser(argsList, initsubstitutions, true); + return new ArgParser(argsList, initsubstitutions, true, bsa); } protected static List readArgFile(File argFile) @@ -794,22 +879,38 @@ public class ArgParser Position pos, ArgValue av, SubVals sv, String key, String pref, String def) { + return getFromSubValArgOrPrefWithSubstitutions(null, avm, a, pos, av, + sv, key, pref, def); + } + + public static String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, + ArgValuesMap avm, Arg a, Position pos, ArgValue av, SubVals sv, + String key, String pref, String def) + { if (key == null) key = a.getName(); + String value = null; if (sv != null && sv.has(key) && sv.get(key) != null) - return sv.get(key); - if (avm != null && avm.containsArg(a)) + { + value = ap == null ? sv.get(key) + : sv.getWithSubstitutions(ap, avm.getLinkedId(), key); + } + else if (avm != null && avm.containsArg(a)) { if (pos == Position.FIRST && avm.getValue(a) != null) - return avm.getValue(a); + value = avm.getValue(a); else if (pos == Position.BEFORE && avm.getClosestPreviousArgValueOfArg(av, a) != null) - return avm.getClosestPreviousArgValueOfArg(av, a).getValue(); + value = avm.getClosestPreviousArgValueOfArg(av, a).getValue(); else if (pos == Position.AFTER && avm.getClosestNextArgValueOfArg(av, a) != null) - return avm.getClosestNextArgValueOfArg(av, a).getValue(); + value = avm.getClosestNextArgValueOfArg(av, a).getValue(); } - return pref != null ? Cache.getDefault(pref, def) : def; + else + { + value = pref != null ? Cache.getDefault(pref, def) : def; + } + return value; } public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a, @@ -821,154 +922,249 @@ public class ArgParser public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a, SubVals sv, String key, String pref, boolean def) { + if ((key == null && a == null) || (sv == null && a == null)) + return false; + + boolean usingArgKey = false; if (key == null) + { key = a.getName(); - if (sv != null && sv.has(key) && sv.get(key) != null) - return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); - if (avm != null && avm.containsArg(a)) - return avm.getBoolean(a); - return pref != null ? Cache.getDefault(pref, def) : def; - } + usingArgKey = true; + } - // the following methods look for the "*" linkedId and add the argvalue to all - // linkedId ArgValues if it does - private void addValue(String linkedId, ArgValues avs, SubVals sv, - String v, int argIndex, boolean doSubs) - { - Arg a = avs.arg(); - if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + String nokey = ArgParser.NEGATESTRING + key; + + // look for key or nokey in subvals first (if using Arg check options) + if (sv != null) { - for (String id : getLinkedIds()) + // check for true boolean + if (sv.has(key) && sv.get(key) != null) { - if (id == null || MATCHALLLINKEDIDS.equals(id)) - continue; - ArgValuesMap avm = linkedArgs.get(id); - if (a.hasOption(Opt.REQUIREINPUT) - && !avm.hasArgWithOption(Opt.INPUT)) - continue; - ArgValues tavs = avm.getOrCreateArgValues(a); - String val = v; - if (doSubs) + if (usingArgKey) { - val = makeSubstitutions(v, id); - sv = new SubVals(sv, val); + if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY))) + { + Console.debug( + "Looking for boolean in subval from non-boolean/non-unary Arg " + + a.getName()); + return false; + } } - tavs.addValue(sv, val, argIndex); - finaliseStoringArgValue(id, tavs); + return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); } - } - else - { - String val = v; - if (doSubs) + + // check for negative boolean (subval "no..." will be "true") + if (sv.has(nokey) && sv.get(nokey) != null) { - val = makeSubstitutions(v, linkedId); - sv = new SubVals(sv, val); + if (usingArgKey) + { + if (!(a.hasOption(Opt.BOOLEAN))) + { + Console.debug( + "Looking for negative boolean in subval from non-boolean Arg " + + a.getName()); + return false; + } + } + return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true"); } - avs.addValue(sv, val, argIndex); - finaliseStoringArgValue(linkedId, avs); } + + // check argvalues + if (avm != null && avm.containsArg(a)) + return avm.getBoolean(a); + + // return preference or default + return pref != null ? Cache.getDefault(pref, def) : def; + } + + // the following methods look for the "*" linkedId and add the argvalue to all + // linkedId ArgValues if it does. + // This version inserts the subvals sv into all created values + private void addValue(String linkedId, ArgValues avs, SubVals sv, + String v, int argIndex, boolean doSubs) + { + this.argValueOperation(Op.ADDVALUE, linkedId, avs, sv, v, false, + argIndex, doSubs); } private void addValue(String linkedId, ArgValues avs, String v, int argIndex, boolean doSubs) { - Arg a = avs.arg(); - if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) - { - for (String id : getLinkedIds()) - { - if (id == null || MATCHALLLINKEDIDS.equals(id)) - continue; - ArgValuesMap avm = linkedArgs.get(id); - // don't set an output if there isn't an input - if (a.hasOption(Opt.REQUIREINPUT) - && !avm.hasArgWithOption(Opt.INPUT)) - continue; - ArgValues tavs = avm.getOrCreateArgValues(a); - String val = doSubs ? makeSubstitutions(v, id) : v; - tavs.addValue(val, argIndex); - finaliseStoringArgValue(id, tavs); - } - } - else - { - String val = doSubs ? makeSubstitutions(v, linkedId) : v; - avs.addValue(val, argIndex); - finaliseStoringArgValue(linkedId, avs); - } + this.argValueOperation(Op.ADDVALUE, linkedId, avs, null, v, false, + argIndex, doSubs); } private void setBoolean(String linkedId, ArgValues avs, boolean b, int argIndex) { - Arg a = avs.arg(); - if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) - { - for (String id : getLinkedIds()) - { - if (id == null || MATCHALLLINKEDIDS.equals(id)) - continue; - ArgValuesMap avm = linkedArgs.get(id); - if (a.hasOption(Opt.REQUIREINPUT) - && !avm.hasArgWithOption(Opt.INPUT)) - continue; - ArgValues tavs = avm.getOrCreateArgValues(a); - tavs.setBoolean(b, argIndex); - finaliseStoringArgValue(id, tavs); - } - } - else - { - avs.setBoolean(b, argIndex); - finaliseStoringArgValue(linkedId, avs); - } + this.argValueOperation(Op.SETBOOLEAN, linkedId, avs, null, null, b, + argIndex, false); } private void setNegated(String linkedId, ArgValues avs, boolean b) { + this.argValueOperation(Op.SETNEGATED, linkedId, avs, null, null, b, 0, + false); + } + + private void incrementCount(String linkedId, ArgValues avs) + { + this.argValueOperation(Op.INCREMENTCOUNT, linkedId, avs, null, null, + false, 0, false); + } + + private enum Op + { + ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT + } + + // The following operations look for the "*" and "open*" linkedIds and add the + // argvalue to all appropriate linkedId ArgValues if it does. + // If subvals are supplied, they are inserted into all new set values. + private void argValueOperation(Op op, String linkedId, ArgValues avs, + SubVals sv, String v, boolean b, int argIndex, boolean doSubs) + { Arg a = avs.arg(); - if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + + List wildcardLinkedIds = null; + if (a.hasOption(Opt.ALLOWALL)) { - for (String id : getLinkedIds()) + switch (linkedId) { - if (id == null || MATCHALLLINKEDIDS.equals(id)) - continue; - ArgValuesMap avm = linkedArgs.get(id); - if (a.hasOption(Opt.REQUIREINPUT) - && !avm.hasArgWithOption(Opt.INPUT)) - continue; - ArgValues tavs = avm.getOrCreateArgValues(a); - tavs.setNegated(b); + case MATCHALLLINKEDIDS: + wildcardLinkedIds = getLinkedIds(); + break; + case MATCHOPENEDLINKEDIDS: + wildcardLinkedIds = this.storedLinkedIds; + break; } } - else + + // if we're not a wildcard linkedId and the arg is marked to be stored, add + // to storedLinkedIds + if (linkedId != null && wildcardLinkedIds == null + && a.hasOption(Opt.STORED) + && !storedLinkedIds.contains(linkedId)) { - avs.setNegated(b); + storedLinkedIds.add(linkedId); } - } - private void incrementCount(String linkedId, ArgValues avs) - { - Arg a = avs.arg(); - if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + // if we are a wildcard linkedId, apply the arg and value to all appropriate + // linkedIds + if (wildcardLinkedIds != null) { - for (String id : getLinkedIds()) + for (String id : wildcardLinkedIds) { - if (id == null || MATCHALLLINKEDIDS.equals(id)) + // skip incorrectly stored wildcard ids! + if (id == null || MATCHALLLINKEDIDS.equals(id) + || MATCHOPENEDLINKEDIDS.equals(id)) continue; ArgValuesMap avm = linkedArgs.get(id); + // don't set an output if there isn't an input if (a.hasOption(Opt.REQUIREINPUT) && !avm.hasArgWithOption(Opt.INPUT)) continue; + ArgValues tavs = avm.getOrCreateArgValues(a); - tavs.incrementCount(); + switch (op) + { + + case ADDVALUE: + String val = v; + if (sv != null) + { + if (doSubs) + { + val = makeSubstitutions(v, id); + sv = new SubVals(sv, val); + } + tavs.addValue(sv, val, argIndex, true); + } + else + { + if (doSubs) + { + val = makeSubstitutions(v, id); + } + tavs.addValue(val, argIndex, true); + } + finaliseStoringArgValue(id, tavs); + break; + + case SETBOOLEAN: + tavs.setBoolean(b, argIndex, true); + finaliseStoringArgValue(id, tavs); + break; + + case SETNEGATED: + tavs.setNegated(b, true); + break; + + case INCREMENTCOUNT: + tavs.incrementCount(); + break; + + default: + break; + + } + } } - else + else // no wildcard linkedId -- do it simpler { - avs.incrementCount(); + switch (op) + { + case ADDVALUE: + String val = v; + if (sv != null) + { + if (doSubs) + { + val = makeSubstitutions(v, linkedId); + sv = new SubVals(sv, val); + } + avs.addValue(sv, val, argIndex, false); + } + else + { + if (doSubs) + { + val = makeSubstitutions(v, linkedId); + } + avs.addValue(val, argIndex, false); + } + finaliseStoringArgValue(linkedId, avs); + break; + + case SETBOOLEAN: + avs.setBoolean(b, argIndex, false); + finaliseStoringArgValue(linkedId, avs); + break; + + case SETNEGATED: + avs.setNegated(b, false); + break; + + case INCREMENTCOUNT: + avs.incrementCount(); + break; + + default: + break; + } } } + private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId) + { + if (linkedArgs.containsKey(linkedId) + && linkedArgs.get(linkedId) != null) + return linkedArgs.get(linkedId); + + linkedArgs.put(linkedId, new ArgValuesMap(linkedId)); + return linkedArgs.get(linkedId); + } + } \ No newline at end of file