Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java
40948 views
1
/*
2
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
package nsk.share;
25
26
import nsk.share.test.StressOptions;
27
28
import java.util.ArrayList;
29
import java.util.Properties;
30
31
/**
32
* Parser for JDI test's command-line arguments.
33
* <p>
34
* Test's command line may contain two kind of arguments, namely:
35
* <ul>
36
* <li> options for ArgumentParser
37
* <li> other arguments for the test itself
38
* </ul>
39
* <p>
40
* We call <i>raw arguments</i> the <code>args[]</code> array
41
* passed to the test's method <code>main(String&nbsp;args[])</code>.
42
* ArgumentParser instance initialized with raw arguments serves to parse
43
* these two kinds of arguments. Use <code>ArgumentParser(args[])</code>
44
* constructor, or <code>setRawArguments(args[])</code> method
45
* to initialize a ArgumentParser instance with particular raw arguments.
46
* <p>
47
* Arguments, started with ``<code>-</code>'' symbol are called <i>options</i>.
48
* They are recognized by ArgumentParser and are used by support classes
49
* (such as Log, Binder, etc.).
50
* These options should be specified in the following general form:
51
* <ul>
52
* <li> <code>-option=<i>value</i></code>
53
* </ul>
54
* or
55
* <ul>
56
* <li> <code>-option <i>value</i></code>
57
* </ul>
58
* List of the recognized options with their values may be obtained by
59
* invoking method <code>getOptions()</code> that returns
60
* a <code>Properties</code> object with options values.
61
* It is not recommended to get options value directly. An appropriate methods
62
* such as <code>verbose()</code>, <code>getArch()</code>, etc. should be used
63
* instead.
64
* Options may appear in the test command line in any order.
65
* <p>
66
* All the other arguments of command line are called <i>test arguments</i>
67
* (or simply <i>arguments</i>). These arguments should be handled by test itself.
68
* Full list of the test arguments in the same order as they appears in the command line
69
* may be obtained by invoking method <code>getArguments()</code>.
70
* <p>
71
* Following is the list of basic options accepted by ArgumentParser:
72
* <ul>
73
* <li> <code>-arch=</code>&lt;<i>${ARCH}</i>&gt; -
74
* architecture name
75
* <li> <code>-waittime=</code>&lt;<i>minutes</i>&gt; -
76
* timeout in minutes for waiting events or so
77
* <li> <code>-verbose</code> -
78
* verbose Log mode (default is quiet)
79
* <li> <code>-trace.time</code> -
80
* prefix log messages with timestamps (default is no)
81
* </ul>
82
* Also ArgumentParser supports following stress options (see nsk.share.test.StressOptions for details):
83
* <ul>
84
* <li> <code>-stressTime</code>
85
* <li> <code>-stressIterationsFactor</code>
86
* <li> <code>-stressThreadsFactor</code>
87
* <li> <code>-stressDebug</code>
88
* </ul>
89
* <p>
90
* Note that the tests from the particular suites have its own argument handlers
91
* which accepts additional options.
92
*
93
* @see #setRawArguments(String[])
94
* @see #getRawArguments()
95
* @see #getArguments()
96
* @see #getOptions()
97
* @see nsk.share.jpda.DebugeeArgumentHandler
98
* @see nsk.share.jdwp.ArgumentHandler
99
* @see nsk.share.jdi.ArgumentHandler
100
* @see nsk.share.jvmti.ArgumentHandler
101
* @see nsk.monitoring.share.ArgumentHandler
102
*/
103
public class ArgumentParser {
104
/**
105
* Raw array of command-line arguments.
106
*
107
* @see #setRawArguments(String[])
108
* @see #getRawArguments()
109
*/
110
protected String[] rawArguments = null;
111
112
/**
113
* Refined arguments -- raw arguments but options.
114
*
115
* @see #options
116
* @see #getArguments()
117
*/
118
protected String[] arguments = null;
119
120
/**
121
* Recognized options for ArgumentParser class.
122
*
123
* @see #arguments
124
* @see #getOptions()
125
*/
126
protected Properties options = new Properties();
127
128
/**
129
* Make new ArgumentParser object with default values of options.
130
* This constructor is used only to obtain default values of options.
131
*
132
* @see #setRawArguments(String[])
133
*/
134
protected ArgumentParser() {
135
this(new String[0]);
136
}
137
138
/**
139
* Keep a copy of raw command-line arguments and parse them;
140
* but throw an exception on parsing error.
141
*
142
* @param args Array of the raw command-line arguments.
143
* @throws BadOption If option values are invalid.
144
* @see #setRawArguments(String[])
145
* @see BadOption
146
*/
147
public ArgumentParser(String[] args) {
148
ArrayList<String> list = new ArrayList<>(args.length);
149
for (int i = 0; i < args.length; ++i) {
150
StringBuilder arg = new StringBuilder(args[i]);
151
// jtreg splits the command string into arguments by space symbol
152
// and doesn't keep arguments within double quotes as one argument,
153
// so we need to join them back
154
long doubleQuotes = numberOfDoubleQuotes(args[i]);
155
while (i < args.length - 1 && (doubleQuotes % 2) != 0) {
156
arg.append(" ").append(args[++i]);
157
doubleQuotes += numberOfDoubleQuotes(args[i]);
158
}
159
if (doubleQuotes % 2 != 0) {
160
throw new TestBug("command-line has odd number of double quotes:" + String.join(" ", args));
161
}
162
163
list.add(arg.toString());
164
}
165
setRawArguments(list.toArray(String[]::new));
166
}
167
168
private static long numberOfDoubleQuotes(String s) {
169
return s.chars().filter(c -> c == '"').count();
170
}
171
172
/**
173
* Return a copy of the raw command-line arguments kept by
174
* this ArgumentParser instance.
175
*
176
* @throws NullPointerException If raw arguments were not
177
* set for this instance.
178
* @see #setRawArguments(String[])
179
*/
180
public String[] getRawArguments() {
181
return rawArguments.clone();
182
}
183
184
/**
185
* Return given raw command-line argument.
186
*
187
* @param index index of argument
188
* @return value of raw argument
189
*/
190
public String getRawArgument(int index) {
191
return rawArguments[index];
192
}
193
194
/**
195
* Return refined array of test arguments (only those of the raw
196
* arguments which are not recognized as options for ArgumentParser).
197
*
198
* <p>Note, that syntax of test arguments was not checked;
199
* while syntax of arguments describing ArgumentParser's options
200
* was checked while raw arguments were set to this ArgumentParser
201
* instance.
202
*
203
* @throws NullPointerException If raw arguments were not
204
* set for this instance.
205
* @see #setRawArguments(String[])
206
* @see #getOptions()
207
*/
208
public String[] getArguments() {
209
return arguments.clone();
210
}
211
212
/**
213
* Return list of recognized options with their values in the form of
214
* <code>Properties</code> object.
215
* If no options has been recognized, this list will be empty.
216
*
217
* @see #setRawArguments(String[])
218
* @see #getArguments()
219
*/
220
public Properties getOptions() {
221
return (Properties) options.clone();
222
}
223
224
/**
225
* Join specified arguments into one line using given quoting
226
* and separator symbols.
227
*
228
* @param args Array of the command-line arguments
229
* @param quote Symbol used to quote each argument
230
* @param separator Symbol used as separator between arguments
231
* @return Single line with arguments
232
*/
233
static public String joinArguments(String[] args, String quote, String separator) {
234
if (args.length <= 0) {
235
return "";
236
}
237
StringBuilder line = new StringBuilder(quote).append(args[0]).append(quote);
238
for (int i = 1; i < args.length; i++) {
239
line.append(separator).append(quote).append(args[i]).append(quote);
240
}
241
return line.toString();
242
}
243
244
/**
245
* Join specified arguments into one line using given quoting symbol
246
* and space as a separator symbol.
247
*
248
* @param args Array of the command-line arguments
249
* @param quote Symbol used to quote each argument
250
* @return Single line with arguments
251
*/
252
static public String joinArguments(String[] args, String quote) {
253
return joinArguments(args, quote, " ");
254
}
255
256
/**
257
* Keep a copy of command-line arguments and parse them;
258
* but throw an exception on parsing error.
259
*
260
* @param args Array of the raw command-line arguments.
261
* @throws BadOption If an option has invalid value.
262
* @see #getRawArguments()
263
* @see #getArguments()
264
*/
265
public void setRawArguments(String[] args) {
266
this.rawArguments = args.clone();
267
parseArguments();
268
}
269
270
/**
271
* Add or replace given option value in options list and in raw arguments list.
272
* Use specified <code>rawPrefix</code> while adding to raw arguments list.
273
*
274
* @see #getRawArguments()
275
* @see #getOptions()
276
*/
277
public void setOption(String rawPrefix, String name, String value) {
278
String prefix = rawPrefix + name + "=";
279
String arg = prefix + value;
280
281
options.setProperty(name, value);
282
283
int length = rawArguments.length;
284
boolean found = false;
285
for (int i = 0; i < length; i++) {
286
if (rawArguments[i].startsWith(prefix)) {
287
found = true;
288
rawArguments[i] = arg;
289
break;
290
}
291
}
292
293
if (!found) {
294
String[] newRawArguments = new String[length + 1];
295
System.arraycopy(rawArguments, 0, newRawArguments, 0, length);
296
newRawArguments[length] = arg;
297
rawArguments = newRawArguments;
298
}
299
}
300
301
/**
302
* Return current architecture name from ArgumentParser's
303
* options.
304
*
305
* <p>Note that null string is returning if test argument
306
* <code>-arch</code> has not been set.
307
*
308
* @see #setRawArguments(String[])
309
*/
310
public String getArch() {
311
return options.getProperty("arch");
312
}
313
314
/**
315
* Timeout (in minutes) for test's critical section like:
316
* (a) awaiting for an event, or conversely (b) making sure
317
* that there is no unexpected event.
318
*
319
* <p>By default, <i>2</i> minutes is returned if option
320
* <code>-waittime</code> is not set with command line.
321
*
322
* @see TimeoutHandler
323
*/
324
public int getWaitTime() {
325
String val = options.getProperty("waittime", "2");
326
int minutes;
327
try {
328
minutes = Integer.parseInt(val);
329
} catch (NumberFormatException e) {
330
throw new TestBug("Not integer value of \"waittime\" argument: " + val);
331
}
332
return minutes;
333
}
334
335
/**
336
* Return boolean value of current Log mode:
337
* <ul>
338
* <li><i>true</i> if Log mode is verbose.
339
* <li><i>false</i> otherwise.
340
*
341
* <p>Note that default Log mode is quiet if test argument
342
* <code>-verbose</code> has not been set.
343
*
344
* @see #setRawArguments(String[])
345
*/
346
public boolean verbose() {
347
return options.getProperty("verbose") != null;
348
}
349
350
/**
351
* Return boolean value of setting of timestamp for log messages:
352
* <ul>
353
* <li><i>true</i> if Log messages are timestamp'ed.
354
* <li><i>false</i> otherwise.
355
*
356
* <p>Note that by default Log messages won't be timestamp'ed until
357
* <code>-trace.time</code> has not been set.
358
*
359
* @see #setRawArguments(String[])
360
*/
361
public boolean isTimestamp() {
362
return options.getProperty("trace.time") != null;
363
}
364
365
/**
366
* Return level of printing tracing messages for debugging purpose.
367
* Level <i>0</i> means no tracing messages at all.
368
*
369
* <p>Note that by default no tracing messages will be printed out
370
* until <code>-trace.level</code> has not been set.
371
*
372
* @see #setRawArguments(String[])
373
*/
374
public int getTraceLevel() {
375
String value = options.getProperty("trace.level", Integer.toString(Log.TraceLevel.DEFAULT));
376
try {
377
return Integer.parseInt(value);
378
} catch (NumberFormatException e) {
379
throw new Failure("Not integer value of -trace.level option: " + value);
380
}
381
}
382
383
/**
384
* Parse arguments from rawArguments, extract recognized options,
385
* check legality of options values options and store non-option
386
* arguments.
387
*
388
* @throws NullPointerException If raw arguments were not set
389
* for this ArgumentParser instance.
390
* @throws BadOption If Option name is not accepted or
391
* option has illegal value.
392
* @see #setRawArguments(String[])
393
* @see #checkOption(String, String)
394
* @see #checkOptions()
395
*/
396
protected void parseArguments() {
397
String[] selected = new String[rawArguments.length];
398
Properties properties = new Properties();
399
int count = 0;
400
for (int i = 0; i < rawArguments.length; i++) {
401
String argument = rawArguments[i];
402
if (argument.startsWith("-")) {
403
int pos = argument.indexOf("=", 1);
404
String option, value;
405
if (pos < 0) {
406
option = argument.substring(1);
407
if (i + 1 < rawArguments.length && !rawArguments[i + 1].startsWith("-")) {
408
value = rawArguments[i + 1];
409
++i;
410
} else {
411
value = "";
412
}
413
} else {
414
option = argument.substring(1, pos);
415
value = argument.substring(pos + 1);
416
}
417
418
if (!checkOption(option, value)) {
419
throw new BadOption("Unrecognized command line option: " + argument);
420
}
421
properties.setProperty(option, value);
422
} else {
423
selected[count++] = rawArguments[i];
424
}
425
}
426
// Strip away the dummy tail of the selected[] array:
427
arguments = new String[count];
428
System.arraycopy(selected, 0, arguments, 0, count);
429
options = properties;
430
checkOptions();
431
}
432
433
public StressOptions getStressOptions() {
434
return new StressOptions(rawArguments);
435
}
436
437
/**
438
* Check if the specified option is allowed and has legal value.
439
* <p>
440
* Derived classes for handling test arguments in particular sub-suites
441
* override this method to allow to accept sub-suite specific options.
442
* However, they should invoke this method of the base class to ensure
443
* that the basic options will be accepted too.
444
*
445
* @return <i>true</i> if option is allowed and has legal value
446
* <i>false</i> if option is unknown
447
* @throws BadOption If value of the allowed option is illegal.
448
* @see #setRawArguments(String[])
449
* @see #parseArguments()
450
*/
451
protected boolean checkOption(String option, String value) {
452
// accept arguments of nsk.share.test.StressOptions
453
if (StressOptions.isValidStressOption(option))
454
return true;
455
456
// options with any string value
457
if (option.equals("arch")) {
458
return true;
459
}
460
461
// options with positive integer value
462
if (option.equals("waittime")
463
|| option.equals("trace.level")) {
464
try {
465
int number = Integer.parseInt(value);
466
if (number < 0) {
467
throw new BadOption(option + ": value must be a positive integer");
468
}
469
} catch (NumberFormatException e) {
470
throw new BadOption(option + ": value must be an integer");
471
}
472
return true;
473
}
474
475
// options without any value
476
if (option.equals("verbose")
477
|| option.equals("vbs")
478
|| option.equals("trace.time")) {
479
if (!(value == null || value.length() <= 0)) {
480
throw new BadOption(option + ": no value must be specified");
481
}
482
return true;
483
}
484
485
return false;
486
}
487
488
/**
489
* Check that the value of all options are not inconsistent.
490
* This method is invoked by <code>parseArguments()</code>
491
*
492
* @throws BadOption If value of the options are inconsistent
493
* @see #parseArguments()
494
*/
495
protected void checkOptions() {
496
// do nothing
497
}
498
499
/**
500
* Thrown if invalid option or option value is found.
501
*/
502
public static class BadOption extends IllegalArgumentException {
503
/**
504
* Explain the reason.
505
*
506
* @param message Printing message.
507
*/
508
public BadOption(String message) {
509
super(message);
510
}
511
}
512
}
513
514