JAL-629 More NG arguments: --features, --annotations, --sortbytree, --tree, --groovy...
[jalview.git] / src / jalview / bin / argparser / ArgParser.java
index 0ab5987..dd863d1 100644 (file)
@@ -26,7 +26,9 @@ import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.EnumSet;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -37,6 +39,7 @@ import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.bin.argparser.Arg.Opt;
 import jalview.util.FileUtils;
 import jalview.bin.Jalview;
 import jalview.bin.argparser.Arg.Opt;
 import jalview.util.FileUtils;
+import jalview.util.HttpUtils;
 
 public class ArgParser
 {
 
 public class ArgParser
 {
@@ -49,6 +52,9 @@ public class ArgParser
   // the default linked id prefix used for no id (not even square braces)
   protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
 
   // the default linked id prefix used for no id (not even square braces)
   protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
 
+  // 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
   private int defaultLinkedIdCounter = 0;
 
   // the counter added to the default linked id prefix
   private int defaultLinkedIdCounter = 0;
 
@@ -92,19 +98,28 @@ public class ArgParser
   private static final String ARGFILEDIRNAME = "{argfiledirname}";
 
   // flag to say whether {n} subtitutions in output filenames should be made.
   private static final String ARGFILEDIRNAME = "{argfiledirname}";
 
   // flag to say whether {n} subtitutions in output filenames should be made.
-  // Turn on and off with --subs and --nosubs
-  private boolean substitutions = false;
+  // 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
+  private boolean allLinkedIds = false;
 
   protected static final Map<String, Arg> argMap;
 
   protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
 
 
   protected static final Map<String, Arg> argMap;
 
   protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
 
-  protected List<String> linkedOrder = null;
+  protected List<String> linkedOrder = new ArrayList<>();
 
 
-  protected List<Arg> argList;
+  protected List<Arg> argList = new ArrayList<>();
 
   private static final char ARGFILECOMMENT = '#';
 
 
   private static final char ARGFILECOMMENT = '#';
 
+  private int argIndex = 0;
+
+  private BootstrapArgs bootstrapArgs = null;
+
   static
   {
     argMap = new HashMap<>();
   static
   {
     argMap = new HashMap<>();
@@ -134,10 +149,11 @@ public class ArgParser
 
   public ArgParser(String[] args)
   {
 
   public ArgParser(String[] args)
   {
-    this(args, false);
+    this(args, false, null);
   }
 
   }
 
-  public ArgParser(String[] args, boolean initsubstitutions)
+  public ArgParser(String[] args, boolean initsubstitutions,
+          BootstrapArgs bsa)
   {
     // Make a mutable new ArrayList so that shell globbing parser works.
     // (When shell file globbing is used, there are a sequence of non-Arg
   {
     // Make a mutable new ArrayList so that shell globbing parser works.
     // (When shell file globbing is used, there are a sequence of non-Arg
@@ -145,16 +161,17 @@ public class ArgParser
     // consumed by the --append/--argfile/etc Arg which is most easily done by
     // removing these filenames from the list one at a time. This can't be done
     // with an ArrayList made with only Arrays.asList(String[] args). )
     // consumed by the --append/--argfile/etc Arg which is most easily done by
     // removing these filenames from the list one at a time. This can't be done
     // with an ArrayList made with only Arrays.asList(String[] args). )
-    this(new ArrayList<>(Arrays.asList(args)), initsubstitutions);
+    this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false,
+            bsa);
   }
 
   public ArgParser(List<String> args, boolean initsubstitutions)
   {
   }
 
   public ArgParser(List<String> args, boolean initsubstitutions)
   {
-    this(args, initsubstitutions, false);
+    this(args, initsubstitutions, false, null);
   }
 
   public ArgParser(List<String> args, boolean initsubstitutions,
   }
 
   public ArgParser(List<String> args, boolean initsubstitutions,
-          boolean allowPrivate)
+          boolean allowPrivate, BootstrapArgs bsa)
   {
     // do nothing if there are no "--" args and (some "-" args || >0 arg is
     // "open")
   {
     // do nothing if there are no "--" args and (some "-" args || >0 arg is
     // "open")
@@ -178,6 +195,10 @@ public class ArgParser
       parse(new ArrayList<String>(), false, false);
       return;
     }
       parse(new ArrayList<String>(), false, false);
       return;
     }
+    if (bsa != null)
+      this.bootstrapArgs = bsa;
+    else
+      this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
     parse(args, initsubstitutions, allowPrivate);
   }
 
     parse(args, initsubstitutions, allowPrivate);
   }
 
@@ -185,19 +206,20 @@ public class ArgParser
           boolean allowPrivate)
   {
     this.substitutions = initsubstitutions;
           boolean allowPrivate)
   {
     this.substitutions = initsubstitutions;
-    int argIndex = 0;
     boolean openEachInitialFilenames = true;
     for (int i = 0; i < args.size(); i++)
     {
       String arg = args.get(i);
 
     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 "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
+      // 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)
       // single arg[i] and increment the defaultLinkedIdCounter so that each of
       // these files is opened separately.
       if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH)
-              && !arg.startsWith("-") && new File(arg).exists())
+              && !arg.startsWith("-") && !arg.equals("open")
+              && (new File(arg).exists()
+                      || HttpUtils.startsWithHttpOrHttps(arg)))
       {
         arg = Arg.OPEN.argString();
       }
       {
         arg = Arg.OPEN.argString();
       }
