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;
121 private BootstrapArgs bootstrapArgs = null;
125 argMap = new HashMap<>();
126 for (Arg a : EnumSet.allOf(Arg.class))
128 for (String argName : a.getNames())
130 if (argMap.containsKey(argName))
132 Console.warn("Trying to add argument name multiple times: '"
133 + argName + "'"); // RESTORE THIS WHEN
135 if (argMap.get(argName) != a)
138 "Trying to add argument name multiple times for different Args: '"
139 + argMap.get(argName).getName() + ":" + argName
140 + "' and '" + a.getName() + ":" + argName
145 argMap.put(argName, a);
150 public ArgParser(String[] args)
152 this(args, false, null);
155 public ArgParser(String[] args, boolean initsubstitutions,
158 // Make a mutable new ArrayList so that shell globbing parser works.
159 // (When shell file globbing is used, there are a sequence of non-Arg
160 // arguments (which are the expanded globbed filenames) that need to be
161 // consumed by the --append/--argfile/etc Arg which is most easily done by
162 // removing these filenames from the list one at a time. This can't be done
163 // with an ArrayList made with only Arrays.asList(String[] args). )
164 this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false,
168 public ArgParser(List<String> args, boolean initsubstitutions)
170 this(args, initsubstitutions, false, null);
173 public ArgParser(List<String> args, boolean initsubstitutions,
174 boolean allowPrivate, BootstrapArgs bsa)
176 // do nothing if there are no "--" args and (some "-" args || >0 arg is
180 for (String arg : args)
182 if (arg.startsWith(DOUBLEDASH))
187 else if (arg.startsWith("-") || arg.equals("open"))
194 // leave it to the old style -- parse an empty list
195 parse(new ArrayList<String>(), false, false);
199 this.bootstrapArgs = bsa;
201 this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
202 parse(args, initsubstitutions, allowPrivate);
205 private void parse(List<String> args, boolean initsubstitutions,
206 boolean allowPrivate)
208 this.substitutions = initsubstitutions;
209 boolean openEachInitialFilenames = true;
210 for (int i = 0; i < args.size(); i++)
212 String arg = args.get(i);
214 // If the first arguments do not start with "--" or "-" or is not "open"
215 // and` is a filename that exists it is probably a file/list of files to
216 // open so we fake an Arg.OPEN argument and when adding files only add the
217 // single arg[i] and increment the defaultLinkedIdCounter so that each of
218 // these files is opened separately.
219 if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH)
220 && !arg.startsWith("-") && !arg.equals("open")
221 && (new File(arg).exists()
222 || HttpUtils.startsWithHttpOrHttps(arg)))
224 arg = Arg.OPEN.argString();
228 openEachInitialFilenames = false;
231 String argName = null;
233 List<String> globVals = null; // for Opt.GLOB only
234 SubVals globSubVals = null; // also for use by Opt.GLOB only
235 String linkedId = null;
236 if (arg.startsWith(DOUBLEDASH))
238 int equalPos = arg.indexOf(EQUALS);
241 argName = arg.substring(DOUBLEDASH.length(), equalPos);
242 val = arg.substring(equalPos + 1);
246 argName = arg.substring(DOUBLEDASH.length());
248 int idOpen = argName.indexOf('[');
249 int idClose = argName.indexOf(']');
251 if (idOpen > -1 && idClose == argName.length() - 1)
253 linkedId = argName.substring(idOpen + 1, idClose);
254 argName = argName.substring(0, idOpen);
257 Arg a = argMap.get(argName);
258 // check for boolean prepended by "no"
259 boolean negated = false;
260 if (a == null && argName.startsWith(NEGATESTRING) && argMap
261 .containsKey(argName.substring(NEGATESTRING.length())))
263 argName = argName.substring(NEGATESTRING.length());
264 a = argMap.get(argName);
268 // check for config errors
272 Console.error("Argument '" + arg + "' not recognised. Exiting.");
273 Jalview.exit("Unrecognised command line argument '" + arg + "'",
277 if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
280 "Argument '" + a.argString() + "' is private. Ignoring.");
283 if (!a.hasOption(Opt.BOOLEAN) && negated)
285 // used "no" with a non-boolean option
286 Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName
287 + "' not a boolean option. Ignoring.");
290 if (!a.hasOption(Opt.STRING) && equalPos > -1)
292 // set --argname=value when arg does not accept values
293 Console.error("Argument '" + a.argString()
294 + "' does not expect a value (given as '" + arg
298 if (!a.hasOption(Opt.LINKED) && linkedId != null)
300 // set --argname[linkedId] when arg does not use linkedIds
301 Console.error("Argument '" + a.argString()
302 + "' does not expect a linked id (given as '" + arg
308 if (a.hasOption(Opt.STRING))
312 if (a.hasOption(Opt.GLOB))
314 // strip off and save the SubVals to be added individually later
315 globSubVals = new SubVals(val);
316 // make substitutions before looking for files
317 String fileGlob = makeSubstitutions(globSubVals.getContent(),
319 globVals = FileUtils.getFilenamesFromGlob(fileGlob);
323 // val is already set -- will be saved in the ArgValue later in
329 // There is no "=" so value is next arg or args (possibly shell
331 if ((openEachInitialFilenames ? i : i + 1) >= args.size())
333 // no value to take for arg, which wants a value
334 Console.error("Argument '" + a.getName()
335 + "' requires a value, none given. Ignoring.");
338 // deal with bash globs here (--arg val* is expanded before reaching
339 // the JVM). Note that SubVals cannot be used in this case.
340 // If using the --arg=val then the glob is preserved and Java globs
341 // will be used later. SubVals can be used.
342 if (a.hasOption(Opt.GLOB))
344 // if this is the first argument with a file list at the start of
345 // the args we add filenames from index i instead of i+1
346 globVals = getShellGlobbedFilenameValues(a, args,
347 openEachInitialFilenames ? i : i + 1);
351 val = args.get(i + 1);
356 // make NOACTION adjustments
357 // default and auto counter increments
360 linkedIdAutoCounter++;
362 else if (a == Arg.SUBSTITUTIONS)
364 substitutions = !negated;
366 else if (a == Arg.SETARGFILE)
370 else if (a == Arg.UNSETARGFILE)
374 else if (a == Arg.ALL)
376 allLinkedIds = !negated;
379 // this is probably only Arg.NEW and Arg.OPEN
380 if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
382 // use the next default prefixed OPENLINKEDID
383 defaultLinkedId(true);
386 String autoCounterString = null;
387 boolean usingAutoCounterLinkedId = false;
388 String defaultLinkedId = defaultLinkedId(false);
389 boolean usingDefaultLinkedId = false;
390 if (a.hasOption(Opt.LINKED))
392 if (linkedId == null)
394 if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
396 linkedId = MATCHALLLINKEDIDS;
400 // use default linkedId for linked arguments
401 linkedId = defaultLinkedId;
402 usingDefaultLinkedId = true;
403 Console.debug("Changing linkedId to '" + linkedId + "' from "
407 else if (linkedId.contains(LINKEDIDAUTOCOUNTER))
409 // turn {n} to the autoCounter
410 autoCounterString = Integer.toString(linkedIdAutoCounter);
411 linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
413 usingAutoCounterLinkedId = true;
415 "Changing linkedId to '" + linkedId + "' from " + arg);
417 else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
419 // turn {++n} to the incremented autoCounter
420 autoCounterString = Integer.toString(++linkedIdAutoCounter);
421 linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
423 usingAutoCounterLinkedId = true;
425 "Changing linkedId to '" + linkedId + "' from " + arg);
429 // do not continue in this block for NOACTION args
430 if (a.hasOption(Opt.NOACTION))
433 if (!linkedArgs.containsKey(linkedId))
434 linkedArgs.put(linkedId, new ArgValuesMap());
436 ArgValuesMap avm = linkedArgs.get(linkedId);
438 // not dealing with both NODUPLICATEVALUES and GLOB
439 if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
441 Console.error("Argument '" + a.argString()
442 + "' cannot contain a duplicate value ('" + val
443 + "'). Ignoring this and subsequent occurrences.");
447 // check for unique id
448 SubVals idsv = new SubVals(val);
449 String id = idsv.get(ArgValues.ID);
450 if (id != null && avm.hasId(a, id))
452 Console.error("Argument '" + a.argString()
453 + "' has a duplicate id ('" + id + "'). Ignoring.");
458 * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*"
459 * DONE, need to check
461 ArgValues avs = avm.getOrCreateArgValues(a);
463 // store appropriate String value(s)
464 if (a.hasOption(Opt.STRING))
466 if (a.hasOption(Opt.GLOB) && globVals != null
467 && globVals.size() > 0)
469 Enumeration<String> gve = Collections.enumeration(globVals);
470 while (gve.hasMoreElements())
472 String v = gve.nextElement();
473 SubVals vsv = new SubVals(globSubVals, v);
474 addValue(linkedId, avs, vsv, v, argIndex++, true);
475 // if we're using defaultLinkedId and the arg increments the
477 if (gve.hasMoreElements() && usingDefaultLinkedId
478 && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
480 // increment the default linkedId
481 linkedId = defaultLinkedId(true);
482 // get new avm and avs
483 avm = linkedArgs.get(linkedId);
484 avs = avm.getOrCreateArgValues(a);
490 addValue(linkedId, avs, val, argIndex, true);
493 else if (a.hasOption(Opt.BOOLEAN))
495 setBoolean(linkedId, avs, !negated, argIndex);
496 setNegated(linkedId, avs, negated);
498 else if (a.hasOption(Opt.UNARY))
500 setBoolean(linkedId, avs, true, argIndex);
503 // remove the '*' linkedId that should be empty if it was created
504 if (MATCHALLLINKEDIDS.equals(linkedId)
505 && linkedArgs.containsKey(linkedId))
507 linkedArgs.remove(linkedId);
513 private void finaliseStoringArgValue(String linkedId, ArgValues avs)
516 incrementCount(linkedId, avs);
519 // store in appropriate place
520 if (a.hasOption(Opt.LINKED))
522 // store the order of linkedIds
523 if (!linkedOrder.contains(linkedId))
524 linkedOrder.add(linkedId);
527 // store arg in the list of args used
528 if (!argList.contains(a))
532 private String defaultLinkedId(boolean increment)
534 String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
535 .append(Integer.toString(defaultLinkedIdCounter)).toString();
538 while (linkedArgs.containsKey(defaultLinkedId))
540 defaultLinkedIdCounter++;
541 defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
542 .append(Integer.toString(defaultLinkedIdCounter))
546 if (!linkedArgs.containsKey(defaultLinkedId))
547 linkedArgs.put(defaultLinkedId, new ArgValuesMap());
548 return defaultLinkedId;
551 public String makeSubstitutions(String val, String linkedId)
553 if (!this.substitutions || val == null)
558 if (val.indexOf('[') == 0 && val.indexOf(']') > 1)
560 int closeBracket = val.indexOf(']');
561 if (val.length() == closeBracket)
563 subvals = val.substring(0, closeBracket + 1);
564 rest = val.substring(closeBracket + 1);
571 if (rest.contains(LINKEDIDAUTOCOUNTER))
572 rest = rest.replace(LINKEDIDAUTOCOUNTER,
573 String.valueOf(linkedIdAutoCounter));
574 if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER))
575 rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER,
576 String.valueOf(++linkedIdAutoCounter));
577 if (rest.contains(DEFAULTLINKEDIDCOUNTER))
578 rest = rest.replace(DEFAULTLINKEDIDCOUNTER,
579 String.valueOf(defaultLinkedIdCounter));
580 ArgValuesMap avm = linkedArgs.get(linkedId);
583 if (rest.contains(LINKEDIDBASENAME))
585 rest = rest.replace(LINKEDIDBASENAME, avm.getBasename());
587 if (rest.contains(LINKEDIDDIRNAME))
589 rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname());
594 if (rest.contains(ARGFILEBASENAME))
596 rest = rest.replace(ARGFILEBASENAME,
597 FileUtils.getBasename(new File(argFile)));
599 if (rest.contains(ARGFILEDIRNAME))
601 rest = rest.replace(ARGFILEDIRNAME,
602 FileUtils.getDirname(new File(argFile)));
606 return new StringBuilder(subvals).append(rest).toString();
610 * A helper method to take a list of String args where we're expecting
611 * {"--previousargs", "--arg", "file1", "file2", "file3", "--otheroptionsornot"}
612 * and the index of the globbed arg, here 1. It returns a List<String> {"file1",
613 * "file2", "file3"} *and remove these from the original list object* so that
614 * processing can continue from where it has left off, e.g. args has become
615 * {"--previousargs", "--arg", "--otheroptionsornot"} so the next increment
616 * carries on from the next --arg if available.
618 protected static List<String> getShellGlobbedFilenameValues(Arg a,
619 List<String> args, int i)
621 List<String> vals = new ArrayList<>();
622 while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH))
624 vals.add(FileUtils.substituteHomeDir(args.remove(i)));
625 if (!a.hasOption(Opt.GLOB))
631 public BootstrapArgs getBootstrapArgs()
633 return bootstrapArgs;
636 public boolean isSet(Arg a)
638 return a.hasOption(Opt.LINKED) ? isSetAtAll(a) : isSet(null, a);
641 public boolean isSetAtAll(Arg a)
643 for (String linkedId : linkedOrder)
645 if (isSet(linkedId, a))
651 public boolean isSet(String linkedId, Arg a)
653 ArgValuesMap avm = linkedArgs.get(linkedId);
654 return avm == null ? false : avm.containsArg(a);
657 public boolean getBoolean(Arg a)
659 if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
661 Console.warn("Getting boolean from non boolean Arg '" + a.getName()
664 return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a);
667 public boolean getBool(String linkedId, Arg a)
669 ArgValuesMap avm = linkedArgs.get(linkedId);
671 return a.getDefaultBoolValue();
672 ArgValues avs = avm.getArgValues(a);
673 return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
676 public List<String> getLinkedIds()
681 public ArgValuesMap getLinkedArgs(String id)
683 return linkedArgs.get(id);
687 public String toString()
689 StringBuilder sb = new StringBuilder();
690 sb.append("UNLINKED\n");
691 sb.append(argValuesMapToString(linkedArgs.get(null)));
692 if (getLinkedIds() != null)
694 sb.append("LINKED\n");
695 for (String id : getLinkedIds())
697 // already listed these as UNLINKED args
701 ArgValuesMap avm = getLinkedArgs(id);
702 sb.append("ID: '").append(id).append("'\n");
703 sb.append(argValuesMapToString(avm));
706 return sb.toString();
709 private static String argValuesMapToString(ArgValuesMap avm)
713 StringBuilder sb = new StringBuilder();
714 for (Arg a : avm.getArgKeys())
716 ArgValues v = avm.getArgValues(a);
717 sb.append(v.toString());
720 return sb.toString();
723 public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
724 boolean initsubstitutions, BootstrapArgs bsa)
726 List<File> argFiles = new ArrayList<>();
728 for (String pattern : argFilenameGlobs)
730 // I don't think we want to dedup files, making life easier
731 argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
734 return parseArgFileList(argFiles, initsubstitutions, bsa);
737 public static ArgParser parseArgFileList(List<File> argFiles,
738 boolean initsubstitutions, BootstrapArgs bsa)
740 List<String> argsList = new ArrayList<>();
741 for (File argFile : argFiles)
743 if (!argFile.exists())
745 String message = Arg.ARGFILE.argString() + EQUALS + "\""
746 + argFile.getPath() + "\": File does not exist.";
747 Jalview.exit(message, 2);
751 String setargfile = new StringBuilder(Arg.SETARGFILE.argString())
752 .append(EQUALS).append(argFile.getCanonicalPath())
754 argsList.add(setargfile);
755 argsList.addAll(readArgFile(argFile));
756 argsList.add(Arg.UNSETARGFILE.argString());
757 } catch (IOException e)
759 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
760 + "\": File could not be read.";
761 Jalview.exit(message, 3);
764 // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
766 return new ArgParser(argsList, initsubstitutions, true, bsa);
769 protected static List<String> readArgFile(File argFile)
771 List<String> args = new ArrayList<>();
772 if (argFile != null && argFile.exists())
776 for (String line : Files.readAllLines(Paths.get(argFile.getPath())))
778 if (line != null && line.length() > 0
779 && line.charAt(0) != ARGFILECOMMENT)
782 } catch (IOException e)
784 String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
785 + "\": File could not be read.";
786 Console.debug(message, e);
787 Jalview.exit(message, 3);
793 public static enum Position
798 // get from following Arg of type a or subval of same name (lowercase)
799 public static String getValueFromSubValOrArg(ArgValuesMap avm,
800 ArgValue av, Arg a, SubVals sv)
802 return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
805 // get from following Arg of type a or subval key or preference pref or
807 public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av,
808 Arg a, SubVals sv, String key, String pref, String def)
810 return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref,
814 // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
815 // Arg of type a or subval key or preference pref or default def
816 public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
817 Position pos, ArgValue av, SubVals sv, String key, String pref,
822 if (sv != null && sv.has(key) && sv.get(key) != null)
824 if (avm != null && avm.containsArg(a))
826 if (pos == Position.FIRST && avm.getValue(a) != null)
827 return avm.getValue(a);
828 else if (pos == Position.BEFORE
829 && avm.getClosestPreviousArgValueOfArg(av, a) != null)
830 return avm.getClosestPreviousArgValueOfArg(av, a).getValue();
831 else if (pos == Position.AFTER
832 && avm.getClosestNextArgValueOfArg(av, a) != null)
833 return avm.getClosestNextArgValueOfArg(av, a).getValue();
835 return pref != null ? Cache.getDefault(pref, def) : def;
838 public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
841 return getFromSubValArgOrPref(avm, a, sv, null, null, false);
844 public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
845 SubVals sv, String key, String pref, boolean def)
847 if ((key == null && a == null) || (sv == null && a == null))
850 boolean usingArgKey = false;
857 String nokey = ArgParser.NEGATESTRING + key;
859 // look for key or nokey in subvals first (if using Arg check options)
862 // check for true boolean
863 if (sv.has(key) && sv.get(key) != null)
867 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
870 "Looking for boolean in subval from non-boolean/non-unary Arg "
875 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
878 // check for negative boolean (subval "no..." will be "true")
879 if (sv.has(nokey) && sv.get(nokey) != null)
883 if (!(a.hasOption(Opt.BOOLEAN)))
886 "Looking for negative boolean in subval from non-boolean Arg "
891 return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true");
896 if (avm != null && avm.containsArg(a))
897 return avm.getBoolean(a);
899 // return preference or default
900 return pref != null ? Cache.getDefault(pref, def) : def;
903 // the following methods look for the "*" linkedId and add the argvalue to all
904 // linkedId ArgValues if it does
905 private void addValue(String linkedId, ArgValues avs, SubVals sv,
906 String v, int argIndex, boolean doSubs)
909 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
911 for (String id : getLinkedIds())
913 if (id == null || MATCHALLLINKEDIDS.equals(id))
915 ArgValuesMap avm = linkedArgs.get(id);
916 if (a.hasOption(Opt.REQUIREINPUT)
917 && !avm.hasArgWithOption(Opt.INPUT))
919 ArgValues tavs = avm.getOrCreateArgValues(a);
923 val = makeSubstitutions(v, id);
924 sv = new SubVals(sv, val);
926 tavs.addValue(sv, val, argIndex);
927 finaliseStoringArgValue(id, tavs);
935 val = makeSubstitutions(v, linkedId);
936 sv = new SubVals(sv, val);
938 avs.addValue(sv, val, argIndex);
939 finaliseStoringArgValue(linkedId, avs);
943 private void addValue(String linkedId, ArgValues avs, String v,
944 int argIndex, boolean doSubs)
947 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
949 for (String id : getLinkedIds())
951 if (id == null || MATCHALLLINKEDIDS.equals(id))
953 ArgValuesMap avm = linkedArgs.get(id);
954 // don't set an output if there isn't an input
955 if (a.hasOption(Opt.REQUIREINPUT)
956 && !avm.hasArgWithOption(Opt.INPUT))
958 ArgValues tavs = avm.getOrCreateArgValues(a);
959 String val = doSubs ? makeSubstitutions(v, id) : v;
960 tavs.addValue(val, argIndex);
961 finaliseStoringArgValue(id, tavs);
966 String val = doSubs ? makeSubstitutions(v, linkedId) : v;
967 avs.addValue(val, argIndex);
968 finaliseStoringArgValue(linkedId, avs);
972 private void setBoolean(String linkedId, ArgValues avs, boolean b,
976 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
978 for (String id : getLinkedIds())
980 if (id == null || MATCHALLLINKEDIDS.equals(id))
982 ArgValuesMap avm = linkedArgs.get(id);
983 if (a.hasOption(Opt.REQUIREINPUT)
984 && !avm.hasArgWithOption(Opt.INPUT))
986 ArgValues tavs = avm.getOrCreateArgValues(a);
987 tavs.setBoolean(b, argIndex);
988 finaliseStoringArgValue(id, tavs);
993 avs.setBoolean(b, argIndex);
994 finaliseStoringArgValue(linkedId, avs);
998 private void setNegated(String linkedId, ArgValues avs, boolean b)
1001 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
1003 for (String id : getLinkedIds())
1005 if (id == null || MATCHALLLINKEDIDS.equals(id))
1007 ArgValuesMap avm = linkedArgs.get(id);
1008 if (a.hasOption(Opt.REQUIREINPUT)
1009 && !avm.hasArgWithOption(Opt.INPUT))
1011 ArgValues tavs = avm.getOrCreateArgValues(a);
1021 private void incrementCount(String linkedId, ArgValues avs)
1024 if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
1026 for (String id : getLinkedIds())
1028 if (id == null || MATCHALLLINKEDIDS.equals(id))
1030 ArgValuesMap avm = linkedArgs.get(id);
1031 if (a.hasOption(Opt.REQUIREINPUT)
1032 && !avm.hasArgWithOption(Opt.INPUT))
1034 ArgValues tavs = avm.getOrCreateArgValues(a);
1035 tavs.incrementCount();
1040 avs.incrementCount();