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 --substitutions and --nosubstitutions
103 private boolean substitutions = true;
105 // flag to say whether the default linkedId is the current default linked id
107 private boolean allLinkedIds = false;
109 protected static final Map<String, Arg> argMap;
111 protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
113 protected List<String> linkedOrder = new ArrayList<>();
115 protected List<Arg> argList = new ArrayList<>();
117 private static final char ARGFILECOMMENT = '#';
119 private int argIndex = 0;
123 argMap = new HashMap<>();
124 for (Arg a : EnumSet.allOf(Arg.class))
126 for (String argName : a.getNames())
128 if (argMap.containsKey(argName))
130 Console.warn("Trying to add argument name multiple times: '"
131 + argName + "'"); // RESTORE THIS WHEN
133 if (argMap.get(argName) != a)
136 "Trying to add argument name multiple times for different Args: '"
137 + argMap.get(argName).getName() + ":" + argName
138 + "' and '" + a.getName() + ":" + argName
143 argMap.put(argName, a);
148 public ArgParser(String[] args)
153 public ArgParser(String[] args, boolean initsubstitutions)
155 // Make a mutable new ArrayList so that shell globbing parser works.
156 // (When shell file globbing is used, there are a sequence of non-Arg
157 // arguments (which are the expanded globbed filenames) that need to be
158 // consumed by the --append/--argfile/etc Arg which is most easily done by
159 // removing these filenames from the list one at a time. This can't be done
160 // with an ArrayList made with only Arrays.asList(String[] args). )
161 this(new ArrayList<>(Arrays.asList(args)), initsubstitutions);
164 public ArgParser(List<String> args, boolean initsubstitutions)
166 this(args, initsubstitutions, false);
169 public ArgParser(List<String> args, boolean initsubstitutions,
170 boolean allowPrivate)
172 // do nothing if there are no "--" args and (some "-" args || >0 arg is
176 for (String arg : args)
178 if (arg.startsWith(DOUBLEDASH))
183 else if (arg.startsWith("-") || arg.equals("open"))
190 // leave it to the old style -- parse an empty list
191 parse(new ArrayList<String>(), false, false);
194 parse(args, initsubstitutions, allowPrivate);
197 private void parse(List<String> args, boolean initsubstitutions,
198 boolean allowPrivate)
200 this.substitutions = initsubstitutions;
201 boolean openEachInitialFilenames = true;
202 for (int i = 0; i < args.size(); i++)
204 String arg = args.get(i);
206 // If the first arguments do not start with "--" or "-" or is not "open"
207 // and` is a filename that exists it is probably a file/list of files to
208 // open so we fake an Arg.OPEN argument and when adding files only add the
209 // single arg[i] and increment the defaultLinkedIdCounter so that each of
210 // these files is opened separately.
211 if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH)
212 && !arg.startsWith("-") && !arg.equals("open")
213 && (new File(arg).exists()
214 || HttpUtils.startsWithHttpOrHttps(arg)))
216 arg = Arg.OPEN.argString();
220 openEachInitialFilenames = false;
223 String argName = null;
225 List<String> globVals = null; // for Opt.GLOB only
226 SubVals globSubVals = null; // also for use by Opt.GLOB only
227 String linkedId = null;
228 if (arg.startsWith(DOUBLEDASH))
230 int equalPos = arg.indexOf(EQUALS);
233 argName = arg.substring(DOUBLEDASH.length(), equalPos);
234 val = arg.substring(equalPos + 1);
238 argName = arg.substring(DOUBLEDASH.length());
240 int idOpen = argName.indexOf('[');
241 int idClose = argName.indexOf(']');
243 if (idOpen > -1 && idClose == argName.length() - 1)
245 linkedId = argName.substring(idOpen + 1, idClose);
246 argName = argName.substring(0, idOpen);
249 Arg a = argMap.get(argName);
250 // check for boolean prepended by "no"
251 boolean negated = false;
252 if (a == null && argName.startsWith(NEGATESTRING) && argMap
253 .containsKey(argName.substring(NEGATESTRING.length())))
255 argName = argName.substring(NEGATESTRING.length());
256 a = argMap.get(argName);
260 // check for config errors
264 Console.error("Argument '" + arg + "' not recognised. Exiting.");
265 Jalview.exit("Unrecognised command line argument '" + arg + "'",
269 if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
272 "Argument '" + a.argString() + "' is private. Ignoring.");
275 if (!a.hasOption(Opt.BOOLEAN) && negated)
277 // used "no" with a non-boolean option
278 Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName
279 + "' not a boolean option. Ignoring.");
282 if (!a.hasOption(Opt.STRING) && equalPos > -1)
284 // set --argname=value when arg does not accept values
285 Console.error("Argument '" + a.argString()
286 + "' does not expect a value (given as '" + arg
290 if (!a.hasOption(Opt.LINKED) && linkedId != null)
292 // set --argname[linkedId] when arg does not use linkedIds
293 Console.error("Argument '" + a.argString()
294 + "' does not expect a linked id (given as '" + arg
300 if (a.hasOption(Opt.STRING))
304 if (a.hasOption(Opt.GLOB))
306 // strip off and save the SubVals to be added individually later
307 globSubVals = new SubVals(val);
308 // make substitutions before looking for files
309 String fileGlob = makeSubstitutions(globSubVals.getContent(),
311 globVals = FileUtils.getFilenamesFromGlob(fileGlob);
315 // val is already set -- will be saved in the ArgValue later in
321 // There is no "=" so value is next arg or args (possibly shell
323 if ((openEachInitialFilenames ? i : i + 1) >= args.size())
325 // no value to take for arg, which wants a value
326 Console.error("Argument '" + a.getName()
327 + "' requires a value, none given. Ignoring.");
330 // deal with bash globs here (--arg val* is expanded before reaching
331 // the JVM). Note that SubVals cannot be used in this case.
332 // If using the --arg=val then the glob is preserved and Java globs
333 // will be used later. SubVals can be used.
334 if (a.hasOption(Opt.GLOB))
336 // if this is the first argument with a file list at the start of
337 // the args we add filenames from index i instead of i+1
338 globVals = getShellGlobbedFilenameValues(a, args,
339 openEachInitialFilenames ? i : i + 1);
343 val = args.get(i + 1);
348 // make NOACTION adjustments
349 // default and auto counter increments
352 linkedIdAutoCounter++;
354 else if (a == Arg.SUBSTITUTIONS)
356 substitutions = !negated;
358 else if (a == Arg.SETARGFILE)
362 else if (a == Arg.UNSETARGFILE)
366 else if (a == Arg.ALL)
368 allLinkedIds = !negated;
371 // this is probably only Arg.NEW and Arg.OPEN
372 if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
374 // use the next default prefixed OPENLINKEDID
375 defaultLinkedId(true);
378 String autoCounterString = null;
379 boolean usingAutoCounterLinkedId = false;
380 String defaultLinkedId = defaultLinkedId(false);
381 boolean usingDefaultLinkedId = false;
382 if (a.hasOption(Opt.LINKED))
384 if (linkedId == null)
386 if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
388 linkedId = MATCHALLLINKEDIDS;
392 // use default linkedId for linked arguments
393 linkedId = defaultLinkedId;
394 usingDefaultLinkedId = true;
395 Console.debug("Changing linkedId to '" + linkedId + "' from "
399 else if (linkedId.contains(LINKEDIDAUTOCOUNTER))
401 // turn {n} to the autoCounter
402 autoCounterString = Integer.toString(linkedIdAutoCounter);
403 linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
405 usingAutoCounterLinkedId = true;
407 "Changing linkedId to '" + linkedId + "' from " + arg);
409 else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
411 // turn {++n} to the incremented autoCounter
412 autoCounterString = Integer.toString(++linkedIdAutoCounter);
413 linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
415 usingAutoCounterLinkedId = true;
417 "Changing linkedId to '" + linkedId + "' from " + arg);
421 // do not continue in this block for NOACTION args
422 if (a.hasOption(Opt.NOACTION))
425 if (!linkedArgs.containsKey(linkedId))
426 linkedArgs.put(linkedId, new ArgValuesMap());
428 ArgValuesMap avm = linkedArgs.get(linkedId);
430 // not dealing with both NODUPLICATEVALUES and GLOB
431 if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
433 Console.error("Argument '" + a.argString()
434 + "' cannot contain a duplicate value ('" + val
435 + "'). Ignoring this and subsequent occurrences.");
439 // check for unique id
440 SubVals idsv = new SubVals(val);
441 String id = idsv.get(ArgValues.ID);
442 if (id != null && avm.hasId(a, id))
444 Console.error("Argument '" + a.argString()
445 + "' has a duplicate id ('" + id + "'). Ignoring.");
450 * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*"
451 * DONE, need to check
453 ArgValues avs = avm.getOrCreateArgValues(a);
455 // store appropriate String value(s)
456 if (a.hasOption(Opt.STRING))
458 if (a.hasOption(Opt.GLOB) && globVals != null
459 && globVals.size() > 0)
461 Enumeration<String> gve = Collections.enumeration(globVals);
462 while (gve.hasMoreElements())
464 String v = gve.nextElement();
465 SubVals vsv = new SubVals(globSubVals, v);
466 addValue(linkedId, avs, vsv, v, argIndex++, true);
467 // if we're using defaultLinkedId and the arg increments the
469 if (gve.hasMoreElements() && usingDefaultLinkedId
470 && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
472 // increment the default linkedId
473 linkedId = defaultLinkedId(true);
474 // get new avm and avs
475 avm = linkedArgs.get(linkedId);
476 avs = avm.getOrCreateArgValues(a);
482 addValue(linkedId, avs, val, argIndex, true);
485 else if (a.hasOption(Opt.BOOLEAN))
487 setBoolean(linkedId, avs, !negated, argIndex);
488 setNegated(linkedId, avs, negated);
490 else if (a.hasOption(Opt.UNARY))
492 setBoolean(linkedId, avs, true, argIndex);
495 // remove the '*' linkedId that should be empty if it was created
496 if (MATCHALLLINKEDIDS.equals(linkedId)
497 && linkedArgs.containsKey(linkedId))
499 linkedArgs.remove(linkedId);
505 private void finaliseStoringArgValue(String linkedId, ArgValues avs)
508 incrementCount(linkedId, avs);
511 // store in appropriate place
512 if (a.hasOption(Opt.LINKED))
514 // store the order of linkedIds
515 if (!linkedOrder.contains(linkedId))
516 linkedOrder.add(linkedId);
519 // store arg in the list of args used
520 if (!argList.contains(a))
524 private String defaultLinkedId(boolean increment)
526 String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
527 .append(Integer.toString(defaultLinkedIdCounter)).toString();
530 while (linkedArgs.containsKey(defaultLinkedId))
532 defaultLinkedIdCounter++;
533 defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
534 .append(Integer.toString(defaultLinkedIdCounter))
538 if (!linkedArgs.containsKey(defaultLinkedId))
539 linkedArgs.put(defaultLinkedId, new ArgValuesMap());
540 return defaultLinkedId;
543 public String makeSubstitutions(String val, String linkedId)
545 if (!this.substitutions || val == null)
550 if (val.indexOf('[') == 0 && val.indexOf(']') > 1)
552 int closeBracket = val.indexOf(']');
553 if (val.length() == closeBracket)
555 subvals = val.substring(0, closeBracket + 1);
556 rest = val.substring(closeBracket + 1);
563 if (rest.contains(LINKEDIDAUTOCOUNTER))
564 rest = rest.replace(LINKEDIDAUTOCOUNTER,
565 String.valueOf(linkedIdAutoCounter));
566 if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER))
567 rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER,
568 String.valueOf(++linkedIdAutoCounter));
569 if (rest.contains(DEFAULTLINKEDIDCOUNTER))
570 rest = rest.replace(DEFAULTLINKEDIDCOUNTER,
571 String.valueOf(defaultLinkedIdCounter));
572 ArgValuesMap avm = linkedArgs.get(linkedId);
575 if (rest.contains(LINKEDIDBASENAME))
577 rest = rest.replace(LINKEDIDBASENAME, avm.getBasename());
579 if (rest.contains(LINKEDIDDIRNAME))
581 rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname());
586 if (rest.contains(ARGFILEBASENAME))
588 rest = rest.replace(ARGFILEBASENAME,
589 FileUtils.getBasename(new File(argFile)));
591 if (rest.contains(ARGFILEDIRNAME))
593 rest = rest.replace(ARGFILEDIRNAME,
594 FileUtils.getDirname(new File(argFile)));
598 return new StringBuilder(subvals).append(rest).toString();
602 * A helper method to take a list of String args where we're expecting
603 * {"--previousargs", "--arg", "file1", "file2", "file3", "--otheroptionsornot"}
604 * and the index of the globbed arg, here 1. It returns a List<String> {"file1",
605 * "file2", "file3"} *and remove these from the original list object* so that
606 * processing can continue from where it has left off, e.g. args has become
607 * {"--previousargs", "--arg", "--otheroptionsornot"} so the next increment
608 * carries on from the next --arg if available.
610 protected static List<String> getShellGlobbedFilenameValues(Arg a,
611 List<String> args, int i)
613 List<String> vals = new ArrayList<>();
614 while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH))
616 vals.add(FileUtils.substituteHomeDir(args.remove(i)));
617 if (!a.hasOption(Opt.GLOB))
623 public boolean isSet(Arg a)
625 return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a);
628 public boolean isSet(String linkedId, Arg a)
630 ArgValuesMap avm = linkedArgs.get(linkedId);
631 return avm == null ? false : avm.containsArg(a);
634 public boolean getBool(Arg a)
636 if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
638 Console.warn("Getting boolean from non boolean Arg '" + a.getName()
641 return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a);
644 public boolean getBool(String linkedId, Arg a)
646 ArgValuesMap avm = linkedArgs.get(linkedId);
648 return a.getDefaultBoolValue();
649 ArgValues avs = avm.getArgValues(a);
650 return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
653 public List<String> getLinkedIds()
658 public ArgValuesMap getLinkedArgs(String id)
660 return linkedArgs.get(id);
664 public String toString()
666 StringBuilder sb = new StringBuilder();
667 sb.append("UNLINKED\n");
668 sb.append(argValuesMapToString(linkedArgs.get(null)));
669 if (getLinkedIds() != null)
671 sb.append("LINKED\n");
672 for (String id : getLinkedIds())
674 // already listed these as UNLINKED args
678 ArgValuesMap avm = getLinkedArgs(id);
679 sb.append("ID: '").append(id).append("'\n");
680 sb.append(argValuesMapToString(avm));
683 return sb.toString();
686 private static String argValuesMapToString(ArgValuesMap avm)
690 StringBuilder sb = new StringBuilder();
691 for (Arg a : avm.getArgKeys())
693 ArgValues v = avm.getArgValues(a);
694 sb.append(v.toString());
697 return sb.toString();
700 public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
701 boolean initsubstitutions)
703 List<File> argFiles = new ArrayList<>();
705 for (String pattern : argFilenameGlobs)
707 // I don't think we want to dedup files, making life easier
708 argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
711 return parseArgFileList(argFiles, initsubstitutions);
714 public static ArgParser parseArgFileList(List<File> argFiles,
715 boolean initsubstitutions)
717 List<String> argsList = new ArrayList<>();
718 for (File argFile : argFiles)
720 if (!argFile.exists())
722 String message = Arg.ARGFILE.argString() + EQUALS + "\""
723 + argFile.getPath() + "\": File does not exist.";
724 Jalview.exit(message, 2);
728 String setargfile = new StringBuilder(Arg.SETARGFILE.argString())
729 .append(EQUALS).append(argFile.getCanonicalPath())
731 argsList.add(setargfile);
732 argsList.addAll(readArgFile(argFile));
733 argsList.add(Arg.UNSETARGFILE.argString());
734 } catch (IOException e)
736 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
737 + "\": File could not be read.";
738 Jalview.exit(message, 3);
741 // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
743 return new ArgParser(argsList, initsubstitutions, true);
746 protected static List<String> readArgFile(File argFile)
748 List<String> args = new ArrayList<>();
749 if (argFile != null && argFile.exists())
753 for (String line : Files.readAllLines(Paths.get(argFile.getPath())))
755 if (line != null && line.length() > 0
756 && line.charAt(0) != ARGFILECOMMENT)
759 } catch (IOException e)
761 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
762 + "\": File could not be read.";
763 Console.debug(message, e);
764 Jalview.exit(message, 3);
770 public static enum Position
775 // get from following Arg of type a or subval of same name (lowercase)
776 public static String getValueFromSubValOrArg(ArgValuesMap avm,
777 ArgValue av, Arg a, SubVals sv)
779 return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
782 // get from following Arg of type a or subval key or preference pref or
784 public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av,
785 Arg a, SubVals sv, String key, String pref, String def)
787 return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref,
791 // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
792 // Arg of type a or subval key or preference pref or default def
793 public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
794 Position pos, ArgValue av, SubVals sv, String key, String pref,
799 if (sv != null && sv.has(key) && sv.get(key) != null)
801 if (avm != null && avm.containsArg(a))
803 if (pos == Position.FIRST && avm.getValue(a) != null)
804 return avm.getValue(a);
805 else if (pos == Position.BEFORE
806 && avm.getClosestPreviousArgValueOfArg(av, a) != null)
807 return avm.getClosestPreviousArgValueOfArg(av, a).getValue();
808 else if (pos == Position.AFTER
809 && avm.getClosestNextArgValueOfArg(av, a) != null)
810 return avm.getClosestNextArgValueOfArg(av, a).getValue();
812 return pref != null ? Cache.getDefault(pref, def) : def;
815 public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
818 return getFromSubValArgOrPref(avm, a, sv, null, null, false);
821 public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
822 SubVals sv, String key, String pref, boolean def)
826 if (sv != null && sv.has(key) && sv.get(key) != null)
827 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
828 if (avm != null && avm.containsArg(a))
829 return avm.getBoolean(a);
830 return pref != null ? Cache.getDefault(pref, def) : def;
833 // the following methods look for the "*" linkedId and add the argvalue to all
834 // linkedId ArgValues if it does
835 private void addValue(String linkedId, ArgValues avs, SubVals sv,
836 String v, int argIndex, boolean doSubs)
839 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
841 for (String id : getLinkedIds())
843 if (id == null || MATCHALLLINKEDIDS.equals(id))
845 ArgValuesMap avm = linkedArgs.get(id);
846 if (a.hasOption(Opt.REQUIREINPUT)
847 && !avm.hasArgWithOption(Opt.INPUT))
849 ArgValues tavs = avm.getOrCreateArgValues(a);
853 val = makeSubstitutions(v, id);
854 sv = new SubVals(sv, val);
856 tavs.addValue(sv, val, argIndex);
857 finaliseStoringArgValue(id, tavs);
865 val = makeSubstitutions(v, linkedId);
866 sv = new SubVals(sv, val);
868 avs.addValue(sv, val, argIndex);
869 finaliseStoringArgValue(linkedId, avs);
873 private void addValue(String linkedId, ArgValues avs, String v,
874 int argIndex, boolean doSubs)
877 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
879 for (String id : getLinkedIds())
881 if (id == null || MATCHALLLINKEDIDS.equals(id))
883 ArgValuesMap avm = linkedArgs.get(id);
884 // don't set an output if there isn't an input
885 if (a.hasOption(Opt.REQUIREINPUT)
886 && !avm.hasArgWithOption(Opt.INPUT))
888 ArgValues tavs = avm.getOrCreateArgValues(a);
889 String val = doSubs ? makeSubstitutions(v, id) : v;
890 tavs.addValue(val, argIndex);
891 finaliseStoringArgValue(id, tavs);
896 String val = doSubs ? makeSubstitutions(v, linkedId) : v;
897 avs.addValue(val, argIndex);
898 finaliseStoringArgValue(linkedId, avs);
902 private void setBoolean(String linkedId, ArgValues avs, boolean b,
906 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
908 for (String id : getLinkedIds())
910 if (id == null || MATCHALLLINKEDIDS.equals(id))
912 ArgValuesMap avm = linkedArgs.get(id);
913 if (a.hasOption(Opt.REQUIREINPUT)
914 && !avm.hasArgWithOption(Opt.INPUT))
916 ArgValues tavs = avm.getOrCreateArgValues(a);
917 tavs.setBoolean(b, argIndex);
918 finaliseStoringArgValue(id, tavs);
923 avs.setBoolean(b, argIndex);
924 finaliseStoringArgValue(linkedId, avs);
928 private void setNegated(String linkedId, ArgValues avs, boolean b)
931 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
933 for (String id : getLinkedIds())
935 if (id == null || MATCHALLLINKEDIDS.equals(id))
937 ArgValuesMap avm = linkedArgs.get(id);
938 if (a.hasOption(Opt.REQUIREINPUT)
939 && !avm.hasArgWithOption(Opt.INPUT))
941 ArgValues tavs = avm.getOrCreateArgValues(a);
951 private void incrementCount(String linkedId, ArgValues avs)
954 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
956 for (String id : getLinkedIds())
958 if (id == null || MATCHALLLINKEDIDS.equals(id))
960 ArgValuesMap avm = linkedArgs.get(id);
961 if (a.hasOption(Opt.REQUIREINPUT)
962 && !avm.hasArgWithOption(Opt.INPUT))
964 ArgValues tavs = avm.getOrCreateArgValues(a);
965 tavs.incrementCount();
970 avs.incrementCount();