@@ -247,7 +269,9 @@ public class ArgParser
         if (a == null)
         {
           // arg not found
         if (a == null)
         {
           // arg not found
-          Console.error("Argument '" + arg + "' not recognised. Ignoring.");
+          Console.error("Argument '" + arg + "' not recognised.  Exiting.");
+          Jalview.exit("Unrecognised command line argument '" + arg + "'",
+                  13);
           continue;
         }
         if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
           continue;
         }
         if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
@@ -331,11 +355,7 @@ public class ArgParser
 
         // make NOACTION adjustments
         // default and auto counter increments
 
         // make NOACTION adjustments
         // default and auto counter increments
-        if (a == Arg.INCREMENT)
-        {
-          defaultLinkedIdCounter++;
-        }
-        else if (a == Arg.NPP)
+        if (a == Arg.NPP)
         {
           linkedIdAutoCounter++;
         }
         {
           linkedIdAutoCounter++;
         }
@@ -351,25 +371,29 @@ public class ArgParser
         {
           argFile = null;
         }
         {
           argFile = null;
         }
+        else if (a == Arg.ALL)
+        {
+          allLinkedIds = !negated;
+        }
+
+        // this is probably only Arg.NEW and Arg.OPEN
+        if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
+        {
+          // use the next default prefixed OPENLINKEDID
+          defaultLinkedId(true);
+        }
 
         String autoCounterString = null;
         boolean usingAutoCounterLinkedId = false;
 
         String autoCounterString = null;
         boolean usingAutoCounterLinkedId = false;
-        String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
-                .append(Integer.toString(defaultLinkedIdCounter))
-                .toString();
+        String defaultLinkedId = defaultLinkedId(false);
         boolean usingDefaultLinkedId = false;
         if (a.hasOption(Opt.LINKED))
         {
           if (linkedId == null)
           {
         boolean usingDefaultLinkedId = false;
         if (a.hasOption(Opt.LINKED))
         {
           if (linkedId == null)
           {
-            if (a == Arg.OPEN)
+            if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
             {
             {
-              // use the next default prefixed OPENLINKEDID
-              // NOW using the linkedIdAutoCounter
-              defaultLinkedIdCounter++;
-              linkedId = new StringBuilder(OPENLINKEDIDPREFIX)
-                      .append(Integer.toString(defaultLinkedIdCounter))
-                      .toString();
+              linkedId = MATCHALLLINKEDIDS;
             }
             else
             {
             }
             else
             {
@@ -402,13 +426,13 @@ public class ArgParser
           }
         }
 
           }
         }
 
-        if (!linkedArgs.containsKey(linkedId))
-          linkedArgs.put(linkedId, new ArgValuesMap());
-
-        // do not continue for NOACTION args
+        // do not continue in this block for NOACTION args
         if (a.hasOption(Opt.NOACTION))
           continue;
 
         if (a.hasOption(Opt.NOACTION))
           continue;
 
+        if (!linkedArgs.containsKey(linkedId))
+          linkedArgs.put(linkedId, new ArgValuesMap());
+
         ArgValuesMap avm = linkedArgs.get(linkedId);
 
         // not dealing with both NODUPLICATEVALUES and GLOB
         ArgValuesMap avm = linkedArgs.get(linkedId);
 
         // not dealing with both NODUPLICATEVALUES and GLOB
@@ -430,7 +454,10 @@ public class ArgParser
           continue;
         }
 
           continue;
         }
 
