2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.bin.argparser;
24 import java.io.IOException;
25 import java.nio.file.Files;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.EnumSet;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Locale;
37 import jalview.bin.Cache;
38 import jalview.bin.Console;
39 import jalview.bin.Jalview;
40 import jalview.bin.argparser.Arg.Opt;
41 import jalview.util.FileUtils;
42 import jalview.util.HttpUtils;
44 public class ArgParser
46 protected static final String DOUBLEDASH = "--";
48 protected static final char EQUALS = '=';
50 protected static final String NEGATESTRING = "no";
52 // the default linked id prefix used for no id (not even square braces)
53 protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
55 // the linkedId string used to match all linkedIds seen so far
56 protected static final String MATCHALLLINKEDIDS = "*";
58 // the counter added to the default linked id prefix
59 private int defaultLinkedIdCounter = 0;
61 // the substitution string used to use the defaultLinkedIdCounter
62 private static final String DEFAULTLINKEDIDCOUNTER = "{}";
64 // the counter added to the default linked id prefix. NOW using
65 // linkedIdAutoCounter
66 // private int openLinkedIdCounter = 0;
68 // the linked id prefix used for --open files. NOW the same as DEFAULT
69 protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX;
71 // the counter used for {n} substitutions
72 private int linkedIdAutoCounter = 0;
74 // the linked id substitution string used to increment the idCounter (and use
75 // the incremented value)
76 private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}";
78 // the linked id substitution string used to use the idCounter
79 private static final String LINKEDIDAUTOCOUNTER = "{n}";
81 // the linked id substitution string used to use the base filename of --append
83 private static final String LINKEDIDBASENAME = "{basename}";
85 // the linked id substitution string used to use the dir path of --append
87 private static final String LINKEDIDDIRNAME = "{dirname}";
89 // the current argfile
90 private String argFile = null;
92 // the linked id substitution string used to use the dir path of the latest
94 private static final String ARGFILEBASENAME = "{argfilebasename}";
96 // the linked id substitution string used to use the dir path of the latest
98 private static final String ARGFILEDIRNAME = "{argfiledirname}";
100 // flag to say whether {n} subtitutions in output filenames should be made.
101 // Turn on and off with --subs and --nosubs
102 private boolean substitutions = false;
104 // flag to say whether the default linkedId is the current default linked id
106 private boolean allLinkedIds = false;
108 protected static final Map<String, Arg> argMap;
110 protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
112 protected List<String> linkedOrder = new ArrayList<>();
114 protected List<Arg> argList = new ArrayList<>();
116 private static final char ARGFILECOMMENT = '#';
118 private int argIndex = 0;
122 argMap = new HashMap<>();
123 for (Arg a : EnumSet.allOf(Arg.class))
125 for (String argName : a.getNames())
127 if (argMap.containsKey(argName))
129 Console.warn("Trying to add argument name multiple times: '"
130 + argName + "'"); // RESTORE THIS WHEN
132 if (argMap.get(argName) != a)
135 "Trying to add argument name multiple times for different Args: '"
136 + argMap.get(argName).getName() + ":" + argName
137 + "' and '" + a.getName() + ":" + argName
142 argMap.put(argName, a);
147 public ArgParser(String[] args)
152 public ArgParser(String[] args, boolean initsubstitutions)
154 // Make a mutable new ArrayList so that shell globbing parser works.
155 // (When shell file globbing is used, there are a sequence of non-Arg
156 // arguments (which are the expanded globbed filenames) that need to be
157 // consumed by the --append/--argfile/etc Arg which is most easily done by
158 // removing these filenames from the list one at a time. This can't be done
159 // with an ArrayList made with only Arrays.asList(String[] args). )
160 this(new ArrayList<>(Arrays.asList(args)), initsubstitutions);
163 public ArgParser(List<String> args, boolean initsubstitutions)
165 this(args, initsubstitutions, false);
168 public ArgParser(List<String> args, boolean initsubstitutions,
169 boolean allowPrivate)
171 // do nothing if there are no "--" args and (some "-" args || >0 arg is
175 for (String arg : args)
177 if (arg.startsWith(DOUBLEDASH))
182 else if (arg.startsWith("-") || arg.equals("open"))
189 // leave it to the old style -- parse an empty list
190 parse(new ArrayList<String>(), false, false);
193 parse(args, initsubstitutions, allowPrivate);
196 private void parse(List<String> args, boolean initsubstitutions,
197 boolean allowPrivate)
199 this.substitutions = initsubstitutions;
200 boolean openEachInitialFilenames = true;
201 for (int i = 0; i < args.size(); i++)
203 String arg = args.get(i);
205 // If the first arguments do not start with "--" or "-" or is not "open"
206 // and` is a filename that exists it is probably a file/list of files to
207 // open so we fake an Arg.OPEN argument and when adding files only add the
208 // single arg[i] and increment the defaultLinkedIdCounter so that each of
209 // these files is opened separately.
210 if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH)
211 && !arg.startsWith("-") && !arg.equals("open")
212 && (new File(arg).exists()
213 || HttpUtils.startsWithHttpOrHttps(arg)))
215 arg = Arg.OPEN.argString();
219 openEachInitialFilenames = false;
222 String argName = null;
224 List<String> globVals = null; // for Opt.GLOB only
225 SubVals globSubVals = null; // also for use by Opt.GLOB only
226 String linkedId = null;
227 if (arg.startsWith(DOUBLEDASH))
229 int equalPos = arg.indexOf(EQUALS);
232 argName = arg.substring(DOUBLEDASH.length(), equalPos);
233 val = arg.substring(equalPos + 1);
237 argName = arg.substring(DOUBLEDASH.length());
239 int idOpen = argName.indexOf('[');
240 int idClose = argName.indexOf(']');
242 if (idOpen > -1 && idClose == argName.length() - 1)
244 linkedId = argName.substring(idOpen + 1, idClose);
245 argName = argName.substring(0, idOpen);
248 Arg a = argMap.get(argName);
249 // check for boolean prepended by "no"
250 boolean negated = false;
251 if (a == null && argName.startsWith(NEGATESTRING) && argMap
252 .containsKey(argName.substring(NEGATESTRING.length())))
254 argName = argName.substring(NEGATESTRING.length());
255 a = argMap.get(argName);
259 // check for config errors
263 Console.error("Argument '" + arg + "' not recognised. Exiting.");
264 Jalview.exit("Unrecognised command line argument '" + arg + "'",
268 if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
271 "Argument '" + a.argString() + "' is private. Ignoring.");
274 if (!a.hasOption(Opt.BOOLEAN) && negated)
276 // used "no" with a non-boolean option
277 Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName
278 + "' not a boolean option. Ignoring.");
281 if (!a.hasOption(Opt.STRING) && equalPos > -1)
283 // set --argname=value when arg does not accept values
284 Console.error("Argument '" + a.argString()
285 + "' does not expect a value (given as '" + arg
289 if (!a.hasOption(Opt.LINKED) && linkedId != null)
291 // set --argname[linkedId] when arg does not use linkedIds
292 Console.error("Argument '" + a.argString()
293 + "' does not expect a linked id (given as '" + arg
299 if (a.hasOption(Opt.STRING))
303 if (a.hasOption(Opt.GLOB))
305 // strip off and save the SubVals to be added individually later
306 globSubVals = new SubVals(val);
307 // make substitutions before looking for files
308 String fileGlob = makeSubstitutions(globSubVals.getContent(),
310 globVals = FileUtils.getFilenamesFromGlob(fileGlob);
314 // val is already set -- will be saved in the ArgValue later in
320 // There is no "=" so value is next arg or args (possibly shell
322 if ((openEachInitialFilenames ? i : i + 1) >= args.size())
324 // no value to take for arg, which wants a value
325 Console.error("Argument '" + a.getName()
326 + "' requires a value, none given. Ignoring.");
329 // deal with bash globs here (--arg val* is expanded before reaching
330 // the JVM). Note that SubVals cannot be used in this case.
331 // If using the --arg=val then the glob is preserved and Java globs
332 // will be used later. SubVals can be used.
333 if (a.hasOption(Opt.GLOB))
335 // if this is the first argument with a file list at the start of
336 // the args we add filenames from index i instead of i+1
337 globVals = getShellGlobbedFilenameValues(a, args,
338 openEachInitialFilenames ? i : i + 1);
342 val = args.get(i + 1);
347 // make NOACTION adjustments
348 // default and auto counter increments
349 if (a == Arg.NEWFRAME)
351 defaultLinkedIdCounter++;
353 else if (a == Arg.NPP)
355 linkedIdAutoCounter++;
357 else if (a == Arg.SUBSTITUTIONS)
359 substitutions = !negated;
361 else if (a == Arg.SETARGFILE)
365 else if (a == Arg.UNSETARGFILE)
369 else if (a == Arg.ALLFRAMES)
371 allLinkedIds = !negated;
374 String autoCounterString = null;
375 boolean usingAutoCounterLinkedId = false;
376 String defaultLinkedId = defaultLinkedId(false);
377 boolean usingDefaultLinkedId = false;
378 if (a.hasOption(Opt.LINKED))
380 if (linkedId == null)
382 if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
384 // use the next default prefixed OPENLINKEDID
385 defaultLinkedId = defaultLinkedId(true);
387 if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
389 linkedId = MATCHALLLINKEDIDS;
393 // use default linkedId for linked arguments
394 linkedId = defaultLinkedId;
395 usingDefaultLinkedId = true;
396 Console.debug("Changing linkedId to '" + linkedId + "' from "
400 else if (linkedId.contains(LINKEDIDAUTOCOUNTER))
402 // turn {n} to the autoCounter
403 autoCounterString = Integer.toString(linkedIdAutoCounter);
404 linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
406 usingAutoCounterLinkedId = true;
408 "Changing linkedId to '" + linkedId + "' from " + arg);
410 else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
412 // turn {++n} to the incremented autoCounter
413 autoCounterString = Integer.toString(++linkedIdAutoCounter);
414 linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
416 usingAutoCounterLinkedId = true;
418 "Changing linkedId to '" + linkedId + "' from " + arg);
422 // do not continue for NOACTION args
423 if (a.hasOption(Opt.NOACTION))
426 if (!linkedArgs.containsKey(linkedId))
427 linkedArgs.put(linkedId, new ArgValuesMap());
429 ArgValuesMap avm = linkedArgs.get(linkedId);
431 // not dealing with both NODUPLICATEVALUES and GLOB
432 if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
434 Console.error("Argument '" + a.argString()
435 + "' cannot contain a duplicate value ('" + val
436 + "'). Ignoring this and subsequent occurrences.");
440 // check for unique id
441 SubVals idsv = new SubVals(val);
442 String id = idsv.get(ArgValues.ID);
443 if (id != null && avm.hasId(a, id))
445 Console.error("Argument '" + a.argString()
446 + "' has a duplicate id ('" + id + "'). Ignoring.");
451 * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*"
452 * DONE, need to check
454 ArgValues avs = avm.getOrCreateArgValues(a);
456 // store appropriate String value(s)
457 if (a.hasOption(Opt.STRING))
459 if (a.hasOption(Opt.GLOB) && globVals != null
460 && globVals.size() > 0)
462 Enumeration<String> gve = Collections.enumeration(globVals);
463 while (gve.hasMoreElements())
465 String v = gve.nextElement();
466 SubVals vsv = new SubVals(globSubVals, v);
467 addValue(linkedId, avs, vsv, v, argIndex++, true);
468 // if we're using defaultLinkedId and the arg increments the
470 if (gve.hasMoreElements() && usingDefaultLinkedId
471 && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
473 // increment the default linkedId
474 linkedId = defaultLinkedId(true);
475 // get new avm and avs
476 avm = linkedArgs.get(linkedId);
477 avs = avm.getOrCreateArgValues(a);
483 addValue(linkedId, avs, val, argIndex, true);
486 else if (a.hasOption(Opt.BOOLEAN))
488 setBoolean(linkedId, avs, !negated, argIndex);
489 setNegated(linkedId, avs, negated);
491 else if (a.hasOption(Opt.UNARY))
493 setBoolean(linkedId, avs, true, argIndex);
496 // remove the '*' linkedId that should be empty if it was created
497 if (MATCHALLLINKEDIDS.equals(linkedId)
498 && linkedArgs.containsKey(linkedId))
500 linkedArgs.remove(linkedId);
506 private void finaliseStoringArgValue(String linkedId, ArgValues avs)
509 incrementCount(linkedId, avs);
512 // store in appropriate place
513 if (a.hasOption(Opt.LINKED))
515 // store the order of linkedIds
516 if (!linkedOrder.contains(linkedId))
517 linkedOrder.add(linkedId);
520 // store arg in the list of args used
521 if (!argList.contains(a))
525 private String defaultLinkedId(boolean increment)
527 String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
528 .append(Integer.toString(defaultLinkedIdCounter)).toString();
531 while (linkedArgs.containsKey(defaultLinkedId))
533 defaultLinkedIdCounter++;
534 defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
535 .append(Integer.toString(defaultLinkedIdCounter))
539 if (!linkedArgs.containsKey(defaultLinkedId))
540 linkedArgs.put(defaultLinkedId, new ArgValuesMap());
541 return defaultLinkedId;
544 public String makeSubstitutions(String val, String linkedId)
546 if (!this.substitutions || val == null)
551 if (val.indexOf('[') == 0 && val.indexOf(']') > 1)
553 int closeBracket = val.indexOf(']');
554 if (val.length() == closeBracket)
556 subvals = val.substring(0, closeBracket + 1);
557 rest = val.substring(closeBracket + 1);
564 if (rest.contains(LINKEDIDAUTOCOUNTER))
565 rest = rest.replace(LINKEDIDAUTOCOUNTER,
566 String.valueOf(linkedIdAutoCounter));
567 if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER))
568 rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER,
569 String.valueOf(++linkedIdAutoCounter));
570 if (rest.contains(DEFAULTLINKEDIDCOUNTER))
571 rest = rest.replace(DEFAULTLINKEDIDCOUNTER,
572 String.valueOf(defaultLinkedIdCounter));
573 ArgValuesMap avm = linkedArgs.get(linkedId);
576 if (rest.contains(LINKEDIDBASENAME))
578 rest = rest.replace(LINKEDIDBASENAME, avm.getBasename());
580 if (rest.contains(LINKEDIDDIRNAME))
582 rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname());
587 if (rest.contains(ARGFILEBASENAME))
589 rest = rest.replace(ARGFILEBASENAME,
590 FileUtils.getBasename(new File(argFile)));
592 if (rest.contains(ARGFILEDIRNAME))
594 rest = rest.replace(ARGFILEDIRNAME,
595 FileUtils.getDirname(new File(argFile)));
599 return new StringBuilder(subvals).append(rest).toString();
603 * A helper method to take a list of String args where we're expecting
604 * {"--previousargs", "--arg", "file1", "file2", "file3", "--otheroptionsornot"}
605 * and the index of the globbed arg, here 1. It returns a List<String> {"file1",
606 * "file2", "file3"} *and remove these from the original list object* so that
607 * processing can continue from where it has left off, e.g. args has become
608 * {"--previousargs", "--arg", "--otheroptionsornot"} so the next increment
609 * carries on from the next --arg if available.
611 protected static List<String> getShellGlobbedFilenameValues(Arg a,
612 List<String> args, int i)
614 List<String> vals = new ArrayList<>();
615 while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH))
617 vals.add(FileUtils.substituteHomeDir(args.remove(i)));
618 if (!a.hasOption(Opt.GLOB))
624 public boolean isSet(Arg a)
626 return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a);
629 public boolean isSet(String linkedId, Arg a)
631 ArgValuesMap avm = linkedArgs.get(linkedId);
632 return avm == null ? false : avm.containsArg(a);
635 public boolean getBool(Arg a)
637 if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
639 Console.warn("Getting boolean from non boolean Arg '" + a.getName()
642 return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a);
645 public boolean getBool(String linkedId, Arg a)
647 ArgValuesMap avm = linkedArgs.get(linkedId);
649 return a.getDefaultBoolValue();
650 ArgValues avs = avm.getArgValues(a);
651 return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
654 public List<String> getLinkedIds()
659 public ArgValuesMap getLinkedArgs(String id)
661 return linkedArgs.get(id);
665 public String toString()
667 StringBuilder sb = new StringBuilder();
668 sb.append("UNLINKED\n");
669 sb.append(argValuesMapToString(linkedArgs.get(null)));
670 if (getLinkedIds() != null)
672 sb.append("LINKED\n");
673 for (String id : getLinkedIds())
675 // already listed these as UNLINKED args
679 ArgValuesMap avm = getLinkedArgs(id);
680 sb.append("ID: '").append(id).append("'\n");
681 sb.append(argValuesMapToString(avm));
684 return sb.toString();
687 private static String argValuesMapToString(ArgValuesMap avm)
691 StringBuilder sb = new StringBuilder();
692 for (Arg a : avm.getArgKeys())
694 ArgValues v = avm.getArgValues(a);
695 sb.append(v.toString());
698 return sb.toString();
701 public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
702 boolean initsubstitutions)
704 List<File> argFiles = new ArrayList<>();
706 for (String pattern : argFilenameGlobs)
708 // I don't think we want to dedup files, making life easier
709 argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
712 return parseArgFileList(argFiles, initsubstitutions);
715 public static ArgParser parseArgFileList(List<File> argFiles,
716 boolean initsubstitutions)
718 List<String> argsList = new ArrayList<>();
719 for (File argFile : argFiles)
721 if (!argFile.exists())
723 String message = Arg.ARGFILE.argString() + EQUALS + "\""
724 + argFile.getPath() + "\": File does not exist.";
725 Jalview.exit(message, 2);
729 String setargfile = new StringBuilder(Arg.SETARGFILE.argString())
730 .append(EQUALS).append(argFile.getCanonicalPath())
732 argsList.add(setargfile);
733 argsList.addAll(readArgFile(argFile));
734 argsList.add(Arg.UNSETARGFILE.argString());
735 } catch (IOException e)
737 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
738 + "\": File could not be read.";
739 Jalview.exit(message, 3);
742 // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
744 return new ArgParser(argsList, initsubstitutions, true);
747 protected static List<String> readArgFile(File argFile)
749 List<String> args = new ArrayList<>();
750 if (argFile != null && argFile.exists())
754 for (String line : Files.readAllLines(Paths.get(argFile.getPath())))
756 if (line != null && line.length() > 0
757 && line.charAt(0) != ARGFILECOMMENT)
760 } catch (IOException e)
762 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
763 + "\": File could not be read.";
764 Console.debug(message, e);
765 Jalview.exit(message, 3);
771 public static enum Position
776 // get from following Arg of type a or subval of same name (lowercase)
777 public static String getValueFromSubValOrArg(ArgValuesMap avm,
778 ArgValue av, Arg a, SubVals sv)
780 return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
783 // get from following Arg of type a or subval key or preference pref or
785 public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av,
786 Arg a, SubVals sv, String key, String pref, String def)
788 return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref,
792 // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
793 // Arg of type a or subval key or preference pref or default def
794 public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
795 Position pos, ArgValue av, SubVals sv, String key, String pref,
800 if (sv != null && sv.has(key) && sv.get(key) != null)
802 if (avm != null && avm.containsArg(a))
804 if (pos == Position.FIRST && avm.getValue(a) != null)
805 return avm.getValue(a);
806 else if (pos == Position.BEFORE
807 && avm.getClosestPreviousArgValueOfArg(av, a) != null)
808 return avm.getClosestPreviousArgValueOfArg(av, a).getValue();
809 else if (pos == Position.AFTER
810 && avm.getClosestNextArgValueOfArg(av, a) != null)
811 return avm.getClosestNextArgValueOfArg(av, a).getValue();
813 return pref != null ? Cache.getDefault(pref, def) : def;
816 public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
819 return getFromSubValArgOrPref(avm, a, sv, null, null, false);
822 public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
823 SubVals sv, String key, String pref, boolean def)
827 if (sv != null && sv.has(key) && sv.get(key) != null)
828 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
829 if (avm != null && avm.containsArg(a))
830 return avm.getBoolean(a);
831 return pref != null ? Cache.getDefault(pref, def) : def;
834 // the following methods look for the "*" linkedId and add the argvalue to all
835 // linkedId ArgValues if it does
836 private void addValue(String linkedId, ArgValues avs, SubVals sv,
837 String v, int argIndex, boolean doSubs)
840 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
842 for (String id : getLinkedIds())
844 if (id == null || MATCHALLLINKEDIDS.equals(id))
846 ArgValuesMap avm = linkedArgs.get(id);
847 if (a.hasOption(Opt.REQUIREINPUT)
848 && !avm.hasArgWithOption(Opt.INPUT))
850 ArgValues tavs = avm.getOrCreateArgValues(a);
854 val = makeSubstitutions(v, id);
855 sv = new SubVals(sv, val);
857 tavs.addValue(sv, val, argIndex);
858 finaliseStoringArgValue(id, tavs);
866 val = makeSubstitutions(v, linkedId);
867 sv = new SubVals(sv, val);
869 avs.addValue(sv, val, argIndex);
870 finaliseStoringArgValue(linkedId, avs);
874 private void addValue(String linkedId, ArgValues avs, String v,
875 int argIndex, boolean doSubs)
878 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
880 for (String id : getLinkedIds())
882 if (id == null || MATCHALLLINKEDIDS.equals(id))
884 ArgValuesMap avm = linkedArgs.get(id);
885 // don't set an output if there isn't an input
886 if (a.hasOption(Opt.REQUIREINPUT)
887 && !avm.hasArgWithOption(Opt.INPUT))
889 ArgValues tavs = avm.getOrCreateArgValues(a);
890 String val = doSubs ? makeSubstitutions(v, id) : v;
891 tavs.addValue(val, argIndex);
892 finaliseStoringArgValue(id, tavs);
897 String val = doSubs ? makeSubstitutions(v, linkedId) : v;
898 avs.addValue(val, argIndex);
899 finaliseStoringArgValue(linkedId, avs);
903 private void setBoolean(String linkedId, ArgValues avs, boolean b,
907 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
909 for (String id : getLinkedIds())
911 if (id == null || MATCHALLLINKEDIDS.equals(id))
913 ArgValuesMap avm = linkedArgs.get(id);
914 if (a.hasOption(Opt.REQUIREINPUT)
915 && !avm.hasArgWithOption(Opt.INPUT))
917 ArgValues tavs = avm.getOrCreateArgValues(a);
918 tavs.setBoolean(b, argIndex);
919 finaliseStoringArgValue(id, tavs);
924 avs.setBoolean(b, argIndex);
925 finaliseStoringArgValue(linkedId, avs);
929 private void setNegated(String linkedId, ArgValues avs, boolean b)
932 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
934 for (String id : getLinkedIds())
936 if (id == null || MATCHALLLINKEDIDS.equals(id))
938 ArgValuesMap avm = linkedArgs.get(id);
939 if (a.hasOption(Opt.REQUIREINPUT)
940 && !avm.hasArgWithOption(Opt.INPUT))
942 ArgValues tavs = avm.getOrCreateArgValues(a);
952 private void incrementCount(String linkedId, ArgValues avs)
955 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
957 for (String id : getLinkedIds())
959 if (id == null || MATCHALLLINKEDIDS.equals(id))
961 ArgValuesMap avm = linkedArgs.get(id);
962 if (a.hasOption(Opt.REQUIREINPUT)
963 && !avm.hasArgWithOption(Opt.INPUT))
965 ArgValues tavs = avm.getOrCreateArgValues(a);
966 tavs.incrementCount();
971 avs.incrementCount();