Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ArgParser | 46 | 404 | 209 | ||
ArgParser.Op | 1105 | 0 | 0 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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. | |
20 | */ | |
21 | package jalview.bin.argparser; | |
22 | ||
23 | import java.io.File; | |
24 | import java.io.IOException; | |
25 | import java.nio.file.Files; | |
26 | import java.nio.file.Paths; | |
27 | import java.util.ArrayList; | |
28 | import java.util.Arrays; | |
29 | import java.util.Collections; | |
30 | import java.util.EnumSet; | |
31 | import java.util.Enumeration; | |
32 | import java.util.HashMap; | |
33 | import java.util.List; | |
34 | import java.util.Map; | |
35 | ||
36 | import jalview.bin.Cache; | |
37 | import jalview.bin.Console; | |
38 | import jalview.bin.Jalview; | |
39 | import jalview.bin.Jalview.ExitCode; | |
40 | import jalview.bin.argparser.Arg.Opt; | |
41 | import jalview.bin.argparser.Arg.Type; | |
42 | import jalview.util.ArgParserUtils; | |
43 | import jalview.util.FileUtils; | |
44 | import jalview.util.HttpUtils; | |
45 | ||
46 | public class ArgParser | |
47 | { | |
48 | protected static final String SINGLEDASH = "-"; | |
49 | ||
50 | protected static final String DOUBLEDASH = "--"; | |
51 | ||
52 | public static final char EQUALS = '='; | |
53 | ||
54 | public static final String STDOUTFILENAME = "-"; | |
55 | ||
56 | protected static final String NEGATESTRING = "no"; | |
57 | ||
58 | /** | |
59 | * the default linked id prefix used for no id (ie when not even square braces | |
60 | * are provided) | |
61 | */ | |
62 | protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:"; | |
63 | ||
64 | /** | |
65 | * the linkedId string used to match all linkedIds seen so far | |
66 | */ | |
67 | protected static final String MATCHALLLINKEDIDS = "*"; | |
68 | ||
69 | /** | |
70 | * the linkedId string used to match all of the last --open'ed linkedIds | |
71 | */ | |
72 | protected static final String MATCHOPENEDLINKEDIDS = "open*"; | |
73 | ||
74 | /** | |
75 | * the counter added to the default linked id prefix | |
76 | */ | |
77 | private int defaultLinkedIdCounter = 0; | |
78 | ||
79 | /** | |
80 | * the substitution string used to use the defaultLinkedIdCounter | |
81 | */ | |
82 | private static final String DEFAULTLINKEDIDCOUNTER = "{}"; | |
83 | ||
84 | /** | |
85 | * the linked id prefix used for --open files. NOW the same as DEFAULT | |
86 | */ | |
87 | protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX; | |
88 | ||
89 | /** | |
90 | * the counter used for {n} substitutions | |
91 | */ | |
92 | private int linkedIdAutoCounter = 0; | |
93 | ||
94 | /** | |
95 | * the linked id substitution string used to increment the idCounter (and use | |
96 | * the incremented value) | |
97 | */ | |
98 | private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}"; | |
99 | ||
100 | /** | |
101 | * the linked id substitution string used to use the idCounter | |
102 | */ | |
103 | private static final String LINKEDIDAUTOCOUNTER = "{n}"; | |
104 | ||
105 | /** | |
106 | * the linked id substitution string used to use the filename extension of | |
107 | * --append or --open | |
108 | */ | |
109 | private static final String LINKEDIDEXTENSION = "{extension}"; | |
110 | ||
111 | /** | |
112 | * the linked id substitution string used to use the base filename of --append | |
113 | */ | |
114 | /** or --open */ | |
115 | private static final String LINKEDIDBASENAME = "{basename}"; | |
116 | ||
117 | /** | |
118 | * the linked id substitution string used to use the dir path of --append or | |
119 | * --open | |
120 | */ | |
121 | private static final String LINKEDIDDIRNAME = "{dirname}"; | |
122 | ||
123 | /** | |
124 | * On-the-fly substitution (not made at argument parsing time)! the current | |
125 | * structure filename extension | |
126 | */ | |
127 | private static final String STRUCTUREEXTENSION = "{structureextension}"; | |
128 | ||
129 | /** | |
130 | * On-the-fly substitution (not made at argument parsing time)! the current | |
131 | * structure filename base | |
132 | */ | |
133 | private static final String STRUCTUREBASENAME = "{structurebasename}"; | |
134 | ||
135 | /** | |
136 | * On-the-fly substitution (not made at argument parsing time)! the current | |
137 | * structure filename dir path | |
138 | */ | |
139 | private static final String STRUCTUREDIRNAME = "{structuredirname}"; | |
140 | ||
141 | /** | |
142 | * On-the-fly substitution (not made at argument parsing time)! increment the | |
143 | * on-the-fly counter and substitute the incremented value | |
144 | */ | |
145 | private static final String INCREMENTONTHEFLYCOUNTER = "{++m}"; | |
146 | ||
147 | /** | |
148 | * On-the-fly substitution (not made at argument parsing time)! the current | |
149 | * substitute with the on-the-fly counter | |
150 | */ | |
151 | private static final String ONTHEFLYCOUNTER = "{m}"; | |
152 | ||
153 | /** | |
154 | * the string used for on-the-fly structure filename substitutions | |
155 | */ | |
156 | private String currentStructureFilename = null; | |
157 | ||
158 | /** | |
159 | * the counter used for on-the-fly {m} substitutions | |
160 | */ | |
161 | private int ontheflyCounter = 0; | |
162 | ||
163 | /** | |
164 | * the current argfile | |
165 | */ | |
166 | private String argFile = null; | |
167 | ||
168 | /** | |
169 | * the linked id substitution string used to use the dir path of the latest | |
170 | */ | |
171 | /** --argfile name */ | |
172 | private static final String ARGFILEBASENAME = "{argfilebasename}"; | |
173 | ||
174 | /** | |
175 | * the linked id substitution string used to use the dir path of the latest | |
176 | * --argfile name | |
177 | */ | |
178 | private static final String ARGFILEDIRNAME = "{argfiledirname}"; | |
179 | ||
180 | /** | |
181 | * flag to say whether {n} subtitutions in output filenames should be made. | |
182 | * Turn on and off with --substitutions and --nosubstitutions Start with it on | |
183 | */ | |
184 | private boolean substitutions = true; | |
185 | ||
186 | /** | |
187 | * flag to say whether the default linkedId is the current default linked id | |
188 | * | |
189 | * or ALL linkedIds | |
190 | */ | |
191 | private boolean allLinkedIds = false; | |
192 | ||
193 | /** | |
194 | * flag to say whether the structure arguments should be applied to all | |
195 | * structures with this linked id | |
196 | */ | |
197 | private boolean allStructures = false; | |
198 | ||
199 | protected static final Map<String, Arg> argMap; | |
200 | ||
201 | protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>(); | |
202 | ||
203 | protected List<String> linkedOrder = new ArrayList<>(); | |
204 | ||
205 | protected List<String> storedLinkedIds = new ArrayList<>(); | |
206 | ||
207 | protected List<Arg> argList = new ArrayList<>(); | |
208 | ||
209 | private static final char ARGFILECOMMENT = '#'; | |
210 | ||
211 | private int argIndex = 0; | |
212 | ||
213 | private BootstrapArgs bootstrapArgs = null; | |
214 | ||
215 | private boolean oldArguments = false; | |
216 | ||
217 | private boolean mixedArguments = false; | |
218 | ||
219 | /** | |
220 | * saved examples of mixed arguments | |
221 | */ | |
222 | private String[] mixedExamples = new String[] { null, null }; | |
223 | ||
224 | 54 | static |
225 | { | |
226 | 54 | argMap = new HashMap<>(); |
227 | 54 | for (Arg a : EnumSet.allOf(Arg.class)) |
228 | { | |
229 | 3672 | for (String argName : a.getNames()) |
230 | { | |
231 | 4104 | if (argMap.containsKey(argName)) |
232 | { | |
233 | 0 | Console.warn("Trying to add argument name multiple times: '" |
234 | + argName + "'"); | |
235 | 0 | if (argMap.get(argName) != a) |
236 | { | |
237 | 0 | Console.error( |
238 | "Trying to add argument name multiple times for different Args: '" | |
239 | + argMap.get(argName).getName() + ":" + argName | |
240 | + "' and '" + a.getName() + ":" + argName | |
241 | + "'"); | |
242 | } | |
243 | 0 | continue; |
244 | } | |
245 | 4104 | argMap.put(argName, a); |
246 | } | |
247 | } | |
248 | } | |
249 | ||
250 | 46 | public ArgParser(String[] args) |
251 | { | |
252 | 46 | this(args, false, null); |
253 | } | |
254 | ||
255 | 168 | public ArgParser(String[] args, boolean initsubstitutions, |
256 | BootstrapArgs bsa) | |
257 | { | |
258 | /* | |
259 | * Make a mutable new ArrayList so that shell globbing parser works. | |
260 | * (When shell file globbing is used, there are a sequence of non-Arg | |
261 | * arguments (which are the expanded globbed filenames) that need to be | |
262 | * consumed by the --append/--argfile/etc Arg which is most easily done | |
263 | * by removing these filenames from the list one at a time. This can't be | |
264 | * done with an ArrayList made with only Arrays.asList(String[] args) as | |
265 | * that is not mutable. ) | |
266 | */ | |
267 | 168 | this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false, |
268 | bsa); | |
269 | } | |
270 | ||
271 | 0 | public ArgParser(List<String> args, boolean initsubstitutions) |
272 | { | |
273 | 0 | this(args, initsubstitutions, false, null); |
274 | } | |
275 | ||
276 | 176 | public ArgParser(List<String> args, boolean initsubstitutions, |
277 | boolean allowPrivate, BootstrapArgs bsa) | |
278 | { | |
279 | // do nothing if there are no "--" args and (some "-" args || >0 arg is | |
280 | // "open") | |
281 | 176 | boolean d = false; |
282 | 176 | boolean dd = false; |
283 | 176 | for (String arg : args) |
284 | { | |
285 | 1063 | if (arg.startsWith(DOUBLEDASH)) |
286 | { | |
287 | 836 | dd = true; |
288 | 836 | if (mixedExamples[1] == null) |
289 | { | |
290 | 149 | mixedExamples[1] = arg; |
291 | } | |
292 | } | |
293 | 227 | else if ((arg.startsWith("-") && !arg.equals(STDOUTFILENAME)) |
294 | || arg.equals("open")) | |
295 | { | |
296 | 44 | d = true; |
297 | 44 | if (mixedExamples[0] == null) |
298 | { | |
299 | 18 | mixedExamples[0] = arg; |
300 | } | |
301 | } | |
302 | } | |
303 | 176 | if (d) |
304 | { | |
305 | 18 | if (dd) |
306 | { | |
307 | 0 | mixedArguments = true; |
308 | } | |
309 | else | |
310 | { | |
311 | 18 | oldArguments = true; |
312 | } | |
313 | } | |
314 | ||
315 | 176 | if (oldArguments || mixedArguments) |
316 | { | |
317 | // leave it to the old style -- parse an empty list | |
318 | 18 | parse(new ArrayList<String>(), false, false); |
319 | 18 | return; |
320 | } | |
321 | ||
322 | // preprocess for associated files only if no actual --args supplied | |
323 | 158 | Console.debug("Supplied args are " + args); |
324 | 158 | if (!dd && !Cache.getDefault("NOARGPREPROCESSING", false)) |
325 | { | |
326 | 9 | ArgParserUtils.preProcessArgs(args); |
327 | 9 | Console.debug("Preprocessed args are " + args); |
328 | } | |
329 | ||
330 | 158 | if (bsa != null) |
331 | { | |
332 | 112 | this.bootstrapArgs = bsa; |
333 | } | |
334 | else | |
335 | { | |
336 | 46 | this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args); |
337 | } | |
338 | 158 | parse(args, initsubstitutions, allowPrivate); |
339 | } | |
340 | ||
341 | 176 | private void parse(List<String> args, boolean initsubstitutions, |
342 | boolean allowPrivate) | |
343 | { | |
344 | 176 | this.substitutions = initsubstitutions; |
345 | ||
346 | /* | |
347 | * If the first argument does not start with "--" or "-" or is not "open", | |
348 | * and is a filename that exists or a URL, it is probably a file/list of | |
349 | * files to open so we insert an Arg.OPEN argument before it. This will | |
350 | * mean the list of files at the start of the arguments are all opened | |
351 | * separately. | |
352 | */ | |
353 | 176 | if (args.size() > 0) |
354 | { | |
355 | 149 | String arg0 = args.get(0); |
356 | 149 | if (arg0 != null |
357 | && (!arg0.startsWith(DOUBLEDASH) && !arg0.startsWith("-") | |
358 | && !arg0.equals("open") && (new File(arg0).exists() | |
359 | || HttpUtils.startsWithHttpOrHttps(arg0)))) | |
360 | { | |
361 | // insert "--open" at the start | |
362 | 6 | args.add(0, Arg.OPEN.argString()); |
363 | } | |
364 | } | |
365 | ||
366 | 1088 | for (int i = 0; i < args.size(); i++) |
367 | { | |
368 | 912 | String arg = args.get(i); |
369 | ||
370 | // look for double-dash, e.g. --arg | |
371 | 912 | if (arg.startsWith(DOUBLEDASH)) |
372 | { | |
373 | 842 | String argName = null; |
374 | 842 | String val = null; |
375 | 842 | List<String> globVals = null; // for Opt.GLOB only |
376 | 842 | SubVals globSubVals = null; // also for use by Opt.GLOB only |
377 | 842 | String linkedId = null; |
378 | 842 | String givenLinkedId = null; // this is preserved to add to each |
379 | // "ArgValue" | |
380 | 842 | Type type = null; |
381 | ||
382 | // look for equals e.g. --arg=value | |
383 | 842 | int equalPos = arg.indexOf(EQUALS); |
384 | 842 | if (equalPos > -1) |
385 | { | |
386 | 375 | argName = arg.substring(DOUBLEDASH.length(), equalPos); |
387 | 375 | val = arg.substring(equalPos + 1); |
388 | } | |
389 | else | |
390 | { | |
391 | 467 | argName = arg.substring(DOUBLEDASH.length()); |
392 | } | |
393 | ||
394 | // look for linked ID e.g. --arg[linkedID] | |
395 | 842 | int idOpen = argName.indexOf('['); |
396 | 842 | int idClose = argName.indexOf(']'); |
397 | 842 | if (idOpen > -1 && idClose == argName.length() - 1) |
398 | { | |
399 | 68 | linkedId = argName.substring(idOpen + 1, idClose); |
400 | 68 | givenLinkedId = linkedId; |
401 | 68 | argName = argName.substring(0, idOpen); |
402 | } | |
403 | ||
404 | // look for type modification e.g. --help-opening | |
405 | 842 | int dashPos = argName.indexOf(SINGLEDASH); |
406 | 842 | if (dashPos > -1) |
407 | { | |
408 | 0 | String potentialArgName = argName.substring(0, dashPos); |
409 | 0 | Arg potentialArg = argMap.get(potentialArgName); |
410 | 0 | if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE)) |
411 | { | |
412 | 0 | String typeName = argName.substring(dashPos + 1); |
413 | 0 | try |
414 | { | |
415 | 0 | type = Type.valueOf(typeName); |
416 | } catch (IllegalArgumentException e) | |
417 | { | |
418 | 0 | type = Type.INVALID; |
419 | } | |
420 | 0 | argName = argName.substring(0, dashPos); |
421 | } | |
422 | } | |
423 | ||
424 | 842 | Arg a = argMap.get(argName); |
425 | // check for boolean prepended by "no" e.g. --nowrap | |
426 | 842 | boolean negated = false; |
427 | 842 | if (a == null) |
428 | { | |
429 | 106 | if (argName.startsWith(NEGATESTRING) && argMap |
430 | .containsKey(argName.substring(NEGATESTRING.length()))) | |
431 | { | |
432 | 106 | argName = argName.substring(NEGATESTRING.length()); |
433 | 106 | a = argMap.get(argName); |
434 | 106 | negated = true; |
435 | } | |
436 | else | |
437 | { | |
438 | // after all other args, look for Opt.PREFIXKEV args if still not | |
439 | // found | |
440 | 0 | for (Arg potentialArg : EnumSet.allOf(Arg.class)) |
441 | { | |
442 | 0 | if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null |
443 | && argName.startsWith(potentialArg.getName()) | |
444 | && equalPos > -1) | |
445 | { | |
446 | 0 | val = argName.substring(potentialArg.getName().length()) |
447 | + EQUALS + val; | |
448 | 0 | argName = argName.substring(0, |
449 | potentialArg.getName().length()); | |
450 | 0 | a = potentialArg; |
451 | 0 | break; |
452 | } | |
453 | } | |
454 | } | |
455 | } | |
456 | ||
457 | // check for config errors | |
458 | 842 | if (a == null) |
459 | { | |
460 | // arg not found | |
461 | 0 | Console.error("Argument '" + arg + "' not recognised. Exiting."); |
462 | 0 | Jalview.exit( |
463 | "Invalid argument used." + System.lineSeparator() + "Use" | |
464 | + System.lineSeparator() + "jalview " | |
465 | + Arg.HELP.argString() + System.lineSeparator() | |
466 | + "for a usage statement.", | |
467 | ExitCode.INVALID_ARGUMENT); | |
468 | 0 | continue; |
469 | } | |
470 | 842 | if (a.hasOption(Opt.PRIVATE) && !allowPrivate) |
471 | { | |
472 | 0 | Console.error( |
473 | "Argument '" + a.argString() + "' is private. Ignoring."); | |
474 | 0 | continue; |
475 | } | |
476 | 842 | if (!a.hasOption(Opt.BOOLEAN) && negated) |
477 | { | |
478 | // used "no" with a non-boolean option | |
479 | 1 | Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName |
480 | + "' not a boolean option. Ignoring."); | |
481 | 1 | continue; |
482 | } | |
483 | 841 | if (!a.hasOption(Opt.STRING) && equalPos > -1) |
484 | { | |
485 | // set --argname=value when arg does not accept values | |
486 | 0 | Console.error("Argument '" + a.argString() |
487 | + "' does not expect a value (given as '" + arg | |
488 | + "'). Ignoring."); | |
489 | 0 | continue; |
490 | } | |
491 | 841 | if (!a.hasOption(Opt.LINKED) && linkedId != null) |
492 | { | |
493 | // set --argname[linkedId] when arg does not use linkedIds | |
494 | 0 | Console.error("Argument '" + a.argString() |
495 | + "' does not expect a linked id (given as '" + arg | |
496 | + "'). Ignoring."); | |
497 | 0 | continue; |
498 | } | |
499 | ||
500 | // String value(s) | |
501 | 841 | if (a.hasOption(Opt.STRING)) |
502 | { | |
503 | 490 | if (equalPos >= 0) |
504 | { | |
505 | 375 | if (a.hasOption(Opt.GLOB)) |
506 | { | |
507 | // strip off and save the SubVals to be added individually later | |
508 | 124 | globSubVals = new SubVals(val); |
509 | // make substitutions before looking for files | |
510 | 124 | String fileGlob = makeSubstitutions(globSubVals.getContent(), |
511 | linkedId); | |
512 | 124 | globVals = FileUtils.getFilenamesFromGlob(fileGlob); |
513 | } | |
514 | else | |
515 | { | |
516 | // val is already set -- will be saved in the ArgValue later in | |
517 | // the normal way | |
518 | } | |
519 | } | |
520 | else | |
521 | { | |
522 | // There is no "=" so value is next arg or args (possibly shell | |
523 | // glob-expanded) | |
524 | 115 | if (i + 1 >= args.size()) |
525 | { | |
526 | // no value to take for arg, which wants a value | |
527 | 4 | Console.error("Argument '" + a.getName() |
528 | + "' requires a value, none given. Ignoring."); | |
529 | 4 | continue; |
530 | } | |
531 | // deal with bash globs here (--arg val* is expanded before reaching | |
532 | // the JVM). Note that SubVals cannot be used in this case. | |
533 | // If using the --arg=val then the glob is preserved and Java globs | |
534 | // will be used later. SubVals can be used. | |
535 | 111 | if (a.hasOption(Opt.GLOB)) |
536 | { | |
537 | // if this is the first argument with a file list at the start of | |
538 | // the args we add filenames from index i instead of i+1 | |
539 | 41 | globVals = getShellGlobbedFilenameValues(a, args, i + 1); |
540 | } | |
541 | else | |
542 | { | |
543 | 70 | val = args.get(i + 1); |
544 | } | |
545 | } | |
546 | } | |
547 | ||
548 | // make NOACTION adjustments | |
549 | // default and auto counter increments | |
550 | 837 | if (a == Arg.NPP) |
551 | { | |
552 | 0 | linkedIdAutoCounter++; |
553 | } | |
554 | 837 | else if (a == Arg.SUBSTITUTIONS) |
555 | { | |
556 | 28 | substitutions = !negated; |
557 | } | |
558 | 809 | else if (a == Arg.SETARGFILE) |
559 | { | |
560 | 14 | argFile = val; |
561 | } | |
562 | 795 | else if (a == Arg.UNSETARGFILE) |
563 | { | |
564 | 14 | argFile = null; |
565 | } | |
566 | 781 | else if (a == Arg.ALL) |
567 | { | |
568 | 13 | allLinkedIds = !negated; |
569 | } | |
570 | 768 | else if (a == Arg.ALLSTRUCTURES) |
571 | { | |
572 | 3 | allStructures = !negated; |
573 | } | |
574 | ||
575 | 837 | if (a.hasOption(Opt.STORED)) |
576 | { | |
577 | // reset the lastOpenedLinkedIds list | |
578 | 97 | this.storedLinkedIds = new ArrayList<>(); |
579 | } | |
580 | ||
581 | // this is probably only Arg.NEW and Arg.OPEN | |
582 | 837 | if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER)) |
583 | { | |
584 | // use the next default prefixed OPENLINKEDID | |
585 | 114 | defaultLinkedId(true); |
586 | } | |
587 | ||
588 | 837 | String autoCounterString = null; |
589 | 837 | String defaultLinkedId = defaultLinkedId(false); |
590 | 837 | boolean usingDefaultLinkedId = false; |
591 | 837 | if (a.hasOption(Opt.LINKED)) |
592 | { | |
593 | 539 | if (linkedId == null) |
594 | { | |
595 | 471 | if (a.hasOption(Opt.OUTPUTFILE) && a.hasOption(Opt.ALLOWMULTIID) |
596 | && val.contains(MATCHALLLINKEDIDS)) | |
597 | { | |
598 | // --output=*.ext is shorthand for --output {basename}.ext | |
599 | // --output=*/*.ext is shorthand for | |
600 | // --output {dirname}/{basename}.ext | |
601 | // (or --image=*.ext) | |
602 | 3 | linkedId = allLinkedIds ? MATCHALLLINKEDIDS |
603 | : MATCHOPENEDLINKEDIDS; | |
604 | 3 | val = FileUtils.convertWildcardsToPath(val, MATCHALLLINKEDIDS, |
605 | LINKEDIDDIRNAME, LINKEDIDBASENAME); | |
606 | } | |
607 | 468 | else if (allLinkedIds && a.hasOption(Opt.ALLOWMULTIID)) |
608 | { | |
609 | 22 | linkedId = MATCHALLLINKEDIDS; |
610 | } | |
611 | 471 | if (allLinkedIds) |
612 | { | |
613 | // user has made conscious decision for these args to apply to | |
614 | // all, so set givenLinkedId too | |
615 | 23 | givenLinkedId = linkedId; |
616 | } | |
617 | 448 | else if (a.hasOption(Opt.ALLOWMULTIID) |
618 | && this.storedLinkedIds != null | |
619 | && this.storedLinkedIds.size() > 0) | |
620 | { | |
621 | 209 | linkedId = MATCHOPENEDLINKEDIDS; |
622 | } | |
623 | else | |
624 | { | |
625 | // use default linkedId for linked arguments | |
626 | 239 | linkedId = defaultLinkedId; |
627 | 239 | usingDefaultLinkedId = true; |
628 | 239 | Console.debug("Changing linkedId to '" + linkedId + "' from " |
629 | + arg); | |
630 | } | |
631 | } | |
632 | else | |
633 | { | |
634 | 68 | if (linkedId.contains(LINKEDIDAUTOCOUNTER)) |
635 | { | |
636 | // turn {n} to the autoCounter | |
637 | 40 | autoCounterString = Integer.toString(linkedIdAutoCounter); |
638 | 40 | linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER, |
639 | autoCounterString); | |
640 | 40 | Console.debug("Changing linkedId to '" + linkedId + "' from " |
641 | + arg); | |
642 | } | |
643 | 68 | if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER)) |
644 | { | |
645 | // turn {++n} to the incremented autoCounter | |
646 | 15 | autoCounterString = Integer.toString(++linkedIdAutoCounter); |
647 | 15 | linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER, |
648 | autoCounterString); | |
649 | 15 | Console.debug("Changing linkedId to '" + linkedId + "' from " |
650 | + arg); | |
651 | } | |
652 | } | |
653 | } | |
654 | ||
655 | // do not continue in this block for NOACTION args | |
656 | 837 | if (a.hasOption(Opt.NOACTION)) |
657 | 98 | continue; |
658 | ||
659 | 739 | ArgValuesMap avm = getOrCreateLinkedArgValuesMap(linkedId); |
660 | ||
661 | // not dealing with both NODUPLICATEVALUES and GLOB | |
662 | 739 | if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val)) |
663 | { | |
664 | 0 | Console.error("Argument '" + a.argString() |
665 | + "' cannot contain a duplicate value ('" + val | |
666 | + "'). Ignoring this and subsequent occurrences."); | |
667 | 0 | continue; |
668 | } | |
669 | ||
670 | // check for unique id | |
671 | 739 | SubVals subvals = new SubVals(val); |
672 | 739 | boolean addNewSubVals = false; |
673 | 739 | String id = subvals.get(ArgValues.ID); |
674 | 739 | if (id != null && avm.hasId(a, id)) |
675 | { | |
676 | 0 | Console.error("Argument '" + a.argString() |
677 | + "' has a duplicate id ('" + id + "'). Ignoring."); | |
678 | 0 | continue; |
679 | } | |
680 | ||
681 | // set allstructures to all non-primary structure options in this linked | |
682 | // id if --allstructures has been set | |
683 | 739 | if (allStructures && (a.hasType(Type.STRUCTURE) |
684 | // || a.getType() == Type.STRUCTUREIMAGE) | |
685 | ) && !a.hasOption(Opt.PRIMARY)) | |
686 | { | |
687 | 1 | if (!subvals.has(Arg.ALLSTRUCTURES.getName())) |
688 | // && !subvals.has("structureid")) | |
689 | { | |
690 | 1 | subvals.put(Arg.ALLSTRUCTURES.getName(), "true"); |
691 | 1 | addNewSubVals = true; |
692 | } | |
693 | } | |
694 | ||
695 | 739 | ArgValues avs = avm.getOrCreateArgValues(a); |
696 | ||
697 | // store appropriate String value(s) | |
698 | 739 | if (a.hasOption(Opt.STRING)) |
699 | { | |
700 | 472 | if (a.hasOption(Opt.GLOB) && globVals != null |
701 | && globVals.size() > 0) | |
702 | { | |
703 | 165 | Enumeration<String> gve = Collections.enumeration(globVals); |
704 | 410 | while (gve.hasMoreElements()) |
705 | { | |
706 | 245 | String v = gve.nextElement(); |
707 | 245 | SubVals vsv = new SubVals(globSubVals, v); |
708 | 245 | addValue(linkedId, givenLinkedId, type, avs, vsv, v, |
709 | argIndex++, true); | |
710 | // if we're using defaultLinkedId and the arg increments the | |
711 | // counter: | |
712 | 245 | if (gve.hasMoreElements() && usingDefaultLinkedId |
713 | && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER)) | |
714 | { | |
715 | // increment the default linkedId | |
716 | 59 | linkedId = defaultLinkedId(true); |
717 | // get new avm and avs | |
718 | 59 | avm = linkedArgs.get(linkedId); |
719 | 59 | avs = avm.getOrCreateArgValues(a); |
720 | } | |
721 | } | |
722 | } | |
723 | else | |
724 | { | |
725 | // addValue(linkedId, type, avs, val, argIndex, true); | |
726 | 307 | addValue(linkedId, givenLinkedId, type, avs, |
727 | 307 | addNewSubVals ? subvals : null, val, argIndex, true); |
728 | } | |
729 | } | |
730 | 267 | else if (a.hasOption(Opt.BOOLEAN)) |
731 | { | |
732 | 134 | setBoolean(linkedId, givenLinkedId, type, avs, !negated, |
733 | argIndex); | |
734 | 134 | setNegated(linkedId, avs, negated); |
735 | } | |
736 | 133 | else if (a.hasOption(Opt.UNARY)) |
737 | { | |
738 | 133 | setBoolean(linkedId, givenLinkedId, type, avs, true, argIndex); |
739 | } | |
740 | ||
741 | // remove the '*' or 'open*' linkedId that should be empty if it was | |
742 | // created | |
743 | 739 | if ((MATCHALLLINKEDIDS.equals(linkedId) |
744 | || MATCHOPENEDLINKEDIDS.equals(linkedId)) | |
745 | && linkedArgs.containsKey(linkedId)) | |
746 | { | |
747 | 232 | linkedArgs.remove(linkedId); |
748 | } | |
749 | } | |
750 | } | |
751 | } | |
752 | ||
753 | 925 | private void finaliseStoringArgValue(String linkedId, ArgValues avs) |
754 | { | |
755 | 925 | Arg a = avs.arg(); |
756 | 925 | incrementCount(linkedId, avs); |
757 | 925 | argIndex++; |
758 | ||
759 | // store in appropriate place | |
760 | 925 | if (a.hasOption(Opt.LINKED)) |
761 | { | |
762 | // store the order of linkedIds | |
763 | 683 | if (!linkedOrder.contains(linkedId)) |
764 | 221 | linkedOrder.add(linkedId); |
765 | } | |
766 | ||
767 | // store arg in the list of args used | |
768 | 925 | if (!argList.contains(a)) |
769 | 591 | argList.add(a); |
770 | } | |
771 | ||
772 | 1010 | private String defaultLinkedId(boolean increment) |
773 | { | |
774 | 1010 | String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX) |
775 | .append(Integer.toString(defaultLinkedIdCounter)).toString(); | |
776 | 1010 | if (increment) |
777 | { | |
778 | 314 | while (linkedArgs.containsKey(defaultLinkedId)) |
779 | { | |
780 | 141 | defaultLinkedIdCounter++; |
781 | 141 | defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX) |
782 | .append(Integer.toString(defaultLinkedIdCounter)) | |
783 | .toString(); | |
784 | } | |
785 | } | |
786 | 1010 | getOrCreateLinkedArgValuesMap(defaultLinkedId); |
787 | 1010 | return defaultLinkedId; |
788 | } | |
789 | ||
790 | 736 | public String makeSubstitutions(String val, String linkedId) |
791 | { | |
792 | 736 | return makeSubstitutions(val, linkedId, false); |
793 | } | |
794 | ||
795 | 746 | public String makeSubstitutions(String val, String linkedId, |
796 | boolean onthefly) | |
797 | { | |
798 | 746 | if (!this.substitutions || val == null) |
799 | 185 | return val; |
800 | ||
801 | 561 | String subvals; |
802 | 561 | String rest; |
803 | 561 | if (val.indexOf('[') == 0 && val.indexOf(']') > 1) |
804 | { | |
805 | 13 | int closeBracket = val.indexOf(']'); |
806 | 13 | if (val.length() == closeBracket) |
807 | 0 | return val; |
808 | 13 | subvals = val.substring(0, closeBracket + 1); |
809 | 13 | rest = val.substring(closeBracket + 1); |
810 | } | |
811 | else | |
812 | { | |
813 | 548 | subvals = ""; |
814 | 548 | rest = val; |
815 | } | |
816 | 561 | if (rest.contains(LINKEDIDAUTOCOUNTER)) |
817 | { | |
818 | 14 | rest = rest.replace(LINKEDIDAUTOCOUNTER, |
819 | String.valueOf(linkedIdAutoCounter)); | |
820 | } | |
821 | 561 | if (rest.contains(INCREMENTLINKEDIDAUTOCOUNTER)) |
822 | { | |
823 | 0 | rest = rest.replace(INCREMENTLINKEDIDAUTOCOUNTER, |
824 | String.valueOf(++linkedIdAutoCounter)); | |
825 | } | |
826 | 561 | if (rest.contains(DEFAULTLINKEDIDCOUNTER)) |
827 | { | |
828 | 0 | rest = rest.replace(DEFAULTLINKEDIDCOUNTER, |
829 | String.valueOf(defaultLinkedIdCounter)); | |
830 | } | |
831 | 561 | ArgValuesMap avm = linkedArgs.get(linkedId); |
832 | 561 | if (avm != null) |
833 | { | |
834 | 535 | if (rest.contains(LINKEDIDBASENAME)) |
835 | { | |
836 | 74 | rest = rest.replace(LINKEDIDBASENAME, avm.getBasename()); |
837 | } | |
838 | 535 | if (rest.contains(LINKEDIDEXTENSION)) |
839 | { | |
840 | 0 | rest = rest.replace(LINKEDIDEXTENSION, avm.getExtension()); |
841 | } | |
842 | 535 | if (rest.contains(LINKEDIDDIRNAME)) |
843 | { | |
844 | 86 | rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname()); |
845 | } | |
846 | } | |
847 | 561 | if (argFile != null) |
848 | { | |
849 | 108 | if (rest.contains(ARGFILEBASENAME)) |
850 | { | |
851 | 0 | rest = rest.replace(ARGFILEBASENAME, |
852 | FileUtils.getBasename(new File(argFile))); | |
853 | } | |
854 | 108 | if (rest.contains(ARGFILEDIRNAME)) |
855 | { | |
856 | 14 | rest = rest.replace(ARGFILEDIRNAME, |
857 | FileUtils.getDirname(new File(argFile))); | |
858 | } | |
859 | } | |
860 | 561 | if (onthefly) |
861 | { | |
862 | 10 | if (rest.contains(ONTHEFLYCOUNTER)) |
863 | { | |
864 | 0 | rest = rest.replace(ONTHEFLYCOUNTER, |
865 | String.valueOf(ontheflyCounter)); | |
866 | } | |
867 | 10 | if (rest.contains(INCREMENTONTHEFLYCOUNTER)) |
868 | { | |
869 | 0 | rest = rest.replace(INCREMENTONTHEFLYCOUNTER, |
870 | String.valueOf(++ontheflyCounter)); | |
871 | } | |
872 | 10 | if (currentStructureFilename != null) |
873 | { | |
874 | 10 | if (rest.contains(STRUCTUREBASENAME)) |
875 | { | |
876 | 0 | rest = rest.replace(STRUCTUREBASENAME, FileUtils |
877 | .getBasename(new File(currentStructureFilename))); | |
878 | } | |
879 | 10 | if (rest.contains(STRUCTUREDIRNAME)) |
880 | { | |
881 | 0 | rest = rest.replace(STRUCTUREDIRNAME, |
882 | FileUtils.getDirname(new File(currentStructureFilename))); | |
883 | } | |
884 | } | |
885 | } | |
886 | ||
887 | 561 | return new StringBuilder(subvals).append(rest).toString(); |
888 | } | |
889 | ||
890 | /* | |
891 | * A helper method to take a list of String args where we're expecting | |
892 | * {"--previousargs", "--arg", "file1", "file2", "file3", "--otheroptionsornot"} | |
893 | * and the index of the globbed arg, here 1. It returns a List<String> {"file1", | |
894 | * "file2", "file3"} *and remove these from the original list object* so that | |
895 | * processing can continue from where it has left off, e.g. args has become | |
896 | * {"--previousargs", "--arg", "--otheroptionsornot"} so the next increment | |
897 | * carries on from the next --arg if available. | |
898 | */ | |
899 | 70 | protected static List<String> getShellGlobbedFilenameValues(Arg a, |
900 | List<String> args, int i) | |
901 | { | |
902 | 70 | List<String> vals = new ArrayList<>(); |
903 | 136 | while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH)) |
904 | { | |
905 | 87 | vals.add(FileUtils.substituteHomeDir(args.remove(i))); |
906 | 87 | if (!a.hasOption(Opt.GLOB)) |
907 | 21 | break; |
908 | } | |
909 | 70 | return vals; |
910 | } | |
911 | ||
912 | 243 | public BootstrapArgs getBootstrapArgs() |
913 | { | |
914 | 243 | return bootstrapArgs; |
915 | } | |
916 | ||
917 | 98 | public boolean isSet(Arg a) |
918 | { | |
919 | 98 | return a.hasOption(Opt.LINKED) ? isSetAtAll(a) : isSet(null, a); |
920 | } | |
921 | ||
922 | 23 | public boolean isSetAtAll(Arg a) |
923 | { | |
924 | 23 | for (String linkedId : linkedOrder) |
925 | { | |
926 | 23 | if (isSet(linkedId, a)) |
927 | 23 | return true; |
928 | } | |
929 | 0 | return false; |
930 | } | |
931 | ||
932 | 98 | public boolean isSet(String linkedId, Arg a) |
933 | { | |
934 | 98 | ArgValuesMap avm = linkedArgs.get(linkedId); |
935 | 98 | return avm == null ? false : avm.containsArg(a); |
936 | } | |
937 | ||
938 | 159 | public boolean getBoolean(Arg a) |
939 | { | |
940 | 159 | if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY)) |
941 | { | |
942 | 0 | Console.warn("Getting boolean from non boolean Arg '" + a.getName() |
943 | + "'."); | |
944 | } | |
945 | 159 | return a.hasOption(Opt.LINKED) ? getBool("", a) : getBool(null, a); |
946 | } | |
947 | ||
948 | 159 | public boolean getBool(String linkedId, Arg a) |
949 | { | |
950 | 159 | ArgValuesMap avm = linkedArgs.get(linkedId); |
951 | 159 | if (avm == null) |
952 | 51 | return a.getDefaultBoolValue(); |
953 | 108 | ArgValues avs = avm.getArgValues(a); |
954 | 108 | return avs == null ? a.getDefaultBoolValue() : avs.getBoolean(); |
955 | } | |
956 | ||
957 | 286 | public List<String> getLinkedIds() |
958 | { | |
959 | 286 | return linkedOrder; |
960 | } | |
961 | ||
962 | 805 | public ArgValuesMap getLinkedArgs(String id) |
963 | { | |
964 | 805 | return linkedArgs.get(id); |
965 | } | |
966 | ||
967 | 0 | @Override |
968 | public String toString() | |
969 | { | |
970 | 0 | StringBuilder sb = new StringBuilder(); |
971 | 0 | sb.append("UNLINKED\n"); |
972 | 0 | sb.append(argValuesMapToString(linkedArgs.get(null))); |
973 | 0 | if (getLinkedIds() != null) |
974 | { | |
975 | 0 | sb.append("LINKED\n"); |
976 | 0 | for (String id : getLinkedIds()) |
977 | { | |
978 | // already listed these as UNLINKED args | |
979 | 0 | if (id == null) |
980 | 0 | continue; |
981 | ||
982 | 0 | ArgValuesMap avm = getLinkedArgs(id); |
983 | 0 | sb.append("ID: '").append(id).append("'\n"); |
984 | 0 | sb.append(argValuesMapToString(avm)); |
985 | } | |
986 | } | |
987 | 0 | return sb.toString(); |
988 | } | |
989 | ||
990 | 0 | private static String argValuesMapToString(ArgValuesMap avm) |
991 | { | |
992 | 0 | if (avm == null) |
993 | 0 | return null; |
994 | 0 | StringBuilder sb = new StringBuilder(); |
995 | 0 | for (Arg a : avm.getArgKeys()) |
996 | { | |
997 | 0 | ArgValues v = avm.getArgValues(a); |
998 | 0 | sb.append(v.toString()); |
999 | 0 | sb.append("\n"); |
1000 | } | |
1001 | 0 | return sb.toString(); |
1002 | } | |
1003 | ||
1004 | 8 | public static ArgParser parseArgFiles(List<String> argFilenameGlobs, |
1005 | boolean initsubstitutions, BootstrapArgs bsa) | |
1006 | { | |
1007 | 8 | List<File> argFiles = new ArrayList<>(); |
1008 | ||
1009 | 8 | for (String pattern : argFilenameGlobs) |
1010 | { | |
1011 | // I don't think we want to dedup files, making life easier | |
1012 | 14 | argFiles.addAll(FileUtils.getFilesFromGlob(pattern)); |
1013 | } | |
1014 | ||
1015 | 8 | return parseArgFileList(argFiles, initsubstitutions, bsa); |
1016 | } | |
1017 | ||
1018 | 8 | public static ArgParser parseArgFileList(List<File> argFiles, |
1019 | boolean initsubstitutions, BootstrapArgs bsa) | |
1020 | { | |
1021 | 8 | List<String> argsList = new ArrayList<>(); |
1022 | 8 | for (File argFile : argFiles) |
1023 | { | |
1024 | 14 | if (!argFile.exists()) |
1025 | { | |
1026 | 0 | String message = Arg.ARGFILE.argString() + EQUALS + "\"" |
1027 | + argFile.getPath() + "\": File does not exist."; | |
1028 | 0 | Jalview.exit(message, ExitCode.FILE_NOT_FOUND); |
1029 | } | |
1030 | 14 | try |
1031 | { | |
1032 | 14 | String setargfile = new StringBuilder(Arg.SETARGFILE.argString()) |
1033 | .append(EQUALS).append(argFile.getCanonicalPath()) | |
1034 | .toString(); | |
1035 | 14 | argsList.add(setargfile); |
1036 | 14 | argsList.addAll(readArgFile(argFile)); |
1037 | 14 | argsList.add(Arg.UNSETARGFILE.argString()); |
1038 | } catch (IOException e) | |
1039 | { | |
1040 | 0 | String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath() |
1041 | + "\": File could not be read."; | |
1042 | 0 | Jalview.exit(message, ExitCode.FILE_NOT_READABLE); |
1043 | } | |
1044 | } | |
1045 | // Third param "true" uses Opt.PRIVATE args --setargile=argfile and | |
1046 | // --unsetargfile | |
1047 | 8 | return new ArgParser(argsList, initsubstitutions, true, bsa); |
1048 | } | |
1049 | ||
1050 | 67 | protected static List<String> readArgFile(File argFile) |
1051 | { | |
1052 | 67 | List<String> args = new ArrayList<>(); |
1053 | 67 | if (argFile != null && argFile.exists()) |
1054 | { | |
1055 | 67 | try |
1056 | { | |
1057 | 67 | for (String line : Files.readAllLines(Paths.get(argFile.getPath()))) |
1058 | { | |
1059 | 300 | if (line != null && line.length() > 0 |
1060 | && line.charAt(0) != ARGFILECOMMENT) | |
1061 | 296 | args.add(line); |
1062 | } | |
1063 | } catch (IOException e) | |
1064 | { | |
1065 | 0 | String message = Arg.ARGFILE.argString() + "=\"" + argFile.getPath() |
1066 | + "\": File could not be read."; | |
1067 | 0 | Console.debug(message, e); |
1068 | 0 | Jalview.exit(message, ExitCode.FILE_NOT_READABLE); |
1069 | } | |
1070 | } | |
1071 | 67 | return args; |
1072 | } | |
1073 | ||
1074 | // the following methods look for the "*" linkedId and add the argvalue to all | |
1075 | // linkedId ArgValues if it does. | |
1076 | /** | |
1077 | * This version inserts the subvals sv into all created values | |
1078 | */ | |
1079 | 552 | private void addValue(String linkedId, String givenLinkedId, Type type, |
1080 | ArgValues avs, SubVals sv, String v, int argIndex, boolean doSubs) | |
1081 | { | |
1082 | 552 | this.argValueOperation(Op.ADDVALUE, linkedId, givenLinkedId, type, avs, |
1083 | sv, v, false, argIndex, doSubs); | |
1084 | } | |
1085 | ||
1086 | 267 | private void setBoolean(String linkedId, String givenLinkedId, Type type, |
1087 | ArgValues avs, boolean b, int argIndex) | |
1088 | { | |
1089 | 267 | this.argValueOperation(Op.SETBOOLEAN, linkedId, givenLinkedId, type, |
1090 | avs, null, null, b, argIndex, false); | |
1091 | } | |
1092 | ||
1093 | 134 | private void setNegated(String linkedId, ArgValues avs, boolean b) |
1094 | { | |
1095 | 134 | this.argValueOperation(Op.SETNEGATED, linkedId, null, null, avs, null, |
1096 | null, b, 0, false); | |
1097 | } | |
1098 | ||
1099 | 925 | private void incrementCount(String linkedId, ArgValues avs) |
1100 | { | |
1101 | 925 | this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, null, avs, |
1102 | null, null, false, 0, false); | |
1103 | } | |
1104 | ||
1105 | private enum Op | |
1106 | { | |
1107 | ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT | |
1108 | } | |
1109 | ||
1110 | 1878 | private void argValueOperation(Op op, String linkedId, |
1111 | String givenLinkedId, Type type, ArgValues avs, SubVals sv, | |
1112 | String v, boolean b, int argIndex, boolean doSubs) | |
1113 | { | |
1114 | // default to merge subvals if subvals are provided | |
1115 | 1878 | argValueOperation(op, linkedId, givenLinkedId, type, avs, sv, true, v, |
1116 | b, argIndex, doSubs); | |
1117 | } | |
1118 | ||
1119 | /** | |
1120 | * The following operations look for the "*" and "open*" linkedIds and add the | |
1121 | * argvalue to all appropriate linkedId ArgValues if it does. If subvals are | |
1122 | * supplied, they are inserted into all new set values. | |
1123 | * | |
1124 | * @param op | |
1125 | * The ArgParser.Op operation | |
1126 | * @param linkedId | |
1127 | * The String linkedId from the ArgValuesMap | |
1128 | * @param type | |
1129 | * The Arg.Type to attach to this ArgValue | |
1130 | * @param avs | |
1131 | * The ArgValues for this linkedId | |
1132 | * @param sv | |
1133 | * Use these SubVals on the ArgValue | |
1134 | * @param merge | |
1135 | * Merge the SubVals with any existing on the value. False will | |
1136 | * replace unless sv is null | |
1137 | * @param v | |
1138 | * The value of the ArgValue (may contain subvals). | |
1139 | * @param b | |
1140 | * The boolean value of the ArgValue. | |
1141 | * @param argIndex | |
1142 | * The argIndex for the ArgValue. | |
1143 | * @param doSubs | |
1144 | * Whether to perform substitutions on the subvals and value. | |
1145 | */ | |
1146 | 1878 | private void argValueOperation(Op op, String linkedId, |
1147 | String givenLinkedId, Type type, ArgValues avs, SubVals sv, | |
1148 | boolean merge, String v, boolean b, int argIndex, boolean doSubs) | |
1149 | { | |
1150 | 1878 | Arg a = avs.arg(); |
1151 | ||
1152 | 1878 | List<String> wildcardLinkedIds = null; |
1153 | 1878 | if (a.hasOption(Opt.ALLOWMULTIID)) |
1154 | { | |
1155 | 828 | switch (linkedId) |
1156 | { | |
1157 | 23 | case MATCHALLLINKEDIDS: |
1158 | 23 | wildcardLinkedIds = getLinkedIds(); |
1159 | 23 | break; |
1160 | 239 | case MATCHOPENEDLINKEDIDS: |
1161 | 239 | wildcardLinkedIds = this.storedLinkedIds; |
1162 | 239 | break; |
1163 | } | |
1164 | } | |
1165 | ||
1166 | // if we're not a wildcard linkedId and the arg is marked to be stored, add | |
1167 | // to storedLinkedIds | |
1168 | 1878 | if (linkedId != null && wildcardLinkedIds == null |
1169 | && a.hasOption(Opt.STORED) | |
1170 | && !storedLinkedIds.contains(linkedId)) | |
1171 | { | |
1172 | 156 | storedLinkedIds.add(linkedId); |
1173 | } | |
1174 | ||
1175 | // if we are a wildcard linkedId, apply the arg and value to all appropriate | |
1176 | // linkedIds | |
1177 | 1878 | if (wildcardLinkedIds != null) |
1178 | { | |
1179 | 262 | for (String matchedLinkedId : wildcardLinkedIds) |
1180 | { | |
1181 | // skip incorrectly stored wildcard ids! | |
1182 | 368 | if (matchedLinkedId == null |
1183 | || MATCHALLLINKEDIDS.equals(matchedLinkedId) | |
1184 | || MATCHOPENEDLINKEDIDS.equals(matchedLinkedId)) | |
1185 | { | |
1186 | 0 | continue; |
1187 | } | |
1188 | 368 | ArgValuesMap avm = linkedArgs.get(matchedLinkedId); |
1189 | // don't set an output if there isn't an input | |
1190 | 368 | if (a.hasOption(Opt.REQUIREINPUT) |
1191 | && !avm.hasArgWithOption(Opt.INPUT)) | |
1192 | 0 | continue; |
1193 | ||
1194 | 368 | ArgValues tavs = avm.getOrCreateArgValues(a); |
1195 | 368 | switch (op) |
1196 | { | |
1197 | ||
1198 | 241 | case ADDVALUE: |
1199 | 241 | String val = v; |
1200 | 241 | if (sv != null) |
1201 | { | |
1202 | 1 | if (doSubs) |
1203 | { | |
1204 | 1 | sv = new SubVals(sv, val, merge); |
1205 | 1 | val = makeSubstitutions(sv.getContent(), matchedLinkedId); |
1206 | } | |
1207 | 1 | tavs.addValue(sv, type, val, argIndex, true, givenLinkedId); |
1208 | } | |
1209 | else | |
1210 | { | |
1211 | 240 | if (doSubs) |
1212 | { | |
1213 | 240 | val = makeSubstitutions(v, matchedLinkedId); |
1214 | } | |
1215 | 240 | tavs.addValue(type, val, argIndex, true, givenLinkedId); |
1216 | } | |
1217 | 241 | finaliseStoringArgValue(matchedLinkedId, tavs); |
1218 | 241 | break; |
1219 | ||
1220 | 97 | case SETBOOLEAN: |
1221 | 97 | tavs.setBoolean(type, b, argIndex, true, givenLinkedId); |
1222 | 97 | finaliseStoringArgValue(matchedLinkedId, tavs); |
1223 | 97 | break; |
1224 | ||
1225 | 30 | case SETNEGATED: |
1226 | 30 | tavs.setNegated(b, true); |
1227 | 30 | break; |
1228 | ||
1229 | 0 | case INCREMENTCOUNT: |
1230 | 0 | tavs.incrementCount(); |
1231 | 0 | break; |
1232 | ||
1233 | 0 | default: |
1234 | 0 | break; |
1235 | ||
1236 | } | |
1237 | ||
1238 | } | |
1239 | } | |
1240 | else // no wildcard linkedId -- do it simpler | |
1241 | { | |
1242 | 1616 | switch (op) |
1243 | { | |
1244 | 365 | case ADDVALUE: |
1245 | 365 | String val = v; |
1246 | 365 | if (sv != null) |
1247 | { | |
1248 | 245 | if (doSubs) |
1249 | { | |
1250 | 245 | val = makeSubstitutions(v, linkedId); |
1251 | 245 | sv = new SubVals(sv, val); |
1252 | } | |
1253 | 245 | avs.addValue(sv, type, val, argIndex, false, givenLinkedId); |
1254 | } | |
1255 | else | |
1256 | { | |
1257 | 120 | if (doSubs) |
1258 | { | |
1259 | 120 | val = makeSubstitutions(v, linkedId); |
1260 | } | |
1261 | 120 | avs.addValue(type, val, argIndex, false, givenLinkedId); |
1262 | } | |
1263 | 365 | finaliseStoringArgValue(linkedId, avs); |
1264 | 365 | break; |
1265 | ||
1266 | 222 | case SETBOOLEAN: |
1267 | 222 | avs.setBoolean(type, b, argIndex, false, givenLinkedId); |
1268 | 222 | finaliseStoringArgValue(linkedId, avs); |
1269 | 222 | break; |
1270 | ||
1271 | 104 | case SETNEGATED: |
1272 | 104 | avs.setNegated(b, false); |
1273 | 104 | break; |
1274 | ||
1275 | 925 | case INCREMENTCOUNT: |
1276 | 925 | avs.incrementCount(); |
1277 | 925 | break; |
1278 | ||
1279 | 0 | default: |
1280 | 0 | break; |
1281 | } | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | 1749 | private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId) |
1286 | { | |
1287 | 1749 | if (linkedArgs.containsKey(linkedId) |
1288 | && linkedArgs.get(linkedId) != null) | |
1289 | 1087 | return linkedArgs.get(linkedId); |
1290 | ||
1291 | 662 | linkedArgs.put(linkedId, new ArgValuesMap(linkedId)); |
1292 | 662 | return linkedArgs.get(linkedId); |
1293 | } | |
1294 | ||
1295 | 154 | public boolean isOldStyle() |
1296 | { | |
1297 | 154 | return oldArguments; |
1298 | } | |
1299 | ||
1300 | 130 | public boolean isMixedStyle() |
1301 | { | |
1302 | 130 | return mixedArguments; |
1303 | } | |
1304 | ||
1305 | 0 | public String[] getMixedExamples() |
1306 | { | |
1307 | 0 | return mixedExamples; |
1308 | } | |
1309 | ||
1310 | 117 | public void setStructureFilename(String s) |
1311 | { | |
1312 | 117 | this.currentStructureFilename = s; |
1313 | } | |
1314 | ||
1315 | } |