-        boolean argIndexIncremented = false;
+        /* TODO
+         * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*"
+         * DONE, need to check
+         */
         ArgValues avs = avm.getOrCreateArgValues(a);
 
         // store appropriate String value(s)
         ArgValues avs = avm.getOrCreateArgValues(a);
 
         // store appropriate String value(s)
@@ -439,50 +466,86 @@ public class ArgParser
           if (a.hasOption(Opt.GLOB) && globVals != null
                   && globVals.size() > 0)
           {
           if (a.hasOption(Opt.GLOB) && globVals != null
                   && globVals.size() > 0)
           {
-            for (String v : globVals)
+            Enumeration<String> gve = Collections.enumeration(globVals);
+            while (gve.hasMoreElements())
             {
             {
-              v = makeSubstitutions(v, linkedId);
+              String v = gve.nextElement();
               SubVals vsv = new SubVals(globSubVals, v);
               SubVals vsv = new SubVals(globSubVals, v);
-              avs.addValue(vsv, v, argIndex++);
-              argIndexIncremented = true;
+              addValue(linkedId, avs, vsv, v, argIndex++, true);
+              // if we're using defaultLinkedId and the arg increments the
+              // counter:
+              if (gve.hasMoreElements() && usingDefaultLinkedId
+                      && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
+              {
+                // increment the default linkedId
+                linkedId = defaultLinkedId(true);
+                // get new avm and avs
+                avm = linkedArgs.get(linkedId);
+                avs = avm.getOrCreateArgValues(a);
+              }
             }
           }
           else
           {
             }
           }
           else
           {
-            avs.addValue(makeSubstitutions(val, linkedId), argIndex);
+            addValue(linkedId, avs, val, argIndex, true);
           }
         }
         else if (a.hasOption(Opt.BOOLEAN))
         {
           }
         }
         else if (a.hasOption(Opt.BOOLEAN))
         {
-          avs.setBoolean(!negated, argIndex);
-          avs.setNegated(negated);
+          setBoolean(linkedId, avs, !negated, argIndex);
+          setNegated(linkedId, avs, negated);
         }
         else if (a.hasOption(Opt.UNARY))
         {
         }
         else if (a.hasOption(Opt.UNARY))
         {
-          avs.setBoolean(true, argIndex);
+          setBoolean(linkedId, avs, true, argIndex);
         }
         }
-        avs.incrementCount();
-        if (!argIndexIncremented)
-          argIndex++;
 
 
-        // store in appropriate place
-        if (a.hasOption(Opt.LINKED))
+        // remove the '*' linkedId that should be empty if it was created
+        if (MATCHALLLINKEDIDS.equals(linkedId)
+                && linkedArgs.containsKey(linkedId))
         {
         {
-          // store the order of linkedIds
-          if (linkedOrder == null)
-            linkedOrder = new ArrayList<>();
-          if (!linkedOrder.contains(linkedId))
-            linkedOrder.add(linkedId);
+          linkedArgs.remove(linkedId);
         }
         }
+      }
+    }
+  }
+
+  private void finaliseStoringArgValue(String linkedId, ArgValues avs)
+  {
+    Arg a = avs.arg();
+    incrementCount(linkedId, avs);
+    argIndex++;
+
+    // store in appropriate place
+    if (a.hasOption(Opt.LINKED))
+    {
+      // store the order of linkedIds
+      if (!linkedOrder.contains(linkedId))
+        linkedOrder.add(linkedId);
+    }
 
 
-        // store arg in the list of args used
-        if (argList == null)
-          argList = new ArrayList<>();
-        if (!argList.contains(a))
-          argList.add(a);
+    // store arg in the list of args used
+    if (!argList.contains(a))
+      argList.add(a);
+  }
 
 
+  private String defaultLinkedId(boolean increment)
+  {
+    String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
+            .append(Integer.toString(defaultLinkedIdCounter)).toString();
+    if (increment)
+    {
+      while (linkedArgs.containsKey(defaultLinkedId))
+      {
+        defaultLinkedIdCounter++;
+        defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX)
+                .append(Integer.toString(defaultLinkedIdCounter))
+                .toString();
       }
     }
       }
     }
