import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import jalview.bin.Console;
{
protected static final String DOUBLEDASH = "--";
+ protected static final char EQUALS = '=';
+
protected static final String NEGATESTRING = "no";
// the default linked id prefix used for no id (not even square braces)
// 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 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 linked id used to increment the idCounter (and use the incremented
- // value)
- private static final String INCREMENTAUTOCOUNTERLINKEDID = "{++n}";
-
- // the linked id used to use the idCounter
- private static final String AUTOCOUNTERLINKEDID = "{n}";
+ // the linked id prefix used for --opennew files
+ protected static final String OPENNEWLINKEDIDPREFIX = "OPENNEW:";
+ // 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)
+ private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}";
+
+ // 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
+ private static final String LINKEDIDBASENAME = "{basename}";
+
+ // the linked id substitution string used to use the dir path of --open
+ // or --opennew
+ private static final String LINKEDIDDIRNAME = "{dirname}";
+
+ // the current argfile
+ private String argFile = null;
+
+ // 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
+ 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;
protected List<Arg> argList;
+ private static final char ARGFILECOMMENT = '#';
+
static
{
argMap = new HashMap<>();
if (argMap.containsKey(argName))
{
Console.warn("Trying to add argument name multiple times: '"
- + argName + "'"); // RESTORE THIS WHEN MERGED
+ + argName + "'"); // RESTORE THIS WHEN
+ // MERGED
if (argMap.get(argName) != a)
{
Console.error(
public ArgParser(String[] args)
{
+ this(args, false);
+ }
+
+ public ArgParser(String[] args, boolean initsubstitutions)
+ {
// 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)));
+ this(new ArrayList<>(Arrays.asList(args)), initsubstitutions);
}
- public ArgParser(List<String> args)
+ public ArgParser(List<String> args, boolean initsubstitutions)
+ {
+ this(args, initsubstitutions, false);
+ }
+
+ public ArgParser(List<String> args, boolean initsubstitutions,
+ boolean allowPrivate)
{
// do nothing if there are no "--" args and some "-" args
boolean d = false;
if (d && !dd)
{
// leave it to the old style -- parse an empty list
- parse(new ArrayList<String>());
+ parse(new ArrayList<String>(), false, false);
return;
}
- parse(args);
+ parse(args, initsubstitutions, allowPrivate);
}
- private void parse(List<String> args)
+ private void parse(List<String> args, boolean initsubstitutions,
+ boolean allowPrivate)
{
+ this.substitutions = initsubstitutions;
int argIndex = 0;
boolean openEachInitialFilenames = true;
for (int i = 0; i < args.size(); i++)
if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH)
&& !arg.startsWith("-") && new File(arg).exists())
{
- arg = DOUBLEDASH + Arg.OPENNEW.getName();
+ arg = Arg.OPENNEW.argString();
}
else
{
String linkedId = null;
if (arg.startsWith(DOUBLEDASH))
{
- int equalPos = arg.indexOf('=');
+ int equalPos = arg.indexOf(EQUALS);
if (equalPos > -1)
{
argName = arg.substring(DOUBLEDASH.length(), equalPos);
Console.error("Argument '" + arg + "' not recognised. Ignoring.");
continue;
}
+ if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
+ {
+ Console.error(
+ "Argument '" + a.argString() + "' is private. Ignoring.");
+ continue;
+ }
if (!a.hasOption(Opt.BOOLEAN) && negated)
{
// used "no" with a non-boolean option
- Console.error("Argument '--" + NEGATESTRING + argName
+ Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName
+ "' not a boolean option. Ignoring.");
continue;
}
if (!a.hasOption(Opt.STRING) && equalPos > -1)
{
// set --argname=value when arg does not accept values
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + a.argString()
+ "' does not expect a value (given as '" + arg
+ "'). Ignoring.");
continue;
if (!a.hasOption(Opt.LINKED) && linkedId != null)
{
// set --argname[linkedId] when arg does not use linkedIds
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + a.argString()
+ "' does not expect a linked id (given as '" + arg
+ "'). Ignoring.");
continue;
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());
+ globSubVals = new SubVals(val);
+ // make substitutions before looking for files
+ String fileGlob = makeSubstitutions(globSubVals.getContent(),
+ linkedId);
+ globVals = FileUtils.getFilenamesFromGlob(fileGlob);
}
else
{
{
// There is no "=" so value is next arg or args (possibly shell
// glob-expanded)
- if (i + 1 >= args.size())
+ if ((openEachInitialFilenames ? i : i + 1) >= args.size())
{
// no value to take for arg, which wants a value
Console.error("Argument '" + a.getName()
{
substitutions = !negated;
}
+ else if (a == Arg.SETARGFILE)
+ {
+ argFile = val;
+ }
+ else if (a == Arg.UNSETARGFILE)
+ {
+ argFile = null;
+ }
String autoCounterString = null;
boolean usingAutoCounterLinkedId = false;
+ arg);
}
}
- else if (linkedId.contains(AUTOCOUNTERLINKEDID))
+ else if (linkedId.contains(LINKEDIDAUTOCOUNTER))
{
// turn {n} to the autoCounter
autoCounterString = Integer.toString(linkedIdAutoCounter);
- linkedId = linkedId.replace(AUTOCOUNTERLINKEDID,
+ linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
autoCounterString);
usingAutoCounterLinkedId = true;
Console.debug(
"Changing linkedId to '" + linkedId + "' from " + arg);
}
- else if (linkedId.contains(INCREMENTAUTOCOUNTERLINKEDID))
+ else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
{
// turn {++n} to the incremented autoCounter
autoCounterString = Integer.toString(++linkedIdAutoCounter);
- linkedId = linkedId.replace(INCREMENTAUTOCOUNTERLINKEDID,
+ linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
autoCounterString);
usingAutoCounterLinkedId = true;
Console.debug(
// not dealing with both NODUPLICATEVALUES and GLOB
if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
{
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + a.argString()
+ "' cannot contain a duplicate value ('" + val
+ "'). Ignoring this and subsequent occurrences.");
continue;
}
// check for unique id
- SubVals idsv = ArgParser.getSubVals(val);
+ SubVals idsv = new SubVals(val);
String id = idsv.get(ArgValues.ID);
if (id != null && avm.hasId(a, id))
{
- Console.error("Argument '--" + argName + "' has a duplicate id ('"
- + id + "'). Ignoring.");
+ Console.error("Argument '" + a.argString()
+ + "' has a duplicate id ('" + id + "'). Ignoring.");
continue;
}
{
for (String v : globVals)
{
- v = makeSubstitutions(v);
+ v = makeSubstitutions(v, linkedId);
SubVals vsv = new SubVals(globSubVals, v);
avs.addValue(vsv, v, argIndex++);
argIndexIncremented = true;
}
else
{
- avs.addValue(makeSubstitutions(val), argIndex);
+ avs.addValue(makeSubstitutions(val, linkedId), argIndex);
}
}
else if (a.hasOption(Opt.BOOLEAN))
}
}
- private String makeSubstitutions(String val)
+ private String makeSubstitutions(String val, String linkedId)
{
if (!this.substitutions)
return val;
subvals = "";
rest = val;
}
- if ((rest.contains(AUTOCOUNTERLINKEDID)))
- rest = rest.replace(AUTOCOUNTERLINKEDID,
+ if (rest.contains(LINKEDIDAUTOCOUNTER))
+ rest = rest.replace(LINKEDIDAUTOCOUNTER,
String.valueOf(linkedIdAutoCounter));
- if ((rest.contains(INCREMENTAUTOCOUNTERLINKEDID)))
- rest = rest.replace(INCREMENTAUTOCOUNTERLINKEDID,
+ if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER))
+ rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER,
String.valueOf(++linkedIdAutoCounter));
- if ((rest.contains("{}")))
- rest = rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
+ if (rest.contains(DEFAULTLINKEDIDCOUNTER))
+ rest = rest.replace(DEFAULTLINKEDIDCOUNTER,
+ String.valueOf(defaultLinkedIdCounter));
+ ArgValuesMap avm = linkedArgs.get(linkedId);
+ if (avm != null)
+ {
+ if (rest.contains(LINKEDIDBASENAME))
+ {
+ rest = rest.replace(LINKEDIDBASENAME, avm.getBasename());
+ }
+ if (rest.contains(LINKEDIDDIRNAME))
+ {
+ rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname());
+ }
+ }
+ if (argFile != null)
+ {
+ if (rest.contains(ARGFILEBASENAME))
+ {
+ rest = rest.replace(ARGFILEBASENAME,
+ FileUtils.getBasename(new File(argFile)));
+ }
+ if (rest.contains(ARGFILEDIRNAME))
+ {
+ rest = rest.replace(ARGFILEDIRNAME,
+ FileUtils.getDirname(new File(argFile)));
+ }
+ }
return new StringBuilder(subvals).append(rest).toString();
}
/*
* A helper method to take a list of String args where we're expecting
* {"--previousargs", "--arg", "file1", "file2", "file3", "--otheroptionsornot"}
- * and the index of the globbed arg, here 1. It returns a
- * List<String> {"file1", "file2", "file3"}
- * *and remove these from the original list object* so that processing
- * can continue from where it has left off, e.g. args has become
- * {"--previousargs", "--arg", "--otheroptionsornot"}
- * so the next increment carries on from the next --arg if available.
+ * and the index of the globbed arg, here 1. It returns a List<String> {"file1",
+ * "file2", "file3"} *and remove these from the original list object* so that
+ * processing can continue from where it has left off, e.g. args has become
+ * {"--previousargs", "--arg", "--otheroptionsornot"} so the next increment
+ * carries on from the next --arg if available.
*/
protected static List<String> getShellGlobbedFilenameValues(Arg a,
List<String> args, int i)
return sb.toString();
}
- public static SubVals getSubVals(String item)
- {
- return new SubVals(item);
- }
-
- public static ArgParser parseArgFiles(List<String> argFilenameGlobs)
+ public static ArgParser parseArgFiles(List<String> argFilenameGlobs,
+ boolean initsubstitutions)
{
List<File> argFiles = new ArrayList<>();
argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
}
- return parseArgFileList(argFiles);
+ return parseArgFileList(argFiles, initsubstitutions);
}
- public static ArgParser parseArgFileList(List<File> argFiles)
+ public static ArgParser parseArgFileList(List<File> argFiles,
+ boolean initsubstitutions)
{
List<String> argsList = new ArrayList<>();
for (File argFile : argFiles)
{
if (!argFile.exists())
{
- String message = DOUBLEDASH
- + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + "=\""
+ String message = Arg.ARGFILE.argString() + EQUALS + "\""
+ argFile.getPath() + "\": File does not exist.";
Jalview.exit(message, 2);
}
try
{
- argsList.addAll(Files.readAllLines(Paths.get(argFile.getPath())));
+ String setargfile = new StringBuilder(Arg.SETARGFILE.argString())
+ .append(EQUALS).append(argFile.getCanonicalPath())
+ .toString();
+ argsList.add(setargfile);
+ argsList.addAll(readArgFile(argFile));
+ argsList.add(Arg.UNSETARGFILE.argString());
+ } catch (IOException e)
+ {
+ String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
+ + "\": File could not be read.";
+ Jalview.exit(message, 3);
+ }
+ }
+ // Third param "true" uses Opt.PRIVATE args --setargile=argfile and
+ // --unsetargfile
+ return new ArgParser(argsList, initsubstitutions, true);
+ }
+
+ protected static List<String> readArgFile(File argFile)
+ {
+ List<String> args = new ArrayList<>();
+ if (argFile != null && argFile.exists())
+ {
+ try
+ {
+ for (String line : Files.readAllLines(Paths.get(argFile.getPath())))
+ {
+ if (line != null && line.length() > 0
+ && line.charAt(0) != ARGFILECOMMENT)
+ args.add(line);
+ }
} catch (IOException e)
{
- String message = DOUBLEDASH
- + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + "=\""
- + argFile.getPath() + "\": File could not be read.";
+ String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath()
+ + "\": File could not be read.";
+ Console.debug(message, e);
Jalview.exit(message, 3);
}
}
- return new ArgParser(argsList);
+ return args;
}
}
\ No newline at end of file