import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.EnumSet;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import jalview.bin.Cache;
import jalview.bin.Console;
import jalview.bin.Jalview;
import jalview.bin.argparser.Arg.Opt;
import jalview.util.FileUtils;
+import jalview.util.HttpUtils;
public class ArgParser
{
// 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 substitution string used to use the defaultLinkedIdCounter
private static final String DEFAULTLINKEDIDCOUNTER = "{}";
- // the counter added to the default linked id prefix
- private int opennewLinkedIdCounter = 0;
+ // the counter added to the default linked id prefix. NOW using
+ // linkedIdAutoCounter
+ // private int openLinkedIdCounter = 0;
- // the linked id prefix used for --opennew files
- protected static final String OPENNEWLINKEDIDPREFIX = "OPENNEW:";
+ // the linked id prefix used for --open files. NOW the same as DEFAULT
+ protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX;
// the counter used for {n} substitutions
private int linkedIdAutoCounter = 0;
// the linked id substitution string used to use the idCounter
private static final String LINKEDIDAUTOCOUNTER = "{n}";
- // the linked id substitution string used to use the base filename of --open
- // or --opennew
+ // the linked id substitution string used to use the base filename of --append
+ // or --open
private static final String LINKEDIDBASENAME = "{basename}";
- // the linked id substitution string used to use the dir path of --open
- // or --opennew
+ // the linked id substitution string used to use the dir path of --append
+ // or --open
private static final String LINKEDIDDIRNAME = "{dirname}";
// the current argfile
// Turn on and off with --subs and --nosubs
private boolean substitutions = false;
+ // 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 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 int argIndex = 0;
+
static
{
argMap = new HashMap<>();
// 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
+ // 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);
public ArgParser(List<String> args, boolean initsubstitutions,
boolean allowPrivate)
{
- // do nothing if there are no "--" args and some "-" args
+ // do nothing if there are no "--" args and (some "-" args || >0 arg is
+ // "open")
boolean d = false;
boolean dd = false;
for (String arg : args)
dd = true;
break;
}
- else if (arg.startsWith("-"))
+ else if (arg.startsWith("-") || arg.equals("open"))
{
d = true;
}
boolean allowPrivate)
{
this.substitutions = initsubstitutions;
- int argIndex = 0;
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)
- && !arg.startsWith("-") && new File(arg).exists())
+ && !arg.startsWith("-") && !arg.equals("open")
+ && (new File(arg).exists()
+ || HttpUtils.startsWithHttpOrHttps(arg)))
{
- arg = Arg.OPENNEW.argString();
+ arg = Arg.OPEN.argString();
}
else
{
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)
// make NOACTION adjustments
// default and auto counter increments
- if (a == Arg.INCREMENT)
+ if (a == Arg.NEWFRAME)
{
defaultLinkedIdCounter++;
}
{
argFile = null;
}
+ else if (a == Arg.ALLFRAMES)
+ {
+ allLinkedIds = !negated;
+ }
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)
{
- if (a == Arg.OPENNEW)
+ if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER))
{
- // use the next default prefixed OPENNEWLINKEDID
- linkedId = new StringBuilder(OPENNEWLINKEDIDPREFIX)
- .append(Integer.toString(opennewLinkedIdCounter))
- .toString();
- opennewLinkedIdCounter++;
+ // use the next default prefixed OPENLINKEDID
+ defaultLinkedId = defaultLinkedId(true);
+ }
+ if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
+ {
+ linkedId = MATCHALLLINKEDIDS;
}
else
{
}
}
- if (!linkedArgs.containsKey(linkedId))
- linkedArgs.put(linkedId, new ArgValuesMap());
-
// do not continue for NOACTION args
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
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)
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);
- 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
{
- avs.addValue(makeSubstitutions(val, linkedId), argIndex);
+ addValue(linkedId, avs, val, argIndex, true);
}
}
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))
{
- 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 arg in the list of args used
- if (argList == null)
- argList = new ArrayList<>();
- if (!argList.contains(a))
- argList.add(a);
+ // 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.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)
return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
}
- public List<String> linkedIds()
+ public List<String> getLinkedIds()
{
return linkedOrder;
}
- public ArgValuesMap linkedArgs(String id)
+ public ArgValuesMap getLinkedArgs(String id)
{
return linkedArgs.get(id);
}
StringBuilder sb = new StringBuilder();
sb.append("UNLINKED\n");
sb.append(argValuesMapToString(linkedArgs.get(null)));
- if (linkedIds() != null)
+ if (getLinkedIds() != null)
{
sb.append("LINKED\n");
- for (String id : linkedIds())
+ for (String id : getLinkedIds())
{
// 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));
}
return args;
}
+ public static enum Position
+ {
+ FIRST, BEFORE, AFTER
+ }
+
+ // 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, av, a, sv, null, null, null);
+ }
+
+ // 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.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)
+ {
+ if (key == null)
+ key = a.getName();
+ if (sv != null && sv.has(key) && sv.get(key) != null)
+ return sv.get(key);
+ if (avm != null && avm.containsArg(a))
+ {
+ if (pos == Position.FIRST && avm.getValue(a) != null)
+ return avm.getValue(a);
+ else if (pos == Position.BEFORE
+ && avm.getClosestPreviousArgValueOfArg(av, a) != null)
+ return avm.getClosestPreviousArgValueOfArg(av, a).getValue();
+ else if (pos == Position.AFTER
+ && avm.getClosestNextArgValueOfArg(av, a) != null)
+ return avm.getClosestNextArgValueOfArg(av, a).getValue();
+ }
+ return pref != null ? Cache.getDefault(pref, def) : def;
+ }
+
+ public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
+ SubVals sv)
+ {
+ return getFromSubValArgOrPref(avm, a, sv, null, null, false);
+ }
+
+ public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+ SubVals sv, String key, String pref, boolean def)
+ {
+ if (key == null)
+ key = a.getName();
+ if (sv != null && sv.has(key) && sv.get(key) != null)
+ return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
+ if (avm != null && avm.containsArg(a))
+ return avm.getBoolean(a);
+ 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