+    if (!linkedArgs.containsKey(defaultLinkedId))
+      linkedArgs.put(defaultLinkedId, new ArgValuesMap());
+    return defaultLinkedId;
   }
 
   public String makeSubstitutions(String val, String linkedId)
   }
 
   public String makeSubstitutions(String val, String linkedId)
@@ -565,9 +628,24 @@ public class ArgParser
     return vals;
   }
 
     return vals;
   }
 
+  public BootstrapArgs getBootstrapArgs()
+  {
+    return bootstrapArgs;
+  }
+
   public boolean isSet(Arg a)
   {
   public boolean isSet(Arg a)
   {
-    return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a);
+    return a.hasOption(Opt.LINKED) ? isSetAtAll(a) : isSet(null, a);
+  }
+
+  public boolean isSetAtAll(Arg a)
+  {
+    for (String linkedId : linkedOrder)
+    {
+      if (isSet(linkedId, a))
+        return true;
+    }
+    return false;
   }
 
   public boolean isSet(String linkedId, Arg a)
   }
 
   public boolean isSet(String linkedId, Arg a)
@@ -576,7 +654,7 @@ public class ArgParser
     return avm == null ? false : avm.containsArg(a);
   }
 
     return avm == null ? false : avm.containsArg(a);
   }
 
-  public boolean getBool(Arg a)
+  public boolean getBoolean(Arg a)
   {
     if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
     {
   {
     if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
     {
@@ -595,12 +673,12 @@ public class ArgParser
     return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
   }
 
     return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
   }
 
-  public List<String> linkedIds()
+  public List<String> getLinkedIds()
   {
     return linkedOrder;
   }
 
   {
     return linkedOrder;
   }
 
-  public ArgValuesMap linkedArgs(String id)
+  public ArgValuesMap getLinkedArgs(String id)
   {
     return linkedArgs.get(id);
   }
   {
     return linkedArgs.get(id);
   }
@@ -611,16 +689,16 @@ public class ArgParser
     StringBuilder sb = new StringBuilder();
     sb.append("UNLINKED\n");
     sb.append(argValuesMapToString(linkedArgs.get(null)));
     StringBuilder sb = new StringBuilder();
     sb.append("UNLINKED\n");
     sb.append(argValuesMapToString(linkedArgs.get(null)));
-    if (linkedIds() != null)
+    if (getLinkedIds() != null)
     {
       sb.append("LINKED\n");
     {
       sb.append("LINKED\n");
-      for (String id : linkedIds())
+      for (String id : getLinkedIds())
       {
         // already listed these as UNLINKED args
         if (id == null)
           continue;
 
       {
         // already listed these as UNLINKED args
         if (id == null)
           continue;
 
-        ArgValuesMap avm = linkedArgs(id);
+        ArgValuesMap avm = getLinkedArgs(id);
         sb.append("ID: '").append(id).append("'\n");
         sb.append(argValuesMapToString(avm));
       }
         sb.append("ID: '").append(id).append("'\n");
         sb.append(argValuesMapToString(avm));
       }
@@ -643,7 +721,7 @@ public class ArgParser
   }
 
   public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
   }
 
   public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
-          boolean initsubstitutions)
+          boolean initsubstitutions, BootstrapArgs bsa)
   {
     List<File> argFiles = new ArrayList<>();
 
   {
     List<File> argFiles = new ArrayList<>();
 
@@ -653,11 +731,11 @@ public class ArgParser
       argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
     }
 
       argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
     }
 
-    return parseArgFileList(argFiles, initsubstitutions);
+    return parseArgFileList(argFiles, initsubstitutions, bsa);
   }
 
   public static ArgParser parseArgFileList(List<File> argFiles,
   }
 
   public static ArgParser parseArgFileList(List<File> argFiles,
-          boolean initsubstitutions)
+          boolean initsubstitutions, BootstrapArgs bsa)
   {
     List<String> argsList = new ArrayList<>();
     for (File argFile : argFiles)
   {
     List<String> argsList = new ArrayList<>();
     for (File argFile : argFiles)
@@ -685,7 +763,7 @@ public class ArgParser
     }
     // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
     // --unsetargfile
     }
     // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
     // --unsetargfile
-    return new ArgParser(argsList, initsubstitutions, true);
+    return new ArgParser(argsList, initsubstitutions, true, bsa);
   }
 
   protected static List<String> readArgFile(File argFile)
   }
 
   protected static List<String> readArgFile(File argFile)
@@ -717,19 +795,24 @@ public class ArgParser
     FIRST, BEFORE, AFTER
   }
 
     FIRST, BEFORE, AFTER
   }
 
