X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fbin%2Fargparser%2FArgParser.java;h=155f69e1af586ed3b54991cea80c95fb11a7714d;hb=3b74463d9ba726384240d7707b6ea416a24c6b59;hp=3ca5d3d4f87ddb389c9647be7f4b6af9beadf568;hpb=135ff4955524fd15e9558364c1e94183f02fd847;p=jalview.git diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 3ca5d3d..155f69e 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -31,91 +31,177 @@ import java.util.EnumSet; import java.util.Enumeration; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import jalview.bin.Cache; import jalview.bin.Console; import jalview.bin.Jalview; +import jalview.bin.Jalview.ExitCode; import jalview.bin.argparser.Arg.Opt; +import jalview.bin.argparser.Arg.Type; import jalview.util.FileUtils; import jalview.util.HttpUtils; public class ArgParser { + protected static final String SINGLEDASH = "-"; + protected static final String DOUBLEDASH = "--"; - protected static final char EQUALS = '='; + public static final char EQUALS = '='; + + public static final String STDOUTFILENAME = "-"; protected static final String NEGATESTRING = "no"; - // the default linked id prefix used for no id (not even square braces) + /** + * the default linked id prefix used for no id (ie when not even square braces + * are provided) + */ protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:"; - // the linkedId string used to match all linkedIds seen so far + /** + * the linkedId string used to match all linkedIds seen so far + */ protected static final String MATCHALLLINKEDIDS = "*"; - // the counter added to the default linked id prefix + /** + * 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; - // the substitution string used to use the defaultLinkedIdCounter + /** + * the substitution string used to use the defaultLinkedIdCounter + */ private static final String DEFAULTLINKEDIDCOUNTER = "{}"; - // the counter added to the default linked id prefix. NOW using - // linkedIdAutoCounter - // private int openLinkedIdCounter = 0; - - // the linked id prefix used for --open files. NOW the same as DEFAULT + /** + * the linked id prefix used for --open files. NOW the same as DEFAULT + */ protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX; - // the counter used for {n} substitutions + /** + * the counter used for {n} substitutions + */ private int linkedIdAutoCounter = 0; - // the linked id substitution string used to increment the idCounter (and use - // the incremented value) + /** + * the linked id substitution string used to increment the idCounter (and use + * the incremented value) + */ private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}"; - // the linked id substitution string used to use the idCounter + /** + * 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 base filename of --append - // or --open + /** + * 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}"; - // the linked id substitution string used to use the dir path of --append - // or --open + /** + * the linked id substitution string used to use the dir path of --append or + * --open + */ private static final String LINKEDIDDIRNAME = "{dirname}"; - // the current argfile + /** + * On-the-fly substitution (not made at argument parsing time)! the current + * structure filename extension + */ + private static final String STRUCTUREEXTENSION = "{structureextension}"; + + /** + * On-the-fly substitution (not made at argument parsing time)! the current + * structure filename base + */ + private static final String STRUCTUREBASENAME = "{structurebasename}"; + + /** + * On-the-fly substitution (not made at argument parsing time)! the current + * structure filename dir path + */ + private static final String STRUCTUREDIRNAME = "{structuredirname}"; + + /** + * On-the-fly substitution (not made at argument parsing time)! increment the + * on-the-fly counter and substitute the incremented value + */ + private static final String INCREMENTONTHEFLYCOUNTER = "{++m}"; + + /** + * On-the-fly substitution (not made at argument parsing time)! the current + * substitute with the on-the-fly counter + */ + private static final String ONTHEFLYCOUNTER = "{m}"; + + /** + * the string used for on-the-fly structure filename substitutions + */ + private String currentStructureFilename = null; + + /** + * the counter used for on-the-fly {m} substitutions + */ + private int ontheflyCounter = 0; + + /** + * the current argfile + */ private String argFile = null; - // the linked id substitution string used to use the dir path of the latest - // --argfile name + /** + * the linked id substitution string used to use the dir path of the latest + */ + /** --argfile name */ private static final String ARGFILEBASENAME = "{argfilebasename}"; - // the linked id substitution string used to use the dir path of the latest - // --argfile name + /** + * the linked id substitution string used to use the dir path of the latest + * --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 + /** + * flag to say whether {n} subtitutions in output filenames should be made. + * Turn on and off with --substitutions and --nosubstitutions Start with it on + */ private boolean substitutions = true; - // flag to say whether the default linkedId is the current default linked id - // or ALL linkedIds + /** + * flag to say whether the default linkedId is the current default linked id + * + * or ALL linkedIds + */ private boolean allLinkedIds = false; + /** + * flag to say whether the structure arguments should be applied to all + * structures with this linked id + */ + private boolean allStructures = 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 = '#'; @@ -124,6 +210,15 @@ public class ArgParser private BootstrapArgs bootstrapArgs = null; + private boolean oldArguments = false; + + private boolean mixedArguments = false; + + /** + * saved examples of mixed arguments + */ + private String[] mixedExamples = new String[] { null, null }; + static { argMap = new HashMap<>(); @@ -134,8 +229,7 @@ public class ArgParser if (argMap.containsKey(argName)) { Console.warn("Trying to add argument name multiple times: '" - + argName + "'"); // RESTORE THIS WHEN - // MERGED + + argName + "'"); if (argMap.get(argName) != a) { Console.error( @@ -159,12 +253,15 @@ public class ArgParser 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 - // arguments (which are the expanded globbed filenames) that need to be - // 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). ) + /* + * Make a mutable new ArrayList so that shell globbing parser works. + * (When shell file globbing is used, there are a sequence of non-Arg + * arguments (which are the expanded globbed filenames) that need to be + * 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) as + * that is not mutable. ) + */ this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false, bsa); } @@ -186,23 +283,48 @@ public class ArgParser if (arg.startsWith(DOUBLEDASH)) { dd = true; - break; + if (mixedExamples[1] == null) + { + mixedExamples[1] = arg; + } } - else if (arg.startsWith("-") || arg.equals("open")) + else if ((arg.startsWith("-") && !arg.equals(STDOUTFILENAME)) + || arg.equals("open")) { d = true; + if (mixedExamples[0] == null) + { + mixedExamples[0] = arg; + } } } - if (d && !dd) + if (d) + { + if (dd) + { + mixedArguments = true; + } + else + { + oldArguments = true; + } + } + + if (oldArguments || mixedArguments) { // leave it to the old style -- parse an empty list parse(new ArrayList(), false, false); return; } + if (bsa != null) + { this.bootstrapArgs = bsa; + } else + { this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args); + } parse(args, initsubstitutions, allowPrivate); } @@ -210,35 +332,42 @@ public class ArgParser boolean allowPrivate) { this.substitutions = initsubstitutions; - boolean openEachInitialFilenames = true; - for (int i = 0; i < args.size(); i++) - { - String arg = args.get(i); - // If the first arguments do not start with "--" or "-" or is not "open" - // and` is a filename that exists it is probably a file/list of files to - // open so we fake an Arg.OPEN argument and when adding files only add the - // single arg[i] and increment the defaultLinkedIdCounter so that each of - // these files is opened separately. - if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH) - && !arg.startsWith("-") && !arg.equals("open") - && (new File(arg).exists() - || HttpUtils.startsWithHttpOrHttps(arg))) - { - arg = Arg.OPEN.argString(); - } - else + /* + * If the first argument does not start with "--" or "-" or is not "open", + * and is a filename that exists or a URL, it is probably a file/list of + * files to open so we insert an Arg.OPEN argument before it. This will + * mean the list of files at the start of the arguments are all opened + * separately. + */ + if (args.size() > 0) + { + String arg0 = args.get(0); + if (arg0 != null + && (!arg0.startsWith(DOUBLEDASH) && !arg0.startsWith("-") + && !arg0.equals("open") && (new File(arg0).exists() + || HttpUtils.startsWithHttpOrHttps(arg0)))) { - openEachInitialFilenames = false; + // insert "--open" at the start + args.add(0, Arg.OPEN.argString()); } + } - String argName = null; - String val = null; - List globVals = null; // for Opt.GLOB only - SubVals globSubVals = null; // also for use by Opt.GLOB only - String linkedId = null; + for (int i = 0; i < args.size(); i++) + { + String arg = args.get(i); + + // look for double-dash, e.g. --arg if (arg.startsWith(DOUBLEDASH)) { + String argName = null; + String val = null; + List globVals = null; // for Opt.GLOB only + SubVals globSubVals = null; // also for use by Opt.GLOB only + String linkedId = null; + Type type = null; + + // look for equals e.g. --arg=value int equalPos = arg.indexOf(EQUALS); if (equalPos > -1) { @@ -249,24 +378,67 @@ public class ArgParser { argName = arg.substring(DOUBLEDASH.length()); } + + // look for linked ID e.g. --arg[linkedID] int idOpen = argName.indexOf('['); int idClose = argName.indexOf(']'); - if (idOpen > -1 && idClose == argName.length() - 1) { linkedId = argName.substring(idOpen + 1, idClose); argName = argName.substring(0, idOpen); } + // look for type modification e.g. --help-opening + int dashPos = argName.indexOf(SINGLEDASH); + if (dashPos > -1) + { + String potentialArgName = argName.substring(0, dashPos); + Arg potentialArg = argMap.get(potentialArgName); + if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE)) + { + String typeName = argName.substring(dashPos + 1); + try + { + type = Type.valueOf(typeName); + } catch (IllegalArgumentException e) + { + type = Type.INVALID; + } + argName = argName.substring(0, dashPos); + } + } + Arg a = argMap.get(argName); - // check for boolean prepended by "no" + // check for boolean prepended by "no" e.g. --nowrap boolean negated = false; - if (a == null && argName.startsWith(NEGATESTRING) && argMap - .containsKey(argName.substring(NEGATESTRING.length()))) + if (a == null) { - argName = argName.substring(NEGATESTRING.length()); - a = argMap.get(argName); - negated = true; + if (argName.startsWith(NEGATESTRING) && argMap + .containsKey(argName.substring(NEGATESTRING.length()))) + { + argName = argName.substring(NEGATESTRING.length()); + a = argMap.get(argName); + negated = true; + } + else + { + // after all other args, look for Opt.PREFIXKEV args if still not + // found + for (Arg potentialArg : EnumSet.allOf(Arg.class)) + { + if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null + && argName.startsWith(potentialArg.getName()) + && equalPos > -1) + { + val = argName.substring(potentialArg.getName().length()) + + EQUALS + val; + argName = argName.substring(0, + potentialArg.getName().length()); + a = potentialArg; + break; + } + } + } } // check for config errors @@ -274,10 +446,12 @@ public class ArgParser { // arg not found Console.error("Argument '" + arg + "' not recognised. Exiting."); - Jalview.exit("Invalid argument used." + System.lineSeparator() - + "Use" + System.lineSeparator() + "jalview " - + Arg.HELP.argString() + System.lineSeparator() - + "for a usage statement.", 13); + Jalview.exit( + "Invalid argument used." + System.lineSeparator() + "Use" + + System.lineSeparator() + "jalview " + + Arg.HELP.argString() + System.lineSeparator() + + "for a usage statement.", + ExitCode.INVALID_ARGUMENT); continue; } if (a.hasOption(Opt.PRIVATE) && !allowPrivate) @@ -334,7 +508,7 @@ public class ArgParser { // There is no "=" so value is next arg or args (possibly shell // glob-expanded) - if ((openEachInitialFilenames ? i : i + 1) >= args.size()) + if (i + 1 >= args.size()) { // no value to take for arg, which wants a value Console.error("Argument '" + a.getName() @@ -349,8 +523,7 @@ public class ArgParser { // if this is the first argument with a file list at the start of // the args we add filenames from index i instead of i+1 - globVals = getShellGlobbedFilenameValues(a, args, - openEachInitialFilenames ? i : i + 1); + globVals = getShellGlobbedFilenameValues(a, args, i + 1); } else { @@ -381,6 +554,16 @@ public class ArgParser { allLinkedIds = !negated; } + else if (a == Arg.ALLSTRUCTURES) + { + allStructures = !negated; + } + + if (a.hasOption(Opt.STORED)) + { + // reset the lastOpenedLinkedIds list + this.storedLinkedIds = new ArrayList<>(); + } // this is probably only Arg.NEW and Arg.OPEN if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER)) @@ -390,28 +573,34 @@ public class ArgParser } String autoCounterString = null; - boolean usingAutoCounterLinkedId = false; String defaultLinkedId = defaultLinkedId(false); boolean usingDefaultLinkedId = false; if (a.hasOption(Opt.LINKED)) { if (linkedId == null) { - if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL) - && val.startsWith(OUTPUTWILDCARD)) + if (a.hasOption(Opt.OUTPUTFILE) && a.hasOption(Opt.ALLOWMULTIID) + && val.contains(MATCHALLLINKEDIDS)) { - // --output=*.ext is shorthand for --all --output {basename}.ext + // --output=*.ext is shorthand for --output {basename}.ext + // --output=*/*.ext is shorthand for + // --output {dirname}/{basename}.ext // (or --image=*.ext) - allLinkedIds = true; - linkedId = MATCHALLLINKEDIDS; - String oldval = val; - val = LINKEDIDBASENAME - + val.substring(OUTPUTWILDCARD.length() - 1); + linkedId = allLinkedIds ? MATCHALLLINKEDIDS + : MATCHOPENEDLINKEDIDS; + val = FileUtils.convertWildcardsToPath(val, MATCHALLLINKEDIDS, + LINKEDIDDIRNAME, LINKEDIDBASENAME); } - else if (allLinkedIds && a.hasOption(Opt.ALLOWALL)) + else if (allLinkedIds && a.hasOption(Opt.ALLOWMULTIID)) { linkedId = MATCHALLLINKEDIDS; } + else if (a.hasOption(Opt.ALLOWMULTIID) + && this.storedLinkedIds != null + && this.storedLinkedIds.size() > 0) + { + linkedId = MATCHOPENEDLINKEDIDS; + } else { // use default linkedId for linked arguments @@ -421,25 +610,26 @@ public class ArgParser + arg); } } - else if (linkedId.contains(LINKEDIDAUTOCOUNTER)) - { - // turn {n} to the autoCounter - autoCounterString = Integer.toString(linkedIdAutoCounter); - linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER, - autoCounterString); - usingAutoCounterLinkedId = true; - Console.debug( - "Changing linkedId to '" + linkedId + "' from " + arg); - } - else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER)) + else { - // turn {++n} to the incremented autoCounter - autoCounterString = Integer.toString(++linkedIdAutoCounter); - linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER, - autoCounterString); - usingAutoCounterLinkedId = true; - Console.debug( - "Changing linkedId to '" + linkedId + "' from " + arg); + if (linkedId.contains(LINKEDIDAUTOCOUNTER)) + { + // turn {n} to the autoCounter + autoCounterString = Integer.toString(linkedIdAutoCounter); + linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER, + autoCounterString); + Console.debug("Changing linkedId to '" + linkedId + "' from " + + arg); + } + if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER)) + { + // turn {++n} to the incremented autoCounter + autoCounterString = Integer.toString(++linkedIdAutoCounter); + linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER, + autoCounterString); + Console.debug("Changing linkedId to '" + linkedId + "' from " + + arg); + } } } @@ -459,8 +649,9 @@ public class ArgParser } // check for unique id - SubVals idsv = new SubVals(val); - String id = idsv.get(ArgValues.ID); + SubVals subvals = new SubVals(val); + boolean addNewSubVals = false; + String id = subvals.get(ArgValues.ID); if (id != null && avm.hasId(a, id)) { Console.error("Argument '" + a.argString() @@ -468,10 +659,20 @@ public class ArgParser continue; } - /* TODO - * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*" - * DONE, need to check - */ + // set allstructures to all non-primary structure options in this linked + // id if --allstructures has been set + if (allStructures && (a.getType() == Type.STRUCTURE + // || a.getType() == Type.STRUCTUREIMAGE) + ) && !a.hasOption(Opt.PRIMARY)) + { + if (!subvals.has(Arg.ALLSTRUCTURES.getName())) + // && !subvals.has("structureid")) + { + subvals.put(Arg.ALLSTRUCTURES.getName(), "true"); + addNewSubVals = true; + } + } + ArgValues avs = avm.getOrCreateArgValues(a); // store appropriate String value(s) @@ -485,7 +686,7 @@ public class ArgParser { String v = gve.nextElement(); SubVals vsv = new SubVals(globSubVals, v); - addValue(linkedId, avs, vsv, v, argIndex++, true); + addValue(linkedId, type, avs, vsv, v, argIndex++, true); // if we're using defaultLinkedId and the arg increments the // counter: if (gve.hasMoreElements() && usingDefaultLinkedId @@ -501,21 +702,25 @@ public class ArgParser } else { - addValue(linkedId, avs, val, argIndex, true); + // addValue(linkedId, type, avs, val, argIndex, true); + addValue(linkedId, type, avs, addNewSubVals ? subvals : null, + val, argIndex, true); } } else if (a.hasOption(Opt.BOOLEAN)) { - setBoolean(linkedId, avs, !negated, argIndex); + setBoolean(linkedId, type, avs, !negated, argIndex); setNegated(linkedId, avs, negated); } else if (a.hasOption(Opt.UNARY)) { - setBoolean(linkedId, avs, true, argIndex); + setBoolean(linkedId, type, 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) + || MATCHOPENEDLINKEDIDS.equals(linkedId)) && linkedArgs.containsKey(linkedId)) { linkedArgs.remove(linkedId); @@ -563,6 +768,12 @@ public class ArgParser public String makeSubstitutions(String val, String linkedId) { + return makeSubstitutions(val, linkedId, false); + } + + public String makeSubstitutions(String val, String linkedId, + boolean onthefly) + { if (!this.substitutions || val == null) return val; @@ -582,14 +793,20 @@ public class ArgParser rest = val; } if (rest.contains(LINKEDIDAUTOCOUNTER)) + { rest = rest.replace(LINKEDIDAUTOCOUNTER, String.valueOf(linkedIdAutoCounter)); + } if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER)) + { rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER, String.valueOf(++linkedIdAutoCounter)); + } if (rest.contains(DEFAULTLINKEDIDCOUNTER)) + { rest = rest.replace(DEFAULTLINKEDIDCOUNTER, String.valueOf(defaultLinkedIdCounter)); + } ArgValuesMap avm = linkedArgs.get(linkedId); if (avm != null) { @@ -597,6 +814,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()); @@ -615,6 +836,32 @@ public class ArgParser FileUtils.getDirname(new File(argFile))); } } + if (onthefly) + { + if (rest.contains(ONTHEFLYCOUNTER)) + { + rest = rest.replace(ONTHEFLYCOUNTER, + String.valueOf(ontheflyCounter)); + } + if (rest.contains(INCREMENTONTHEFLYCOUNTER)) + { + rest = rest.replace(INCREMENTONTHEFLYCOUNTER, + String.valueOf(++ontheflyCounter)); + } + if (currentStructureFilename != null) + { + if (rest.contains(STRUCTUREBASENAME)) + { + rest = rest.replace(STRUCTUREBASENAME, FileUtils + .getBasename(new File(currentStructureFilename))); + } + if (rest.contains(STRUCTUREDIRNAME)) + { + rest = rest.replace(STRUCTUREDIRNAME, + FileUtils.getDirname(new File(currentStructureFilename))); + } + } + } return new StringBuilder(subvals).append(rest).toString(); } @@ -757,7 +1004,7 @@ public class ArgParser { String message = Arg.ARGFILE.argString() + EQUALS + "\"" + argFile.getPath() + "\": File does not exist."; - Jalview.exit(message, 2); + Jalview.exit(message, ExitCode.FILE_NOT_FOUND); } try { @@ -771,7 +1018,7 @@ public class ArgParser { String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath() + "\": File could not be read."; - Jalview.exit(message, 3); + Jalview.exit(message, ExitCode.FILE_NOT_READABLE); } } // Third param "true" uses Opt.PRIVATE args --setargile=argfile and @@ -797,287 +1044,250 @@ public class ArgParser String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath() + "\": File could not be read."; Console.debug(message, e); - Jalview.exit(message, 3); + Jalview.exit(message, ExitCode.FILE_NOT_READABLE); } } return args; } - public static enum Position + // 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, Type type, ArgValues avs, + SubVals sv, String v, int argIndex, boolean doSubs) { - FIRST, BEFORE, AFTER + this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, sv, v, false, + argIndex, doSubs); } - // get from following Arg of type a or subval of same name (lowercase) - public static String getValueFromSubValOrArg(ArgValuesMap avm, - ArgValue av, Arg a, SubVals sv) + private void setBoolean(String linkedId, Type type, ArgValues avs, + boolean b, int argIndex) { - return getFromSubValArgOrPref(avm, av, a, sv, null, null, null); + this.argValueOperation(Op.SETBOOLEAN, linkedId, type, avs, null, null, + b, argIndex, false); } - // get from following Arg of type a or subval key or preference pref or - // default def - public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av, - Arg a, SubVals sv, String key, String pref, String def) + private void setNegated(String linkedId, ArgValues avs, boolean b) { - return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref, - def); + this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null, + b, 0, false); } - // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE) - // Arg of type a or subval key or preference pref or default def - public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a, - Position pos, ArgValue av, SubVals sv, String key, String pref, - String def) + private void incrementCount(String linkedId, ArgValues avs) { - return getFromSubValArgOrPrefWithSubstitutions(null, avm, a, pos, av, - sv, key, pref, def); + this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null, + null, false, 0, false); } - public static String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, - ArgValuesMap avm, Arg a, Position pos, ArgValue av, SubVals sv, - String key, String pref, String def) + private enum Op { - if (key == null) - key = a.getName(); - String value = null; - if (sv != null && sv.has(key) && sv.get(key) != null) - { - 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) - value = avm.getValue(a); - else if (pos == Position.BEFORE - && avm.getClosestPreviousArgValueOfArg(av, a) != null) - value = avm.getClosestPreviousArgValueOfArg(av, a).getValue(); - else if (pos == Position.AFTER - && avm.getClosestNextArgValueOfArg(av, a) != null) - value = avm.getClosestNextArgValueOfArg(av, a).getValue(); - } - else - { - value = pref != null ? Cache.getDefault(pref, def) : def; - } - return value; + ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT } - public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a, - SubVals sv) + private void argValueOperation(Op op, String linkedId, Type type, + ArgValues avs, SubVals sv, String v, boolean b, int argIndex, + boolean doSubs) { - return getFromSubValArgOrPref(avm, a, sv, null, null, false); + // default to merge subvals if subvals are provided + argValueOperation(op, linkedId, type, avs, sv, true, v, b, argIndex, + doSubs); } - public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a, - SubVals sv, String key, String pref, boolean def) + /** + * 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. + * + * @param op + * The ArgParser.Op operation + * @param linkedId + * The String linkedId from the ArgValuesMap + * @param type + * The Arg.Type to attach to this ArgValue + * @param avs + * The ArgValues for this linkedId + * @param sv + * Use these SubVals on the ArgValue + * @param merge + * Merge the SubVals with any existing on the value. False will + * replace unless sv is null + * @param v + * The value of the ArgValue (may contain subvals). + * @param b + * The boolean value of the ArgValue. + * @param argIndex + * The argIndex for the ArgValue. + * @param doSubs + * Whether to perform substitutions on the subvals and value. + */ + private void argValueOperation(Op op, String linkedId, Type type, + ArgValues avs, SubVals sv, boolean merge, String v, boolean b, + int argIndex, boolean doSubs) { - if ((key == null && a == null) || (sv == null && a == null)) - return false; - - boolean usingArgKey = false; - if (key == null) - { - key = a.getName(); - usingArgKey = true; - } - - String nokey = ArgParser.NEGATESTRING + key; + Arg a = avs.arg(); - // look for key or nokey in subvals first (if using Arg check options) - if (sv != null) + List wildcardLinkedIds = null; + if (a.hasOption(Opt.ALLOWMULTIID)) { - // check for true boolean - if (sv.has(key) && sv.get(key) != null) + switch (linkedId) { - if (usingArgKey) - { - 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; - } - } - return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); - } - - // check for negative boolean (subval "no..." will be "true") - if (sv.has(nokey) && sv.get(nokey) != null) - { - 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"); + case MATCHALLLINKEDIDS: + wildcardLinkedIds = getLinkedIds(); + break; + case MATCHOPENEDLINKEDIDS: + wildcardLinkedIds = this.storedLinkedIds; + break; } } - // check argvalues - if (avm != null && avm.containsArg(a)) - return avm.getBoolean(a); - - // return preference or default - return pref != null ? Cache.getDefault(pref, def) : def; - } + // 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)) + { + storedLinkedIds.add(linkedId); + } - // 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)) + // 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); - String val = v; - if (doSubs) + switch (op) { - val = makeSubstitutions(v, id); - sv = new SubVals(sv, val); + + case ADDVALUE: + String val = v; + if (sv != null) + { + if (doSubs) + { + sv = new SubVals(sv, val, merge); + val = makeSubstitutions(sv.getContent(), id); + } + tavs.addValue(sv, type, val, argIndex, true); + } + else + { + if (doSubs) + { + val = makeSubstitutions(v, id); + } + tavs.addValue(type, val, argIndex, true); + } + finaliseStoringArgValue(id, tavs); + break; + + case SETBOOLEAN: + tavs.setBoolean(type, b, argIndex, true); + finaliseStoringArgValue(id, tavs); + break; + + case SETNEGATED: + tavs.setNegated(b, true); + break; + + case INCREMENTCOUNT: + tavs.incrementCount(); + break; + + default: + break; + } - tavs.addValue(sv, val, argIndex); - finaliseStoringArgValue(id, tavs); + } } - else + else // no wildcard linkedId -- do it simpler { - String val = v; - if (doSubs) + switch (op) { - val = makeSubstitutions(v, linkedId); - sv = new SubVals(sv, val); + case ADDVALUE: + String val = v; + if (sv != null) + { + if (doSubs) + { + val = makeSubstitutions(v, linkedId); + sv = new SubVals(sv, val); + } + avs.addValue(sv, type, val, argIndex, false); + } + else + { + if (doSubs) + { + val = makeSubstitutions(v, linkedId); + } + avs.addValue(type, val, argIndex, false); + } + finaliseStoringArgValue(linkedId, avs); + break; + + case SETBOOLEAN: + avs.setBoolean(type, b, argIndex, false); + finaliseStoringArgValue(linkedId, avs); + break; + + case SETNEGATED: + avs.setNegated(b, false); + break; + + case INCREMENTCOUNT: + avs.incrementCount(); + break; + + default: + break; } - avs.addValue(sv, val, argIndex); - finaliseStoringArgValue(linkedId, avs); } } - private void addValue(String linkedId, ArgValues avs, String v, - int argIndex, boolean doSubs) + private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId) { - 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); - } + if (linkedArgs.containsKey(linkedId) + && linkedArgs.get(linkedId) != null) + return linkedArgs.get(linkedId); + + linkedArgs.put(linkedId, new ArgValuesMap(linkedId)); + return linkedArgs.get(linkedId); } - private void setBoolean(String linkedId, ArgValues avs, boolean b, - int argIndex) + public boolean isOldStyle() { - 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); - } + return oldArguments; } - private void setNegated(String linkedId, ArgValues avs, boolean b) + public boolean isMixedStyle() { - 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.setNegated(b); - } - } - else - { - avs.setNegated(b); - } + return mixedArguments; } - private void incrementCount(String linkedId, ArgValues avs) + public String[] getMixedExamples() { - 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.incrementCount(); - } - } - else - { - avs.incrementCount(); - } + return mixedExamples; } - private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId) + public void setStructureFilename(String s) { - if (linkedArgs.containsKey(linkedId) - && linkedArgs.get(linkedId) != null) - return linkedArgs.get(linkedId); - - linkedArgs.put(linkedId, new ArgValuesMap(linkedId)); - return linkedArgs.get(linkedId); + this.currentStructureFilename = s; } } \ No newline at end of file