JAL-629 Don't use new ArgParser if there are no --args and some -args
[jalview.git] / src / jalview / bin / argparser / ArgParser.java
index 82b1b92..54f57fe 100644 (file)
@@ -49,6 +49,12 @@ public class ArgParser
   // the counter added to the default linked id prefix
   private int defaultLinkedIdCounter = 0;
 
+  // the linked id prefix used for --opennew files
+  protected static final String OPENNEWLINKEDIDPREFIX = "OPENNEW:";
+
+  // the counter added to the default linked id prefix
+  private int opennewLinkedIdCounter = 0;
+
   // the linked id used to increment the idCounter (and use the incremented
   // value)
   private static final String INCREMENTAUTOCOUNTERLINKEDID = "{++n}";
@@ -56,7 +62,7 @@ public class ArgParser
   // the linked id used to use the idCounter
   private static final String AUTOCOUNTERLINKEDID = "{n}";
 
-  private int idCounter = 0;
+  private int linkedIdAutoCounter = 0;
 
   // flag to say whether {n} subtitutions in output filenames should be made.
   // Turn on and off with --subs and --nosubs
@@ -98,27 +104,68 @@ public class ArgParser
 
   public ArgParser(String[] args)
   {
-    // make a mutable new ArrayList so that shell globbing parser works
+    // Make a mutable new ArrayList so that shell globbing parser works.
+    // (When shell file globbing is used, there are a sequence of non-Arg
+    // arguments (which are the expanded globbed filenames) that need to be
+    // consumed by the --open/--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)));
   }
 
   public ArgParser(List<String> args)
   {
-    init(args);
+    // do nothing if there are no "--" args and some "-" args
+    boolean d = false;
+    boolean dd = false;
+    for (String arg : args)
+    {
+      if (arg.startsWith(DOUBLEDASH))
+      {
+        dd = true;
+        break;
+      }
+      else if (arg.startsWith("-"))
+      {
+        d = true;
+      }
+    }
+    if (d && !dd)
+    {
+      // leave it to the old style -- parse an empty list
+      parse(new ArrayList<String>());
+      return;
+    }
+    parse(args);
   }
 
