/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.bin;
import java.net.URLDecoder;
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.util.Platform;
public class ArgParser
{
private static final String NEGATESTRING = "no";
private static final String DEFAULTLINKEDID = "";
private static enum Opt
{
BOOLEAN, STRING, UNARY, MULTI, LINKED, ORDERED
}
public enum Arg
{
/*
NOCALCULATION, NOMENUBAR, NOSTATUS, SHOWOVERVIEW, ANNOTATIONS, COLOUR,
FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, NOANNOTATION, NOANNOTATION2,
NODISPLAY, NOGUI, NONEWS, NOQUESTIONNAIRE, NOSORTBYTREE, NOUSAGESTATS,
OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, SORTBYTREE, TREE, VDOC,
VSESS;
*/
HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
ANNOTATION2, DISPLAY, GUI, NEWS, NOQUESTIONNAIRE, SORTBYTREE,
USAGESTATS, OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC,
VSESS, OUTPUT, OUTPUTTYPE, SSANNOTATION, NOTEMPFAC, TEMPFAC,
TEMPFAC_LABEL, TEMPFAC_DESC, TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP,
NOSTRUCTURE, STRUCTURE, IMAGE, QUIT;
static
{
HELP.setOptions(Opt.UNARY);
CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
// expecting "--nocalculation"
MENUBAR.setOptions(true, Opt.BOOLEAN);
STATUS.setOptions(true, Opt.BOOLEAN);
SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED);
COLOUR.setOptions(Opt.STRING, Opt.LINKED);
FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
GROUPS.setOptions(Opt.STRING, Opt.LINKED);
HEADLESS.setOptions(Opt.UNARY);
JABAWS.setOptions(Opt.STRING);
ANNOTATION.setOptions(true, Opt.BOOLEAN);
ANNOTATION2.setOptions(true, Opt.BOOLEAN);
DISPLAY.setOptions(true, Opt.BOOLEAN);
GUI.setOptions(true, Opt.BOOLEAN);
NEWS.setOptions(true, Opt.BOOLEAN);
NOQUESTIONNAIRE.setOptions(Opt.UNARY); // unary as --questionnaire=val
// expects a string value
SORTBYTREE.setOptions(true, Opt.BOOLEAN);
USAGESTATS.setOptions(true, Opt.BOOLEAN);
OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
OPEN2.setOptions(Opt.STRING, Opt.LINKED);
PROPS.setOptions(Opt.STRING);
QUESTIONNAIRE.setOptions(Opt.STRING);
SETPROP.setOptions(Opt.STRING);
TREE.setOptions(Opt.STRING);
VDOC.setOptions(Opt.UNARY);
VSESS.setOptions(Opt.UNARY);
OUTPUT.setOptions(Opt.STRING, Opt.LINKED);
OUTPUTTYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
SSANNOTATION.setOptions(Opt.BOOLEAN, Opt.LINKED);
NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
TEMPFAC_LABEL.setOptions(Opt.STRING, Opt.LINKED);
TEMPFAC_DESC.setOptions(Opt.STRING, Opt.LINKED);
TEMPFAC_SHADING.setOptions(Opt.BOOLEAN, Opt.LINKED);
TITLE.setOptions(Opt.STRING, Opt.LINKED);
PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
IMAGE.setOptions(Opt.STRING, Opt.LINKED);
QUIT.setOptions(Opt.UNARY);
}
private final String[] argNames;
private Opt[] argOptions;
private boolean defaultBoolValue = false;
public String toLongString()
{
StringBuilder sb = new StringBuilder();
sb.append("Arg: ").append(this.name());
for (String name : getNames())
{
sb.append(", '").append(name).append("'");
}
sb.append("\nOptions: ");
boolean first = true;
for (Opt o : argOptions)
{
if (!first)
{
sb.append(", ");
}
sb.append(o.toString());
first = false;
}
sb.append("\n");
return sb.toString();
}
private Arg()
{
this(new String[0]);
}
private Arg(String... names)
{
int length = (names == null || names.length == 0
|| (names.length == 1 && names[0] == null)) ? 1
: names.length + 1;
this.argNames = new String[length];
this.argNames[0] = this.getName();
if (length > 1)
System.arraycopy(names, 0, this.argNames, 1, names.length);
}
public String[] getNames()
{
return argNames;
}
public String getName()
{
return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
}
@Override
public final String toString()
{
return getName();
}
public boolean hasOption(Opt o)
{
if (argOptions == null)
return false;
for (Opt option : argOptions)
{
if (o == option)
return true;
}
return false;
}
protected void setOptions(Opt... options)
{
setOptions(false, options);
}
protected void setOptions(boolean defaultBoolValue, Opt... options)
{
this.defaultBoolValue = defaultBoolValue;
argOptions = options;
}
protected boolean getDefaultBoolValue()
{
return defaultBoolValue;
}
}
public static class ArgValues
{
private Arg arg;
private int argCount = 0;
private boolean boolValue = false;
private boolean negated = false;
private List argsList;
protected ArgValues(Arg a)
{
this.arg = a;
this.argsList = new ArrayList();
this.boolValue = arg.getDefaultBoolValue();
}
public Arg arg()
{
return arg;
}
protected int getCount()
{
return argCount;
}
protected void incrementCount()
{
argCount++;
}
protected void setNegated(boolean b)
{
this.negated = b;
}
protected boolean isNegated()
{
return this.negated;
}
protected void setBoolean(boolean b)
{
this.boolValue = b;
}
protected boolean getBoolean()
{
return this.boolValue;
}
@Override
public String toString()
{
if (argsList == null)
return null;
StringBuilder sb = new StringBuilder();
sb.append(arg.toLongString());
if (arg.hasOption(Opt.BOOLEAN) || arg.hasOption(Opt.UNARY))
sb.append("Boolean: ").append(boolValue).append("; Default: ")
.append(arg.getDefaultBoolValue()).append("; Negated: ")
.append(negated).append("\n");
if (arg.hasOption(Opt.STRING))
{
sb.append("Values:");
boolean first = true;
for (String v : argsList)
{
if (!first)
sb.append(",");
sb.append("\n '");
sb.append(v).append("'");
first = false;
}
sb.append("\n");
}
sb.append("Count: ").append(argCount).append("\n");
return sb.toString();
}
protected void addValue()
{
addValue(null);
}
protected void addValue(String val)
{
addValue(val, false);
}
protected void addValue(String val, boolean noDuplicates)
{
if ((!arg.hasOption(Opt.MULTI) && argsList.size() > 0)
|| (noDuplicates && argsList.contains(val)))
return;
if (argsList == null)
{
Console.warn("** inst");
argsList = new ArrayList();
}
argsList.add(val);
}
protected boolean hasValue(String val)
{
return argsList.contains(val);
}
protected String getValue()
{
if (arg.hasOption(Opt.MULTI))
Console.warn("Requesting single value for multi value argument");
return argsList.size() > 0 ? argsList.get(0) : null;
}
protected List getValues()
{
return argsList;
}
}
// old style
private List vargs = null;
private boolean isApplet;
// private AppletParams appletParams;
public boolean isApplet()
{
return isApplet;
}
public String nextValue()
{
return vargs.remove(0);
}
public int getSize()
{
return vargs.size();
}
public String getValue(String arg)
{
return getValue(arg, false);
}
public String getValue(String arg, boolean utf8decode)
{
int index = vargs.indexOf(arg);
String dc = null, ret = null;
if (index != -1)
{
ret = vargs.get(index + 1).toString();
vargs.remove(index);
vargs.remove(index);
if (utf8decode && ret != null)
{
try
{
dc = URLDecoder.decode(ret, "UTF-8");
ret = dc;
} catch (Exception e)
{
// TODO: log failure to decode
}
}
}
return ret;
}
/*
public Object getAppletValue(String key, String def, boolean asString)
{
Object value;
return (appletParams == null ? null
: (value = appletParams.get(key.toLowerCase())) == null ? def
: asString ? "" + value : value);
}
*/
// new style
private static final Map argMap;
private Map> linkedArgs = new HashMap<>();
private List linkedOrder = null;
private List argList;
static
{
argMap = new HashMap<>();
for (Arg a : EnumSet.allOf(Arg.class))
{
ARGNAME: for (String argName : a.getNames())
{
if (argMap.containsKey(argName))
{
Console.warn("Trying to add argument name multiple times: '"
+ argName + "'"); // RESTORE THIS WHEN MERGED
if (argMap.get(argName) != a)
{
Console.error(
"Trying to add argument name multiple times for different Args: '"
+ argMap.get(argName).getName() + ":" + argName
+ "' and '" + a.getName() + ":" + argName
+ "'");
}
continue ARGNAME;
}
argMap.put(argName, a);
}
}
}
public ArgParser(String[] args)
{
// old style
vargs = new ArrayList<>();
isApplet = (args.length > 0 && args[0].startsWith("