-  public static String getValueFromSubValOrArg(ArgValuesMap avm, Arg a,
-          SubVals sv)
+  // 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)
   {
   {
-    return getFromSubValArgOrPref(avm, a, sv, null, null, null);
+    return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
   }
 
   }
 
-  public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
-          SubVals sv, String key, String pref, String def)
+  // 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)
   {
   {
-    return getFromSubValArgOrPref(avm, a, Position.FIRST, null, sv, key,
-            pref, def);
+    return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref,
+            def);
   }
 
   }
 
+  // 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)
   public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
           Position pos, ArgValue av, SubVals sv, String key, String pref,
           String def)
@@ -740,7 +823,6 @@ public class ArgParser
       return sv.get(key);
     if (avm != null && avm.containsArg(a))
     {
       return sv.get(key);
     if (avm != null && avm.containsArg(a))
     {
-      String val = null;
       if (pos == Position.FIRST && avm.getValue(a) != null)
         return avm.getValue(a);
       else if (pos == Position.BEFORE
       if (pos == Position.FIRST && avm.getValue(a) != null)
         return avm.getValue(a);
       else if (pos == Position.BEFORE
@@ -771,4 +853,145 @@ public class ArgParser
     return pref != null ? Cache.getDefault(pref, def) : def;
   }
 
     return pref != null ? Cache.getDefault(pref, def) : def;
   }
 
+  // the following methods look for the "*" linkedId and add the argvalue to all
+  // linkedId ArgValues if it does
+  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))
+    {
+      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);
+        String val = v;
+        if (doSubs)
+        {
+          val = makeSubstitutions(v, id);
+          sv = new SubVals(sv, val);
+        }
+        tavs.addValue(sv, val, argIndex);
+        finaliseStoringArgValue(id, tavs);
+      }
+    }
+    else
+    {
+      String val = v;
+      if (doSubs)
+      {
+        val = makeSubstitutions(v, linkedId);
+        sv = new SubVals(sv, val);
+      }
+      avs.addValue(sv, val, argIndex);
+      finaliseStoringArgValue(linkedId, avs);
+    }
+  }
+
+  private void addValue(String linkedId, ArgValues avs, String v,
+          int argIndex, boolean doSubs)
+  {
+    Arg a = avs.arg();
+    if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
+    {
+      for (String id : getLinkedIds())
+      {
+        if (id == null || MATCHALLLINKEDIDS.equals(id))
+          continue;
+        ArgValuesMap avm = linkedArgs.get(id);
+        // don't set an output if there isn't an input
+        if (a.hasOption(Opt.REQUIREINPUT)
+                && !avm.hasArgWithOption(Opt.INPUT))
+          continue;
+        ArgValues tavs = avm.getOrCreateArgValues(a);
+        String val = doSubs ? makeSubstitutions(v, id) : v;
+        tavs.addValue(val, argIndex);
+        finaliseStoringArgValue(id, tavs);
+      }
+    }
+    else
+    {
+      String val = doSubs ? makeSubstitutions(v, linkedId) : v;
+      avs.addValue(val, argIndex);
+      finaliseStoringArgValue(linkedId, avs);
+    }
+  }
+
+  private void setBoolean(String linkedId, ArgValues avs, boolean b,
+          int argIndex)
+  {
+    Arg a = avs.arg();
+    if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL))
+    {
+      for (String id : getLinkedIds())
+      {
+        if (id == null || MATCHALLLINKEDIDS.equals(id))
+          continue;
+        ArgValuesMap avm = linkedArgs.get(id);
+        if (a.hasOption(Opt.REQUIREINPUT)
+                && !avm.hasArgWithOption(Opt.INPUT))
+          continue;
+        ArgValues tavs = avm.getOrCreateArgValues(a);
+        tavs.setBoolean(b, argIndex);
+        finaliseStoringArgValue(id, tavs);
+      }
+    }
+    else
+    {
+      avs.setBoolean(b, argIndex);
+      finaliseStoringArgValue(linkedId, avs);
+    }
+  }
+
+  private void setNegated(String linkedId, ArgValues avs, boolean b)
+  {
+    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);
+    }
+  }
+
+  private void incrementCount(String linkedId, ArgValues avs)
+  {
+    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();
+    }
+  }
+
 }
\ No newline at end of file
 }
\ No newline at end of file