-  private void init(List<String> args)
+  private void parse(List<String> args)
   {
-    // Enumeration<String> argE = Collections.enumeration(args);
     int argIndex = 0;
-    // while (argE.hasMoreElements())
+    boolean openEachInitialFilenames = true;
     for (int i = 0; i < args.size(); i++)
     {
-      // String arg = argE.nextElement();
       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
+      // 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 = DOUBLEDASH + Arg.OPENNEW.getName();
+      }
+      else
+      {
+        openEachInitialFilenames = false;
+      }
+
       String argName = null;
       String val = null;
-      List<String> vals = null; // for Opt.GLOB only
+      List<String> globVals = null; // for Opt.GLOB only
+      SubVals globSubVals = null; // also for use by Opt.GLOB only
       String linkedId = null;
       if (arg.startsWith(DOUBLEDASH))
       {
@@ -183,28 +230,50 @@ public class ArgParser
           continue;
         }
 
-        if (a.hasOption(Opt.STRING) && equalPos == -1)
+        // String value(s)
+        if (a.hasOption(Opt.STRING))
         {
-          // take next arg as value if required, and '=' was not found
-          // if (!argE.hasMoreElements())
-          if (i + 1 >= args.size())
-          {
-            // no value to take for arg, which wants a value
-            Console.error("Argument '" + a.getName()
-                    + "' requires a value, none given. Ignoring.");
-            continue;
-          }
-          // deal with bash globs here (--arg val* is expanded before reaching
-          // the JVM). Note that SubVals cannot be used in this case.
-          // If using the --arg=val then the glob is preserved and Java globs
-          // will be used later. SubVals can be used.
-          if (a.hasOption(Opt.GLOB))
+          if (equalPos >= 0)
           {
-            vals.addAll(getShellGlobbedFilenameValues(a, args, i + 1));
+            if (a.hasOption(Opt.GLOB))
+            {
+              // strip off and save the SubVals to be added individually later
+              globSubVals = ArgParser.getSubVals(val);
+              globVals = FileUtils
+                      .getFilenamesFromGlob(globSubVals.getContent());
+            }
+            else
+            {
+              // val is already set -- will be saved in the ArgValue later in
+              // the normal way
+            }
           }
           else
           {
-            val = args.get(i + 1);
+            // There is no "=" so value is next arg or args (possibly shell
+            // glob-expanded)
+            if (i + 1 >= args.size())
+            {
+              // no value to take for arg, which wants a value
+              Console.error("Argument '" + a.getName()
+                      + "' requires a value, none given. Ignoring.");
+              continue;
+            }
+            // deal with bash globs here (--arg val* is expanded before reaching
+            // the JVM). Note that SubVals cannot be used in this case.
+            // If using the --arg=val then the glob is preserved and Java globs
+            // will be used later. SubVals can be used.
+            if (a.hasOption(Opt.GLOB))
+            {
+              // if this is the first argument with a file list at the start of
+              // the args we add filenames from index i instead of i+1
+              globVals = getShellGlobbedFilenameValues(a, args,
+                      openEachInitialFilenames ? i : i + 1);
+            }
+            else
+            {
+              val = args.get(i + 1);
+            }
           }
         }
 
@@ -216,7 +285,7 @@ public class ArgParser
         }
         else if (a == Arg.NPP)
         {
-          idCounter++;
+          linkedIdAutoCounter++;
         }
         else if (a == Arg.SUBSTITUTIONS)
         {
@@ -233,26 +302,39 @@ public class ArgParser
         {
           if (linkedId == null)
           {
-            // use default linkedId for linked arguments
-            linkedId = defaultLinkedId;
-            usingDefaultLinkedId = true;
-            Console.debug(
-                    "Changing linkedId to '" + linkedId + "' from " + arg);
+            if (a == Arg.OPENNEW)
+            {
+              // use the next default prefixed OPENNEWLINKEDID
+              linkedId = new StringBuilder(OPENNEWLINKEDIDPREFIX)
+                      .append(Integer.toString(opennewLinkedIdCounter))
+                      .toString();
+              opennewLinkedIdCounter++;
+            }
+            else
+            {
+              // use default linkedId for linked arguments
+              linkedId = defaultLinkedId;
+              usingDefaultLinkedId = true;
+              Console.debug("Changing linkedId to '" + linkedId + "' from "
+                      + arg);
+            }
           }
-          else if (linkedId.equals(AUTOCOUNTERLINKEDID))
+          else if (linkedId.contains(AUTOCOUNTERLINKEDID))
           {
             // turn {n} to the autoCounter
-            autoCounterString = Integer.toString(idCounter);
-            linkedId = autoCounterString;
+            autoCounterString = Integer.toString(linkedIdAutoCounter);
+            linkedId = linkedId.replace(AUTOCOUNTERLINKEDID,
+                    autoCounterString);
             usingAutoCounterLinkedId = true;
             Console.debug(
                     "Changing linkedId to '" + linkedId + "' from " + arg);
           }
-          else if (linkedId.equals(INCREMENTAUTOCOUNTERLINKEDID))
+          else if (linkedId.contains(INCREMENTAUTOCOUNTERLINKEDID))
           {
             // turn {++n} to the incremented autoCounter
-            autoCounterString = Integer.toString(++idCounter);
-            linkedId = autoCounterString;
+            autoCounterString = Integer.toString(++linkedIdAutoCounter);
+            linkedId = linkedId.replace(INCREMENTAUTOCOUNTERLINKEDID,
+                    autoCounterString);
             usingAutoCounterLinkedId = true;
             Console.debug(
                     "Changing linkedId to '" + linkedId + "' from " + arg);
@@ -278,8 +360,8 @@ public class ArgParser
         }
 
         // check for unique id
-        SubVals sv = ArgParser.getSubVals(val);
-        String id = sv.get(ArgValues.ID);
+        SubVals idsv = ArgParser.getSubVals(val);
+        String id = idsv.get(ArgValues.ID);
         if (id != null && avm.hasId(a, id))
         {
           Console.error("Argument '--" + argName + "' has a duplicate id ('"
@@ -287,19 +369,21 @@ public class ArgParser
           continue;
         }
 
+        boolean argIndexIncremented = false;
         ArgValues avs = avm.getOrCreateArgValues(a);
-        if (avs == null)
-        {
-          avs = new ArgValues(a);
-        }
-        // store appropriate value
+
+        // store appropriate String value(s)
         if (a.hasOption(Opt.STRING))
         {
-          if (a.hasOption(Opt.GLOB) && vals != null && vals.size() > 0)
+          if (a.hasOption(Opt.GLOB) && globVals != null
+                  && globVals.size() > 0)
           {
-            for (String v : vals)
+            for (String v : globVals)
             {
-              avs.addValue(makeSubstitutions(v), argIndex++);
+              v = makeSubstitutions(v);
+              SubVals vsv = new SubVals(globSubVals, v);
+              avs.addValue(vsv, v, argIndex++);
+              argIndexIncremented = true;
             }
           }
           else
@@ -317,13 +401,12 @@ public class ArgParser
           avs.setBoolean(true, argIndex);
         }
         avs.incrementCount();
+        if (!argIndexIncremented)
+          argIndex++;
 
         // store in appropriate place
         if (a.hasOption(Opt.LINKED))
         {
-          // allow a default linked id for single usage
-          if (linkedId == null)
-            linkedId = defaultLinkedId;
           // store the order of linkedIds
           if (linkedOrder == null)
             linkedOrder = new ArrayList<>();
@@ -336,6 +419,7 @@ public class ArgParser
           argList = new ArrayList<>();
         if (!argList.contains(a))
           argList.add(a);
+
       }
     }
   }
@@ -360,9 +444,14 @@ public class ArgParser
       subvals = "";
       rest = val;
     }
-    rest.replace(AUTOCOUNTERLINKEDID, String.valueOf(idCounter));
-    rest.replace(INCREMENTAUTOCOUNTERLINKEDID, String.valueOf(++idCounter));
-    rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
+    if ((rest.contains(AUTOCOUNTERLINKEDID)))
+      rest = rest.replace(AUTOCOUNTERLINKEDID,
+              String.valueOf(linkedIdAutoCounter));
+    if ((rest.contains(INCREMENTAUTOCOUNTERLINKEDID)))
+      rest = rest.replace(INCREMENTAUTOCOUNTERLINKEDID,
+              String.valueOf(++linkedIdAutoCounter));
+    if ((rest.contains("{}")))
+      rest = rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
 
     return new StringBuilder(subvals).append(rest).toString();
   }
@@ -383,7 +472,7 @@ public class ArgParser
     List<String> vals = new ArrayList<>();
     while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH))
     {
-      vals.add(args.remove(i));
+      vals.add(FileUtils.substituteHomeDir(args.remove(i)));
       if (!a.hasOption(Opt.GLOB))
         break;
     }