2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
24 import java.io.IOException;
25 import java.net.URLDecoder;
26 import java.nio.file.Files;
27 import java.nio.file.Paths;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.EnumSet;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
39 import jalview.util.FileUtils;
41 public class ArgParser
43 private static final String NEGATESTRING = "no";
45 private static final String DEFAULTLINKEDID = "";
47 private static enum Opt
49 BOOLEAN, STRING, UNARY, MULTI, LINKED, NODUPLICATEVALUES, BOOTSTRAP,
53 // These bootstrap args are simply parsed before a full parse of arguments and
54 // so are accessible at an earlier stage to (e.g.) set debug log leve, provide
55 // a props file (that might set log level), run headlessly, read an argfile
56 // instead of other args.
57 private static final List<Arg> bootstrapArgs;
62 NOCALCULATION, NOMENUBAR, NOSTATUS, SHOWOVERVIEW, ANNOTATIONS, COLOUR,
63 FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, NOANNOTATION, NOANNOTATION2,
64 NODISPLAY, NOGUI, NONEWS, NOQUESTIONNAIRE, NOSORTBYTREE, NOUSAGESTATS,
65 OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, SORTBYTREE, TREE, VDOC,
68 HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
69 COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
70 ANNOTATION2, DISPLAY, GUI, NEWS, NOQUESTIONNAIRE, SORTBYTREE,
71 USAGESTATS, OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC,
72 VSESS, OUTPUT, OUTPUTTYPE, SSANNOTATION, NOTEMPFAC, TEMPFAC,
73 TEMPFAC_LABEL, TEMPFAC_DESC, TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP,
74 NOSTRUCTURE, STRUCTURE, IMAGE, QUIT, CLOSE, DEBUG("d"), QUIET("q"),
79 HELP.setOptions(Opt.UNARY);
80 CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
81 // expecting "--nocalculation"
82 MENUBAR.setOptions(true, Opt.BOOLEAN);
83 STATUS.setOptions(true, Opt.BOOLEAN);
84 SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
85 ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED);
86 COLOUR.setOptions(Opt.STRING, Opt.LINKED);
87 FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
88 GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
89 GROUPS.setOptions(Opt.STRING, Opt.LINKED);
90 HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
91 JABAWS.setOptions(Opt.STRING);
92 ANNOTATION.setOptions(true, Opt.BOOLEAN);
93 ANNOTATION2.setOptions(true, Opt.BOOLEAN);
94 DISPLAY.setOptions(true, Opt.BOOLEAN);
95 GUI.setOptions(true, Opt.BOOLEAN);
96 NEWS.setOptions(true, Opt.BOOLEAN);
97 NOQUESTIONNAIRE.setOptions(Opt.UNARY); // unary as --questionnaire=val
98 // expects a string value
99 SORTBYTREE.setOptions(true, Opt.BOOLEAN);
100 USAGESTATS.setOptions(true, Opt.BOOLEAN);
101 OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
102 OPEN2.setOptions(Opt.STRING, Opt.LINKED);
103 PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
104 QUESTIONNAIRE.setOptions(Opt.STRING);
105 SETPROP.setOptions(Opt.STRING);
106 TREE.setOptions(Opt.STRING);
108 VDOC.setOptions(Opt.UNARY);
109 VSESS.setOptions(Opt.UNARY);
111 OUTPUT.setOptions(Opt.STRING, Opt.LINKED);
112 OUTPUTTYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
114 SSANNOTATION.setOptions(Opt.BOOLEAN, Opt.LINKED);
115 NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
116 TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
117 TEMPFAC_LABEL.setOptions(Opt.STRING, Opt.LINKED);
118 TEMPFAC_DESC.setOptions(Opt.STRING, Opt.LINKED);
119 TEMPFAC_SHADING.setOptions(Opt.BOOLEAN, Opt.LINKED);
120 TITLE.setOptions(Opt.STRING, Opt.LINKED);
121 PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
122 NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
123 STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
124 WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
125 IMAGE.setOptions(Opt.STRING, Opt.LINKED);
126 QUIT.setOptions(Opt.UNARY);
127 CLOSE.setOptions(Opt.UNARY, Opt.LINKED);
128 DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
129 QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
130 ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB);
133 private final String[] argNames;
135 private Opt[] argOptions;
137 private boolean defaultBoolValue = false;
139 public String toLongString()
141 StringBuilder sb = new StringBuilder();
142 sb.append("Arg: ").append(this.name());
143 for (String name : getNames())
145 sb.append(", '").append(name).append("'");
147 sb.append("\nOptions: ");
148 boolean first = true;
149 for (Opt o : argOptions)
155 sb.append(o.toString());
159 return sb.toString();
167 private Arg(String... names)
169 int length = (names == null || names.length == 0
170 || (names.length == 1 && names[0] == null)) ? 1
172 this.argNames = new String[length];
173 this.argNames[0] = this.getName();
175 System.arraycopy(names, 0, this.argNames, 1, names.length);
178 public String[] getNames()
183 public String getName()
185 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
189 public final String toString()
194 public boolean hasOption(Opt o)
196 if (argOptions == null)
198 for (Opt option : argOptions)
206 protected void setOptions(Opt... options)
208 setOptions(false, options);
211 protected void setOptions(boolean defaultBoolValue, Opt... options)
213 this.defaultBoolValue = defaultBoolValue;
214 argOptions = options;
217 protected boolean getDefaultBoolValue()
219 return defaultBoolValue;
223 public static class ArgValues
225 private static final String ID = "id";
229 private int argCount = 0;
231 private boolean boolValue = false;
233 private boolean negated = false;
235 private int boolIndex = -1;
237 private List<Integer> argsIndexes;
239 private List<ArgValue> argValueList;
241 private Map<String, ArgValue> idMap = new HashMap<>();
243 protected ArgValues(Arg a)
246 this.argValueList = new ArrayList<ArgValue>();
247 this.boolValue = arg.getDefaultBoolValue();
255 protected int getCount()
260 protected void incrementCount()
265 protected void setNegated(boolean b)
270 protected boolean isNegated()
275 protected void setBoolean(boolean b, int i)
281 protected boolean getBoolean()
283 return this.boolValue;
287 public String toString()
289 if (argValueList == null)
291 StringBuilder sb = new StringBuilder();
292 sb.append(arg.toLongString());
293 if (arg.hasOption(Opt.BOOLEAN) || arg.hasOption(Opt.UNARY))
294 sb.append("Boolean: ").append(boolValue).append("; Default: ")
295 .append(arg.getDefaultBoolValue()).append("; Negated: ")
296 .append(negated).append("\n");
297 if (arg.hasOption(Opt.STRING))
299 sb.append("Values:");
300 boolean first = true;
301 for (ArgValue av : argValueList)
303 String v = av.getValue();
307 sb.append(v).append("'");
312 sb.append("Count: ").append(argCount).append("\n");
313 return sb.toString();
316 protected void addValue()
321 protected void addValue(String val, int argIndex)
323 addArgValue(new ArgValue(val, argIndex));
326 protected void addArgValue(ArgValue av)
328 if ((!arg.hasOption(Opt.MULTI) && argValueList.size() > 0)
329 || (arg.hasOption(Opt.NODUPLICATEVALUES)
330 && argValueList.contains(av.getValue())))
332 if (argValueList == null)
334 argValueList = new ArrayList<ArgValue>();
336 SubVals sv = ArgParser.getSubVals(av.getValue());
339 String id = sv.get(ID);
343 argValueList.add(av);
346 protected boolean hasValue(String val)
348 return argValueList.contains(val);
351 protected ArgValue getArgValue()
353 if (arg.hasOption(Opt.MULTI))
354 Console.warn("Requesting single value for multi value argument");
355 return argValueList.size() > 0 ? argValueList.get(0) : null;
358 protected List<ArgValue> getArgValueList()
363 protected boolean hasId(String id)
365 return idMap.containsKey(id);
368 protected ArgValue getId(String id)
370 return idMap.get(id);
375 private List<String> vargs = null;
377 private boolean isApplet;
379 // private AppletParams appletParams;
381 public boolean isApplet()
386 public String nextValue()
388 return vargs.remove(0);
396 public String getValue(String arg)
398 return getValue(arg, false);
401 public String getValue(String arg, boolean utf8decode)
403 int index = vargs.indexOf(arg);
408 ret = vargs.get(index + 1).toString();
411 if (utf8decode && ret != null)
415 dc = URLDecoder.decode(ret, "UTF-8");
417 } catch (Exception e)
419 // TODO: log failure to decode
427 public Object getAppletValue(String key, String def, boolean asString)
430 return (appletParams == null ? null
431 : (value = appletParams.get(key.toLowerCase())) == null ? def
432 : asString ? "" + value : value);
437 private static final Map<String, Arg> argMap;
439 private Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
441 private List<String> linkedOrder = null;
443 private List<Arg> argList;
447 argMap = new HashMap<>();
448 bootstrapArgs = new ArrayList<>();
449 for (Arg a : EnumSet.allOf(Arg.class))
451 if (a.hasOption(Opt.BOOTSTRAP))
452 bootstrapArgs.add(a);
453 for (String argName : a.getNames())
455 if (argMap.containsKey(argName))
457 Console.warn("Trying to add argument name multiple times: '"
458 + argName + "'"); // RESTORE THIS WHEN MERGED
459 if (argMap.get(argName) != a)
462 "Trying to add argument name multiple times for different Args: '"
463 + argMap.get(argName).getName() + ":" + argName
464 + "' and '" + a.getName() + ":" + argName
469 argMap.put(argName, a);
474 public ArgParser(String[] args)
476 this(Arrays.asList(args));
479 public ArgParser(List<String> args)
481 Enumeration<String> argE = Collections.enumeration(args);
483 while (argE.hasMoreElements())
485 String arg = argE.nextElement();
486 String argName = null;
488 String linkedId = null;
489 if (arg.startsWith("--"))
491 int equalPos = arg.indexOf('=');
494 argName = arg.substring(2, equalPos);
495 val = arg.substring(equalPos + 1);
499 argName = arg.substring(2);
501 int idOpen = argName.indexOf('[');
502 int idClose = argName.indexOf(']');
504 if (idOpen > -1 && idClose == argName.length() - 1)
506 linkedId = argName.substring(idOpen + 1, idClose);
507 argName = argName.substring(0, idOpen);
510 Arg a = argMap.get(argName);
511 // check for boolean prepended by "no"
512 boolean negated = false;
513 if (a == null && argName.startsWith(NEGATESTRING) && argMap
514 .containsKey(argName.substring(NEGATESTRING.length())))
516 argName = argName.substring(NEGATESTRING.length());
517 a = argMap.get(argName);
521 // check for config errors
525 Console.error("Argument '" + arg + "' not recognised. Ignoring.");
528 if (!a.hasOption(Opt.BOOLEAN) && negated)
530 // used "no" with a non-boolean option
531 Console.error("Argument '--" + NEGATESTRING + argName
532 + "' not a boolean option. Ignoring.");
535 if (!a.hasOption(Opt.STRING) && equalPos > -1)
537 // set --argname=value when arg does not accept values
538 Console.error("Argument '--" + argName
539 + "' does not expect a value (given as '" + arg
543 if (!a.hasOption(Opt.LINKED) && linkedId != null)
545 // set --argname[linkedId] when arg does not use linkedIds
546 Console.error("Argument '--" + argName
547 + "' does not expect a linked id (given as '" + arg
552 if (a.hasOption(Opt.STRING) && equalPos == -1)
554 // take next arg as value if required, and '=' was not found
555 if (!argE.hasMoreElements())
557 // no value to take for arg, which wants a value
558 Console.error("Argument '" + a.getName()
559 + "' requires a value, none given. Ignoring.");
562 val = argE.nextElement();
565 // use default linkedId for linked arguments
566 if (a.hasOption(Opt.LINKED) && linkedId == null)
567 linkedId = DEFAULTLINKEDID;
569 if (!linkedArgs.containsKey(linkedId))
570 linkedArgs.put(linkedId, new ArgValuesMap());
572 ArgValuesMap avm = linkedArgs.get(linkedId);
574 if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
576 Console.error("Argument '--" + argName
577 + "' cannot contain a duplicate value ('" + val
578 + "'). Ignoring this and subsequent occurrences.");
582 // check for unique id
583 SubVals sv = ArgParser.getSubVals(val);
584 String id = sv.get(ArgValues.ID);
585 if (id != null && avm.hasId(a, id))
587 Console.error("Argument '--" + argName + "' has a duplicate id ('"
588 + id + "'). Ignoring.");
592 ArgValues avs = avm.getOrCreateArgValues(a);
595 avs = new ArgValues(a);
597 // store appropriate value
598 if (a.hasOption(Opt.STRING))
600 avs.addValue(val, argIndex);
602 else if (a.hasOption(Opt.BOOLEAN))
604 avs.setBoolean(!negated, argIndex);
605 avs.setNegated(negated);
607 else if (a.hasOption(Opt.UNARY))
609 avs.setBoolean(true, argIndex);
611 avs.incrementCount();
613 // store in appropriate place
614 if (a.hasOption(Opt.LINKED))
616 // allow a default linked id for single usage
617 if (linkedId == null)
618 linkedId = DEFAULTLINKEDID;
619 // store the order of linkedIds
620 if (linkedOrder == null)
621 linkedOrder = new ArrayList<>();
622 if (!linkedOrder.contains(linkedId))
623 linkedOrder.add(linkedId);
626 // store arg in the list of args used
628 argList = new ArrayList<>();
629 if (!argList.contains(a))
635 public boolean isSet(Arg a)
637 return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a);
640 public boolean isSet(String linkedId, Arg a)
642 ArgValuesMap avm = linkedArgs.get(linkedId);
643 return avm == null ? false : avm.containsArg(a);
646 public boolean getBool(Arg a)
648 if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY))
650 Console.warn("Getting boolean from non boolean Arg '" + a.getName()
653 return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a);
656 public boolean getBool(String linkedId, Arg a)
658 ArgValuesMap avm = linkedArgs.get(linkedId);
660 return a.getDefaultBoolValue();
661 ArgValues avs = avm.getArgValues(a);
662 return avs == null ? a.getDefaultBoolValue() : avs.getBoolean();
665 public List<String> linkedIds()
670 public ArgValuesMap linkedArgs(String id)
672 return linkedArgs.get(id);
676 public String toString()
678 StringBuilder sb = new StringBuilder();
679 sb.append("UNLINKED\n");
680 sb.append(argValuesMapToString(linkedArgs.get(null)));
681 if (linkedIds() != null)
683 sb.append("LINKED\n");
684 for (String id : linkedIds())
686 // already listed these as UNLINKED args
690 ArgValuesMap avm = linkedArgs(id);
691 sb.append("ID: '").append(id).append("'\n");
692 sb.append(argValuesMapToString(avm));
695 return sb.toString();
698 private static String argValuesMapToString(ArgValuesMap avm)
702 StringBuilder sb = new StringBuilder();
703 for (Arg a : avm.getArgKeys())
705 ArgValues v = avm.getArgValues(a);
706 sb.append(v.toString());
709 return sb.toString();
712 public static SubVals getSubVals(String item)
714 return new SubVals(item);
718 * A helper class to keep an index of argument position with argument values
720 public static class ArgValue
722 private int argIndex;
724 private String value;
728 protected ArgValue(String value, int argIndex)
731 this.argIndex = argIndex;
734 protected String getValue()
739 protected int getArgIndex()
744 protected void setId(String i)
749 protected String getId()
756 * A helper class to parse a string of the possible forms "content"
757 * "[index]content", "[keyName=keyValue]content" and return the integer index,
758 * the strings keyName and keyValue, and the content after the square brackets
759 * (if present). Values not set `will be -1 or null.
761 public static class SubVals
763 private static int NOTSET = -1;
765 private int index = NOTSET;
767 private Map<String, String> subVals = null;
769 private static char SEPARATOR = ';';
771 private String content = null;
773 public SubVals(String item)
775 this.parseVals(item);
778 public void parseVals(String item)
782 if (item.indexOf('[') == 0 && item.indexOf(']') > 1)
784 int openBracket = item.indexOf('[');
785 int closeBracket = item.indexOf(']');
786 String subvalsString = item.substring(openBracket + 1,
788 this.content = item.substring(closeBracket + 1);
789 boolean setIndex = false;
790 for (String subvalString : subvalsString
791 .split(Character.toString(SEPARATOR)))
793 int equals = subvalString.indexOf('=');
797 subVals = new HashMap<>();
798 subVals.put(subvalString.substring(0, equals),
799 subvalString.substring(equals + 1));
805 this.index = Integer.parseInt(subvalString);
807 } catch (NumberFormatException e)
809 Console.warn("Failed to obtain subvalue or index from '"
810 + item + "'. Setting index=0 and using content='"
824 public boolean notSet()
826 // notSet is true if content present but nonsensical
827 return index == NOTSET && subVals == null;
830 public String get(String key)
832 return subVals == null ? null : subVals.get(key);
835 public boolean has(String key)
837 return subVals == null ? false : subVals.containsKey(key);
840 public int getIndex()
845 public String getContent()
852 * Helper class to allow easy extraction of information about specific
853 * argument values (without having to check for null etc all the time)
855 protected static class ArgValuesMap
857 protected Map<Arg, ArgValues> m;
859 protected ArgValuesMap()
864 protected ArgValuesMap(Map<Arg, ArgValues> map)
869 private Map<Arg, ArgValues> getMap()
874 private void newMap()
876 m = new HashMap<Arg, ArgValues>();
879 private void newArg(Arg a)
884 m.put(a, new ArgValues(a));
887 protected void addArgValue(Arg a, ArgValue av)
889 if (getMap() == null)
890 m = new HashMap<Arg, ArgValues>();
892 if (!m.containsKey(a))
893 m.put(a, new ArgValues(a));
894 ArgValues avs = m.get(a);
898 protected ArgValues getArgValues(Arg a)
900 return m == null ? null : m.get(a);
903 protected ArgValues getOrCreateArgValues(Arg a)
905 ArgValues avs = m.get(a);
908 return getArgValues(a);
911 protected List<ArgValue> getArgValueList(Arg a)
913 ArgValues avs = getArgValues(a);
914 return avs == null ? new ArrayList<>() : avs.getArgValueList();
917 protected ArgValue getArgValue(Arg a)
919 List<ArgValue> vals = getArgValueList(a);
920 return (vals == null || vals.size() == 0) ? null : vals.get(0);
923 protected String getValue(Arg a)
925 ArgValue av = getArgValue(a);
926 return av == null ? null : av.getValue();
929 protected boolean containsArg(Arg a)
931 if (m == null || !m.containsKey(a))
933 return a.hasOption(Opt.STRING) ? getArgValue(a) != null
934 : this.getBoolean(a);
937 protected boolean hasValue(Arg a, String val)
939 if (m == null || !m.containsKey(a))
941 for (ArgValue av : getArgValueList(a))
943 String avVal = av.getValue();
944 if ((val == null && avVal == null)
945 || (val != null && val.equals(avVal)))
953 protected boolean getBoolean(Arg a)
955 ArgValues av = getArgValues(a);
956 return av == null ? false : av.getBoolean();
959 protected Set<Arg> getArgKeys()
964 protected ArgValue getClosestPreviousArgValueOfArg(ArgValue thisAv,
967 ArgValue closestAv = null;
968 int thisArgIndex = thisAv.getArgIndex();
969 ArgValues compareAvs = this.getArgValues(a);
970 int closestPreviousIndex = -1;
971 for (ArgValue av : compareAvs.getArgValueList())
973 int argIndex = av.getArgIndex();
974 if (argIndex < thisArgIndex && argIndex > closestPreviousIndex)
976 closestPreviousIndex = argIndex;
983 protected ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a)
985 // this looks for the *next* arg that *might* be referring back to
986 // a thisAv. Such an arg would have no subValues (if it does it should
987 // specify an id in the subValues so wouldn't need to be guessed).
988 ArgValue closestAv = null;
989 int thisArgIndex = thisAv.getArgIndex();
990 ArgValues compareAvs = this.getArgValues(a);
991 int closestNextIndex = Integer.MAX_VALUE;
992 for (ArgValue av : compareAvs.getArgValueList())
994 int argIndex = av.getArgIndex();
995 if (argIndex > thisArgIndex && argIndex < closestNextIndex)
997 closestNextIndex = argIndex;
1004 protected ArgValue[] getArgValuesReferringTo(String key, String value,
1007 // this looks for the *next* arg that *might* be referring back to
1008 // a thisAv. Such an arg would have no subValues (if it does it should
1009 // specify an id in the subValues so wouldn't need to be guessed).
1010 List<ArgValue> avList = new ArrayList<>();
1011 Arg[] args = a == null ? (Arg[]) this.getMap().keySet().toArray()
1014 for (Arg keyArg : args)
1016 for (ArgValue av : this.getArgValueList(keyArg))
1021 return (ArgValue[]) avList.toArray();
1024 protected boolean hasId(Arg a, String id)
1026 ArgValues avs = this.getArgValues(a);
1027 return avs == null ? false : avs.hasId(id);
1030 protected ArgValue getId(Arg a, String id)
1032 ArgValues avs = this.getArgValues(a);
1033 return avs == null ? null : avs.getId(id);
1037 public static ArgParser parseArgFiles(List<String> argFilenameGlobs)
1039 List<File> argFiles = new ArrayList<>();
1041 for (String pattern : argFilenameGlobs)
1043 // I don't think we want to dedup files, making life easier
1044 argFiles.addAll(FileUtils.getFilesFromGlob(pattern));
1047 return parseArgFileList(argFiles);
1050 public static ArgParser parseArgFileList(List<File> argFiles)
1052 List<String> argsList = new ArrayList<>();
1053 for (File argFile : argFiles)
1055 if (!argFile.exists())
1058 "--" + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + "=\""
1059 + argFile.getPath() + "\": File does not exist.");
1064 argsList.addAll(Files.readAllLines(Paths.get(argFile.getPath())));
1065 } catch (IOException e)
1067 System.err.println("--"
1068 + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + "=\""
1069 + argFile.getPath() + "\": File could not be read.");
1073 return new ArgParser(argsList);
1076 public static class BootstrapArgs
1079 private static Map<Arg, List<String>> bootstrapArgMap = new HashMap<>();
1081 public static BootstrapArgs getBootstrapArgs(String[] args)
1083 return new BootstrapArgs(args);
1086 private BootstrapArgs(String[] args)
1091 private void init(String[] args)
1095 Enumeration<String> argE = Collections
1096 .enumeration(Arrays.asList(args));
1097 while (argE.hasMoreElements())
1099 String arg = argE.nextElement();
1100 String argName = null;
1102 if (arg.startsWith("--"))
1104 int equalPos = arg.indexOf('=');
1107 argName = arg.substring(2, equalPos);
1108 val = arg.substring(equalPos + 1);
1112 argName = arg.substring(2);
1115 Arg a = argMap.get(argName);
1116 if (a != null && bootstrapArgs.contains(a))
1118 if (!bootstrapArgMap.containsKey(a)
1119 || bootstrapArgMap.get(a) == null)
1121 List<String> aL = new ArrayList<>();
1123 bootstrapArgMap.put(a, aL);
1125 else if (a.hasOption(Opt.MULTI))
1127 List<String> aL = bootstrapArgMap.get(a); // already established
1130 bootstrapArgMap.put(a, aL);
1137 public boolean contains(Arg a)
1139 return bootstrapArgMap.containsKey(a);
1142 public List<String> getList(Arg a)
1144 return bootstrapArgMap.get(a);
1147 public String get(Arg a)
1149 if (bootstrapArgMap.containsKey(a))
1151 List<String> aL = bootstrapArgMap.get(a);
1152 return (aL == null || aL.size() == 0) ? null : aL.get(0);