import jalview.bin.Cache;
import jalview.bin.Console;
import jalview.bin.Jalview;
+import jalview.bin.Jalview.ExitCode;
import jalview.bin.argparser.Arg.Opt;
import jalview.bin.argparser.Arg.Type;
import jalview.util.FileUtils;
protected static final String DOUBLEDASH = "--";
- protected static final char EQUALS = '=';
+ public static final char EQUALS = '=';
+
+ public static final String STDOUTFILENAME = "-";
protected static final String NEGATESTRING = "no";
- // the default linked id prefix used for no id (not even square braces)
+ /**
+ * the default linked id prefix used for no id (ie when not even square braces
+ * are provided)
+ */
protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
- // the linkedId string used to match all linkedIds seen so far
+ /**
+ * the linkedId string used to match all linkedIds seen so far
+ */
protected static final String MATCHALLLINKEDIDS = "*";
- // the linkedId string used to match all of the last --open'ed linkedIds
+ /**
+ * the linkedId string used to match all of the last --open'ed linkedIds
+ */
protected static final String MATCHOPENEDLINKEDIDS = "open*";
- // the counter added to the default linked id prefix
+ /**
+ * the counter added to the default linked id prefix
+ */
private int defaultLinkedIdCounter = 0;
- // the substitution string used to use the defaultLinkedIdCounter
+ /**
+ * the substitution string used to use the defaultLinkedIdCounter
+ */
private static final String DEFAULTLINKEDIDCOUNTER = "{}";
- // the counter added to the default linked id prefix. NOW using
- // linkedIdAutoCounter
- // private int openLinkedIdCounter = 0;
-
- // the linked id prefix used for --open files. NOW the same as DEFAULT
+ /**
+ * 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
+ /**
+ * the counter used for {n} substitutions
+ */
private int linkedIdAutoCounter = 0;
- // the linked id substitution string used to increment the idCounter (and use
- // the incremented value)
+ /**
+ * the linked id substitution string used to increment the idCounter (and use
+ * the incremented value)
+ */
private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}";
- // the linked id substitution string used to use the idCounter
+ /**
+ * 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 filename extension of
- // --append
- // or --open
+ /**
+ * the linked id substitution string used to use the filename extension of
+ * --append or --open
+ */
private static final String LINKEDIDEXTENSION = "{extension}";
- // the linked id substitution string used to use the base filename of --append
- // or --open
+ /**
+ * 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 --append
- // or --open
+ /**
+ * the linked id substitution string used to use the dir path of --append or
+ * --open
+ */
private static final String LINKEDIDDIRNAME = "{dirname}";
- // the current argfile
+ /**
+ * the current argfile
+ */
private String argFile = null;
- // the linked id substitution string used to use the dir path of the latest
- // --argfile name
+ /**
+ * the linked id substitution string used to use the dir path of the latest
+ */
+ /** --argfile name */
private static final String ARGFILEBASENAME = "{argfilebasename}";
- // the linked id substitution string used to use the dir path of the latest
- // --argfile name
+ /**
+ * the linked id substitution string used to use the dir path of the latest
+ * --argfile name
+ */
private static final String ARGFILEDIRNAME = "{argfiledirname}";
- // flag to say whether {n} subtitutions in output filenames should be made.
- // Turn on and off with --substitutions and --nosubstitutions
- // Start with it on
+ /**
+ * flag to say whether {n} subtitutions in output filenames should be made.
+ * 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
+ /**
+ * flag to say whether the default linkedId is the current default linked id
+ *
+ * or ALL linkedIds
+ */
private boolean allLinkedIds = false;
- // flag to say whether the default linkedId is the current default linked id
- // or OPENED linkedIds
- private boolean openedLinkedIds = false;
-
- // flag to say whether the structure arguments should be applied to all
- // structures with this linked id
+ /**
+ * flag to say whether the structure arguments should be applied to all
+ * structures with this linked id
+ */
private boolean allStructures = false;
protected static final Map<String, Arg> argMap;
private BootstrapArgs bootstrapArgs = null;
+ private boolean oldArguments = false;
+
+ private boolean mixedArguments = false;
+
+ /**
+ * saved examples of mixed arguments
+ */
+ private String[] mixedExamples = new String[] { null, null };
+
static
{
argMap = new HashMap<>();
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
- // arguments (which are the expanded globbed filenames) that need to be
- // 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). )
+ /*
+ * 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 --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) as
+ * that is not mutable. )
+ */
this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false,
bsa);
}
if (arg.startsWith(DOUBLEDASH))
{
dd = true;
- break;
+ if (mixedExamples[1] == null)
+ {
+ mixedExamples[1] = arg;
+ }
}
- else if (arg.startsWith("-") || arg.equals("open"))
+ else if ((arg.startsWith("-") && !arg.equals(STDOUTFILENAME))
+ || arg.equals("open"))
{
d = true;
+ if (mixedExamples[0] == null)
+ {
+ mixedExamples[0] = arg;
+ }
+ }
+ }
+ if (d)
+ {
+ if (dd)
+ {
+ mixedArguments = true;
+ }
+ else
+ {
+ oldArguments = true;
}
}
- if (d && !dd)
+
+ if (oldArguments || mixedArguments)
{
// leave it to the old style -- parse an empty list
parse(new ArrayList<String>(), false, false);
return;
}
+
if (bsa != null)
this.bootstrapArgs = bsa;
else
boolean allowPrivate)
{
this.substitutions = initsubstitutions;
- 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 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("-") && !arg.equals("open")
- && (new File(arg).exists()
- || HttpUtils.startsWithHttpOrHttps(arg)))
- {
- arg = Arg.OPEN.argString();
- }
- else
+ /*
+ * If the first argument does not start with "--" or "-" or is not "open",
+ * and is a filename that exists or a URL, it is probably a file/list of
+ * files to open so we insert an Arg.OPEN argument before it. This will
+ * mean the list of files at the start of the arguments are all opened
+ * separately.
+ */
+ if (args.size() > 0)
+ {
+ String arg0 = args.get(0);
+ if (arg0 != null
+ && (!arg0.startsWith(DOUBLEDASH) && !arg0.startsWith("-")
+ && !arg0.equals("open") && (new File(arg0).exists()
+ || HttpUtils.startsWithHttpOrHttps(arg0))))
{
- openEachInitialFilenames = false;
+ // insert "--open" at the start
+ args.add(0, Arg.OPEN.argString());
}
+ }
+
+ for (int i = 0; i < args.size(); i++)
+ {
+ String arg = args.get(i);
// look for double-dash, e.g. --arg
if (arg.startsWith(DOUBLEDASH))
Arg a = argMap.get(argName);
// check for boolean prepended by "no" e.g. --nowrap
boolean negated = false;
- if (a == null && argName.startsWith(NEGATESTRING) && argMap
- .containsKey(argName.substring(NEGATESTRING.length())))
+ if (a == null)
{
- argName = argName.substring(NEGATESTRING.length());
- a = argMap.get(argName);
- negated = true;
+ if (argName.startsWith(NEGATESTRING) && argMap
+ .containsKey(argName.substring(NEGATESTRING.length())))
+ {
+ argName = argName.substring(NEGATESTRING.length());
+ a = argMap.get(argName);
+ negated = true;
+ }
+ else
+ {
+ // after all other args, look for Opt.PREFIXKEV args if still not
+ // found
+ for (Arg potentialArg : EnumSet.allOf(Arg.class))
+ {
+ if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
+ && argName.startsWith(potentialArg.getName())
+ && equalPos > -1)
+ {
+ val = argName.substring(potentialArg.getName().length())
+ + EQUALS + val;
+ argName = argName.substring(0,
+ potentialArg.getName().length());
+ a = potentialArg;
+ break;
+ }
+ }
+ }
}
// check for config errors
{
// arg not found
Console.error("Argument '" + arg + "' not recognised. Exiting.");
- Jalview.exit("Invalid argument used." + System.lineSeparator()
- + "Use" + System.lineSeparator() + "jalview "
- + Arg.HELP.argString() + System.lineSeparator()
- + "for a usage statement.", 13);
+ Jalview.exit(
+ "Invalid argument used." + System.lineSeparator() + "Use"
+ + System.lineSeparator() + "jalview "
+ + Arg.HELP.argString() + System.lineSeparator()
+ + "for a usage statement.",
+ ExitCode.INVALID_ARGUMENT);
continue;
}
if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
{
// There is no "=" so value is next arg or args (possibly shell
// glob-expanded)
- if ((openEachInitialFilenames ? i : i + 1) >= args.size())
+ if (i + 1 >= args.size())
{
// no value to take for arg, which wants a value
Console.error("Argument '" + a.getName()
{
// 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);
+ globVals = getShellGlobbedFilenameValues(a, args, i + 1);
}
else
{
else if (a == Arg.ALL)
{
allLinkedIds = !negated;
- openedLinkedIds = false;
- }
- else if (a == Arg.OPENED)
- {
- openedLinkedIds = !negated;
- allLinkedIds = false;
}
else if (a == Arg.ALLSTRUCTURES)
{
{
if (linkedId == null)
{
- if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL)
- && val.startsWith(MATCHALLLINKEDIDS))
+ if (a.hasOption(Opt.OUTPUTFILE) && a.hasOption(Opt.ALLOWMULTIID)
+ && val.contains(MATCHALLLINKEDIDS))
{
- // --output=*.ext is shorthand for --all --output {basename}.ext
+ // --output=*.ext is shorthand for --output {basename}.ext
+ // --output=*/*.ext is shorthand for
+ // --output {dirname}/{basename}.ext
// (or --image=*.ext)
- allLinkedIds = true;
- openedLinkedIds = false;
- linkedId = MATCHALLLINKEDIDS;
- val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME
- + val.substring(MATCHALLLINKEDIDS.length());
- }
- else if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL)
- && val.startsWith(MATCHOPENEDLINKEDIDS))
- {
- // --output=open*.ext is shorthand for --opened --output
- // {basename}.ext
- // (or --image=open*.ext)
- openedLinkedIds = true;
- allLinkedIds = false;
- linkedId = MATCHOPENEDLINKEDIDS;
- val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME
- + val.substring(MATCHOPENEDLINKEDIDS.length());
+ linkedId = allLinkedIds ? MATCHALLLINKEDIDS
+ : MATCHOPENEDLINKEDIDS;
+ val = FileUtils.convertWildcardsToPath(val, MATCHALLLINKEDIDS,
+ LINKEDIDDIRNAME, LINKEDIDBASENAME);
}
- else if (allLinkedIds && a.hasOption(Opt.ALLOWALL))
+ else if (allLinkedIds && a.hasOption(Opt.ALLOWMULTIID))
{
linkedId = MATCHALLLINKEDIDS;
}
- else if (openedLinkedIds && a.hasOption(Opt.ALLOWALL))
+ else if (a.hasOption(Opt.ALLOWMULTIID)
+ && this.storedLinkedIds != null
+ && this.storedLinkedIds.size() > 0)
{
linkedId = MATCHOPENEDLINKEDIDS;
}
// remove the '*' or 'open*' linkedId that should be empty if it was
// created
if ((MATCHALLLINKEDIDS.equals(linkedId)
+ || MATCHOPENEDLINKEDIDS.equals(linkedId))
&& linkedArgs.containsKey(linkedId))
- || (MATCHOPENEDLINKEDIDS.equals(linkedId)
- && linkedArgs.containsKey(linkedId)))
{
linkedArgs.remove(linkedId);
}
{
String message = Arg.ARGFILE.argString() + EQUALS + "\""
+ argFile.getPath() + "\": File does not exist.";
- Jalview.exit(message, 2);
+ Jalview.exit(message, ExitCode.FILE_NOT_FOUND);
}
try
{
{
String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
+ "\": File could not be read.";
- Jalview.exit(message, 3);
+ Jalview.exit(message, ExitCode.FILE_NOT_READABLE);
}
}
// Third param "true" uses Opt.PRIVATE args --setargile=argfile and
String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
+ "\": File could not be read.";
Console.debug(message, e);
- Jalview.exit(message, 3);
+ Jalview.exit(message, ExitCode.FILE_NOT_READABLE);
}
}
return args;
FIRST, BEFORE, AFTER
}
- // get from following Arg of type a or subval of same name (lowercase)
+ /**
+ * 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
+ /**
+ * 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)
{
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
+ /**
+ * 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)
// the following methods look for the "*" linkedId and add the argvalue to all
// linkedId ArgValues if it does.
- // This version inserts the subvals sv into all created values
+ /**
+ * This version inserts the subvals sv into all created values
+ */
private void addValue(String linkedId, Type type, ArgValues avs,
SubVals sv, String v, int argIndex, boolean doSubs)
{
doSubs);
}
- /*
+ /**
* The following operations look for the "*" and "open*" linkedIds and add the
- * argvalue to all appropriate linkedId ArgValues if it does.
- * If subvals are supplied, they are inserted into all new set values.
+ * argvalue to all appropriate linkedId ArgValues if it does. If subvals are
+ * supplied, they are inserted into all new set values.
*
- * @param op The ArgParser.Op operation
- * @param linkedId The String linkedId from the ArgValuesMap
- * @param type The Arg.Type to attach to this ArgValue
- * @param avs The ArgValues for this linkedId
- * @param sv Use these SubVals on the ArgValue
- * @param merge Merge the SubVals with any existing on the value. False will replace unless sv is null
- * @param v The value of the ArgValue (may contain subvals).
- * @param b The boolean value of the ArgValue.
- * @param argIndex The argIndex for the ArgValue.
- * @param doSubs Whether to perform substitutions on the subvals and value.
+ * @param op
+ * The ArgParser.Op operation
+ * @param linkedId
+ * The String linkedId from the ArgValuesMap
+ * @param type
+ * The Arg.Type to attach to this ArgValue
+ * @param avs
+ * The ArgValues for this linkedId
+ * @param sv
+ * Use these SubVals on the ArgValue
+ * @param merge
+ * Merge the SubVals with any existing on the value. False will
+ * replace unless sv is null
+ * @param v
+ * The value of the ArgValue (may contain subvals).
+ * @param b
+ * The boolean value of the ArgValue.
+ * @param argIndex
+ * The argIndex for the ArgValue.
+ * @param doSubs
+ * Whether to perform substitutions on the subvals and value.
*/
private void argValueOperation(Op op, String linkedId, Type type,
ArgValues avs, SubVals sv, boolean merge, String v, boolean b,
Arg a = avs.arg();
List<String> wildcardLinkedIds = null;
- if (a.hasOption(Opt.ALLOWALL))
+ if (a.hasOption(Opt.ALLOWMULTIID))
{
switch (linkedId)
{
// skip incorrectly stored wildcard ids!
if (id == null || MATCHALLLINKEDIDS.equals(id)
|| MATCHOPENEDLINKEDIDS.equals(id))
+ {
continue;
+ }
ArgValuesMap avm = linkedArgs.get(id);
// don't set an output if there isn't an input
if (a.hasOption(Opt.REQUIREINPUT)
return linkedArgs.get(linkedId);
}
+ public boolean isOldStyle()
+ {
+ return oldArguments;
+ }
+
+ public boolean isMixedStyle()
+ {
+ return mixedArguments;
+ }
+
+ public String[] getMixedExamples()
+ {
+ return mixedExamples;
+ }
}
\ No newline at end of file