87 G_CUSTOM("-g:", "opt.g.lines.vars.source", |
98 G_CUSTOM("-g:", "opt.g.lines.vars.source", |
88 STANDARD, BASIC, ANYOF, "lines", "vars", "source"), |
99 STANDARD, BASIC, ANYOF, "lines", "vars", "source"), |
89 |
100 |
90 XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC), |
101 XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC), |
91 |
102 |
92 XLINT_CUSTOM("-Xlint:", EXTENDED, BASIC, ANYOF, getXLintChoices()) { |
103 XLINT_CUSTOM("-Xlint:", "opt.arg.Xlint", "opt.Xlint.custom", EXTENDED, BASIC, ANYOF, getXLintChoices()) { |
93 private static final String LINT_KEY_FORMAT = " %-19s %s"; |
104 private final String LINT_KEY_FORMAT = LARGE_INDENT + " %-" + |
94 @Override |
105 (DEFAULT_SYNOPSIS_WIDTH + SMALL_INDENT.length() - LARGE_INDENT.length() - 2) + "s %s"; |
95 void help(Log log, OptionKind kind) { |
106 @Override |
96 if (this.kind != kind) |
107 protected void help(Log log) { |
97 return; |
108 super.help(log); |
98 |
|
99 log.printRawLines(WriterKind.STDOUT, |
|
100 String.format(HELP_LINE_FORMAT, |
|
101 log.localize(PrefixKind.JAVAC, "opt.Xlint.subopts"), |
|
102 log.localize(PrefixKind.JAVAC, "opt.Xlint.suboptlist"))); |
|
103 log.printRawLines(WriterKind.STDOUT, |
109 log.printRawLines(WriterKind.STDOUT, |
104 String.format(LINT_KEY_FORMAT, |
110 String.format(LINT_KEY_FORMAT, |
105 "all", |
111 "all", |
106 log.localize(PrefixKind.JAVAC, "opt.Xlint.all"))); |
112 log.localize(PrefixKind.JAVAC, "opt.Xlint.all"))); |
107 for (LintCategory lc : LintCategory.values()) { |
113 for (LintCategory lc : LintCategory.values()) { |
123 |
129 |
124 XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) { |
130 XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) { |
125 @Override |
131 @Override |
126 public boolean matches(String option) { |
132 public boolean matches(String option) { |
127 return DocLint.isValidOption( |
133 return DocLint.isValidOption( |
128 option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX)); |
134 option.replace(XDOCLINT_CUSTOM.primaryName, DocLint.XMSGS_CUSTOM_PREFIX)); |
129 } |
135 } |
130 |
136 |
131 @Override |
137 @Override |
132 public boolean process(OptionHelper helper, String option) { |
138 public boolean process(OptionHelper helper, String option) { |
133 String prev = helper.get(XDOCLINT_CUSTOM); |
139 String prev = helper.get(XDOCLINT_CUSTOM); |
134 String next = (prev == null) ? option : (prev + " " + option); |
140 String next = (prev == null) ? option : (prev + " " + option); |
135 helper.put(XDOCLINT_CUSTOM.text, next); |
141 helper.put(XDOCLINT_CUSTOM.primaryName, next); |
136 return false; |
142 return false; |
137 } |
143 } |
138 }, |
144 }, |
139 |
145 |
140 XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) { |
146 XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) { |
141 @Override |
147 @Override |
142 public boolean matches(String option) { |
148 public boolean matches(String option) { |
143 return DocLint.isValidOption( |
149 return DocLint.isValidOption( |
144 option.replace(XDOCLINT_PACKAGE.text, DocLint.XCHECK_PACKAGE)); |
150 option.replace(XDOCLINT_PACKAGE.primaryName, DocLint.XCHECK_PACKAGE)); |
145 } |
151 } |
146 |
152 |
147 @Override |
153 @Override |
148 public boolean process(OptionHelper helper, String option) { |
154 public boolean process(OptionHelper helper, String option) { |
149 String prev = helper.get(XDOCLINT_PACKAGE); |
155 String prev = helper.get(XDOCLINT_PACKAGE); |
150 String next = (prev == null) ? option : (prev + " " + option); |
156 String next = (prev == null) ? option : (prev + " " + option); |
151 helper.put(XDOCLINT_PACKAGE.text, next); |
157 helper.put(XDOCLINT_PACKAGE.primaryName, next); |
152 return false; |
158 return false; |
153 } |
159 } |
154 }, |
160 }, |
155 |
161 |
156 // -nowarn is retained for command-line backward compatibility |
162 // -nowarn is retained for command-line backward compatibility |
171 helper.put("-Xlint:deprecation", option); |
177 helper.put("-Xlint:deprecation", option); |
172 return false; |
178 return false; |
173 } |
179 } |
174 }, |
180 }, |
175 |
181 |
176 CLASSPATH("-classpath", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER), |
182 CLASS_PATH("--class-path -classpath -cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER), |
177 |
183 |
178 CP("-cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER) { |
184 SOURCE_PATH("--source-path -sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER), |
|
185 |
|
186 MODULE_SOURCE_PATH("--module-source-path -modulesourcepath", "opt.arg.mspath", "opt.modulesourcepath", STANDARD, FILEMANAGER), |
|
187 |
|
188 MODULE_PATH("--module-path -p -modulepath -mp", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER), |
|
189 |
|
190 UPGRADE_MODULE_PATH("--upgrade-module-path -upgrademodulepath", "opt.arg.path", "opt.upgrademodulepath", STANDARD, FILEMANAGER), |
|
191 |
|
192 SYSTEM("--system -system", "opt.arg.jdk", "opt.system", STANDARD, FILEMANAGER), |
|
193 |
|
194 PATCH_MODULE("--patch-module -Xpatch:", "opt.arg.patch", "opt.patch", EXTENDED, FILEMANAGER) { |
|
195 // The deferred filemanager diagnostics mechanism assumes a single value per option, |
|
196 // but --patch-module can be used multiple times, once per module. Therefore we compose |
|
197 // a value for the option containing the last value specified for each module, and separate |
|
198 // the the module=path pairs by an invalid path character, NULL. |
|
199 // The standard file manager code knows to split apart the NULL-separated components. |
179 @Override |
200 @Override |
180 public boolean process(OptionHelper helper, String option, String arg) { |
201 public boolean process(OptionHelper helper, String option, String arg) { |
181 return super.process(helper, "-classpath", arg); |
202 if (!arg.contains("=")) { // could be more strict regeex, e.g. "(?i)[a-z0-9_.]+=.*" |
182 } |
203 helper.error(Errors.LocnInvalidArgForXpatch(arg)); |
183 }, |
204 } |
184 |
205 |
185 SOURCEPATH("-sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER), |
206 String previous = helper.get(this); |
186 |
207 if (previous == null) { |
187 MODULESOURCEPATH("-modulesourcepath", "opt.arg.mspath", "opt.modulesourcepath", STANDARD, FILEMANAGER), |
208 return super.process(helper, option, arg); |
188 |
209 } |
189 MODULEPATH("-modulepath", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER), |
210 |
190 |
211 Map<String,String> map = new LinkedHashMap<>(); |
191 MP("-mp", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER) { |
212 for (String s : previous.split("\0")) { |
192 @Override |
213 int sep = s.indexOf('='); |
193 public boolean process(OptionHelper helper, String option, String arg) { |
214 map.put(s.substring(0, sep), s.substring(sep + 1)); |
194 return super.process(helper, "-modulepath", arg); |
215 } |
195 } |
216 |
196 }, |
217 int sep = arg.indexOf('='); |
197 |
218 map.put(arg.substring(0, sep), arg.substring(sep + 1)); |
198 UPGRADEMODULEPATH("-upgrademodulepath", "opt.arg.path", "opt.upgrademodulepath", STANDARD, FILEMANAGER), |
219 |
199 |
220 StringBuilder sb = new StringBuilder(); |
200 SYSTEM("-system", "opt.arg.jdk", "opt.system", STANDARD, FILEMANAGER), |
221 map.forEach((m, p) -> { |
201 |
222 if (sb.length() > 0) |
202 XPATCH("-Xpatch:", "opt.arg.patch", "opt.patch", EXTENDED, FILEMANAGER), |
223 sb.append('\0'); |
203 |
224 sb.append(m).append('=').append(p); |
204 BOOTCLASSPATH("-bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) { |
225 }); |
|
226 return super.process(helper, option, sb.toString()); |
|
227 } |
|
228 }, |
|
229 |
|
230 BOOT_CLASS_PATH("--boot-class-path -bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) { |
205 @Override |
231 @Override |
206 public boolean process(OptionHelper helper, String option, String arg) { |
232 public boolean process(OptionHelper helper, String option, String arg) { |
207 helper.remove("-Xbootclasspath/p:"); |
233 helper.remove("-Xbootclasspath/p:"); |
208 helper.remove("-Xbootclasspath/a:"); |
234 helper.remove("-Xbootclasspath/a:"); |
209 return super.process(helper, option, arg); |
235 return super.process(helper, option, arg); |
226 EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER), |
252 EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER), |
227 |
253 |
228 DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) { |
254 DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) { |
229 @Override |
255 @Override |
230 public boolean process(OptionHelper helper, String option, String arg) { |
256 public boolean process(OptionHelper helper, String option, String arg) { |
231 return super.process(helper, "-extdirs", arg); |
257 return EXTDIRS.process(helper, "-extdirs", arg); |
232 } |
258 } |
233 }, |
259 }, |
234 |
260 |
235 ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER), |
261 ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER), |
236 |
262 |
237 DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) { |
263 DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) { |
238 @Override |
264 @Override |
239 public boolean process(OptionHelper helper, String option, String arg) { |
265 public boolean process(OptionHelper helper, String option, String arg) { |
240 return super.process(helper, "-endorseddirs", arg); |
266 return ENDORSEDDIRS.process(helper, "-endorseddirs", arg); |
241 } |
267 } |
242 }, |
268 }, |
243 |
269 |
244 PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC, ONEOF, "none", "only"), |
270 PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC, ONEOF, "none", "only"), |
245 |
271 |
246 PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC), |
272 PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC), |
247 |
273 |
248 PROCESSORPATH("-processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER), |
274 PROCESSOR_PATH("--processor-path -processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER), |
249 |
275 |
250 PROCESSORMODULEPATH("-processormodulepath", "opt.arg.path", "opt.processormodulepath", STANDARD, FILEMANAGER), |
276 PROCESSOR_MODULE_PATH("--processor-module-path -processormodulepath", "opt.arg.path", "opt.processormodulepath", STANDARD, FILEMANAGER), |
251 |
277 |
252 PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC), |
278 PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC), |
253 |
279 |
254 D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER), |
280 D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER), |
255 |
281 |
344 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "fullVersion", ownName, JavaCompiler.fullVersion()); |
364 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "fullVersion", ownName, JavaCompiler.fullVersion()); |
345 return super.process(helper, option); |
365 return super.process(helper, option); |
346 } |
366 } |
347 }, |
367 }, |
348 |
368 |
349 HELP("-help", "opt.help", STANDARD, INFO) { |
369 // Note: -h is already taken for "native header output directory". |
|
370 HELP("--help -help", "opt.help", STANDARD, INFO) { |
350 @Override |
371 @Override |
351 public boolean process(OptionHelper helper, String option) { |
372 public boolean process(OptionHelper helper, String option) { |
352 Log log = helper.getLog(); |
373 Log log = helper.getLog(); |
353 String ownName = helper.getOwnName(); |
374 String ownName = helper.getOwnName(); |
354 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.header", ownName); |
375 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.header", ownName); |
355 for (Option o: getJavaCompilerOptions()) { |
376 showHelp(log, OptionKind.STANDARD); |
356 o.help(log, OptionKind.STANDARD); |
|
357 } |
|
358 log.printNewline(WriterKind.STDOUT); |
377 log.printNewline(WriterKind.STDOUT); |
359 return super.process(helper, option); |
378 return super.process(helper, option); |
360 } |
379 } |
361 }, |
380 }, |
362 |
381 |
363 A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, true) { |
382 A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, ArgKind.ADJACENT) { |
364 @Override |
383 @Override |
365 public boolean matches(String arg) { |
384 public boolean matches(String arg) { |
366 return arg.startsWith("-A"); |
385 return arg.startsWith("-A"); |
367 } |
386 } |
368 |
387 |
383 String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) ); |
402 String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) ); |
384 if (!JavacProcessingEnvironment.isValidOptionName(key)) { |
403 if (!JavacProcessingEnvironment.isValidOptionName(key)) { |
385 helper.error("err.invalid.A.key", option); |
404 helper.error("err.invalid.A.key", option); |
386 return true; |
405 return true; |
387 } |
406 } |
388 return process(helper, option, option); |
407 helper.put(option, option); |
|
408 return false; |
389 } |
409 } |
390 }, |
410 }, |
391 |
411 |
392 X("-X", "opt.X", STANDARD, INFO) { |
412 X("-X", "opt.X", STANDARD, INFO) { |
393 @Override |
413 @Override |
394 public boolean process(OptionHelper helper, String option) { |
414 public boolean process(OptionHelper helper, String option) { |
395 Log log = helper.getLog(); |
415 Log log = helper.getLog(); |
396 for (Option o: getJavaCompilerOptions()) { |
416 showHelp(log, OptionKind.EXTENDED); |
397 o.help(log, OptionKind.EXTENDED); |
|
398 } |
|
399 log.printNewline(WriterKind.STDOUT); |
417 log.printNewline(WriterKind.STDOUT); |
400 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.nonstandard.footer"); |
418 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.nonstandard.footer"); |
401 return super.process(helper, option); |
419 return super.process(helper, option); |
402 } |
420 } |
403 }, |
421 }, |
404 |
422 |
405 // This option exists only for the purpose of documenting itself. |
423 // This option exists only for the purpose of documenting itself. |
406 // It's actually implemented by the launcher. |
424 // It's actually implemented by the launcher. |
407 J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, true) { |
425 J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, ArgKind.ADJACENT) { |
408 @Override |
426 @Override |
409 public boolean process(OptionHelper helper, String option) { |
427 public boolean process(OptionHelper helper, String option) { |
410 throw new AssertionError |
428 throw new AssertionError |
411 ("the -J flag should be caught by the launcher."); |
429 ("the -J flag should be caught by the launcher."); |
412 } |
430 } |
546 helper.put(key, value); |
564 helper.put(key, value); |
547 return false; |
565 return false; |
548 } |
566 } |
549 }, |
567 }, |
550 |
568 |
551 XADDEXPORTS("-XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) { |
569 ADD_EXPORTS("--add-exports -XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) { |
552 @Override |
570 @Override |
553 public boolean process(OptionHelper helper, String option) { |
571 public boolean process(OptionHelper helper, String option, String arg) { |
554 String p = option.substring(option.indexOf(':') + 1).trim(); |
572 String prev = helper.get(ADD_EXPORTS); |
555 String prev = helper.get(XADDEXPORTS); |
573 helper.put(ADD_EXPORTS.primaryName, (prev == null) ? arg : prev + '\0' + arg); |
556 helper.put(XADDEXPORTS.text, (prev == null) ? p : prev + '\0' + p); |
574 return false; |
557 return false; |
575 } |
558 } |
576 }, |
559 }, |
577 |
560 |
578 ADD_READS("--add-reads -XaddReads:", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) { |
561 XADDREADS("-XaddReads:", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) { |
579 @Override |
562 @Override |
580 public boolean process(OptionHelper helper, String option, String arg) { |
563 public boolean process(OptionHelper helper, String option) { |
581 String prev = helper.get(ADD_READS); |
564 String p = option.substring(option.indexOf(':') + 1).trim(); |
582 helper.put(ADD_READS.primaryName, (prev == null) ? arg : prev + '\0' + arg); |
565 String prev = helper.get(XADDREADS); |
|
566 helper.put(XADDREADS.text, (prev == null) ? p : prev + '\0' + p); |
|
567 return false; |
583 return false; |
568 } |
584 } |
569 }, |
585 }, |
570 |
586 |
571 XMODULE("-Xmodule:", "opt.arg.module", "opt.module", EXTENDED, BASIC) { |
587 XMODULE("-Xmodule:", "opt.arg.module", "opt.module", EXTENDED, BASIC) { |
572 @Override |
588 @Override |
573 public boolean process(OptionHelper helper, String option) { |
589 public boolean process(OptionHelper helper, String option, String arg) { |
574 String prev = helper.get(XMODULE); |
590 String prev = helper.get(XMODULE); |
575 if (prev != null) { |
591 if (prev != null) { |
576 helper.error("err.option.too.many", XMODULE.text); |
592 helper.error("err.option.too.many", XMODULE.primaryName); |
577 } |
593 } |
578 String p = option.substring(option.indexOf(':') + 1); |
594 helper.put(XMODULE.primaryName, arg); |
579 helper.put(XMODULE.text, p); |
595 return false; |
580 return false; |
596 } |
581 } |
597 }, |
582 }, |
598 |
583 |
599 MODULE("--module -m", "opt.arg.m", "opt.m", STANDARD, BASIC), |
584 M("-m", "opt.arg.m", "opt.m", STANDARD, BASIC), |
600 |
585 |
601 ADD_MODULES("--add-modules -addmods", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC), |
586 ADDMODS("-addmods", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC), |
602 |
587 LIMITMODS("-limitmods", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC), |
603 LIMIT_MODULES("--limit-modules -limitmods", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC), |
588 |
604 |
589 // This option exists only for the purpose of documenting itself. |
605 // This option exists only for the purpose of documenting itself. |
590 // It's actually implemented by the CommandLine class. |
606 // It's actually implemented by the CommandLine class. |
591 AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, true) { |
607 AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, ArgKind.ADJACENT) { |
592 @Override |
608 @Override |
593 public boolean process(OptionHelper helper, String option) { |
609 public boolean process(OptionHelper helper, String option) { |
594 throw new AssertionError("the @ flag should be caught by CommandLine."); |
610 throw new AssertionError("the @ flag should be caught by CommandLine."); |
595 } |
611 } |
596 }, |
612 }, |
627 } |
643 } |
628 return false; |
644 return false; |
629 } |
645 } |
630 }, |
646 }, |
631 |
647 |
632 MULTIRELEASE("-multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER); |
648 MULTIRELEASE("--multi-release -multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER), |
633 |
649 |
634 /** The kind of an Option. This is used by the -help and -X options. */ |
650 INHERIT_RUNTIME_ENVIRONMENT("--inherit-runtime-environment", "opt.inherit_runtime_environment", |
|
651 EXTENDED, BASIC) { |
|
652 @Override |
|
653 public boolean process(OptionHelper helper, String option) { |
|
654 try { |
|
655 Class.forName(JDK9Wrappers.VMHelper.VM_CLASSNAME); |
|
656 String[] runtimeArgs = JDK9Wrappers.VMHelper.getRuntimeArguments(); |
|
657 for (String arg : runtimeArgs) { |
|
658 // Handle any supported runtime options; ignore all others. |
|
659 // The runtime arguments always use the single token form, e.g. "--name=value". |
|
660 for (Option o : getSupportedRuntimeOptions()) { |
|
661 if (o.matches(arg)) { |
|
662 o.handleOption(helper, arg, Collections.emptyIterator()); |
|
663 break; |
|
664 } |
|
665 } |
|
666 } |
|
667 } catch (ClassNotFoundException | SecurityException e) { |
|
668 helper.error("err.cannot.access.runtime.env"); |
|
669 } |
|
670 return false; |
|
671 } |
|
672 |
|
673 private Option[] getSupportedRuntimeOptions() { |
|
674 Option[] supportedRuntimeOptions = { |
|
675 ADD_EXPORTS, |
|
676 ADD_MODULES, |
|
677 LIMIT_MODULES, |
|
678 MODULE_PATH, |
|
679 UPGRADE_MODULE_PATH, |
|
680 PATCH_MODULE |
|
681 }; |
|
682 return supportedRuntimeOptions; |
|
683 } |
|
684 }; |
|
685 |
|
686 /** |
|
687 * The kind of argument, if any, accepted by this option. The kind is augmented |
|
688 * by characters in the name of the option. |
|
689 */ |
|
690 public enum ArgKind { |
|
691 /** This option does not take any argument. */ |
|
692 NONE, |
|
693 |
|
694 // Not currently supported |
|
695 // /** |
|
696 // * This option takes an optional argument, which may be provided directly after an '=' |
|
697 // * separator, or in the following argument position if that word does not itself appear |
|
698 // * to be the name of an option. |
|
699 // */ |
|
700 // OPTIONAL, |
|
701 |
|
702 /** |
|
703 * This option takes an argument. |
|
704 * If the name of option ends with ':' or '=', the argument must be provided directly |
|
705 * after that separator. |
|
706 * Otherwise, if may appear after an '=' or in the following argument position. |
|
707 */ |
|
708 REQUIRED, |
|
709 |
|
710 /** |
|
711 * This option takes an argument immediately after the option name, with no separator |
|
712 * character. |
|
713 */ |
|
714 ADJACENT |
|
715 } |
|
716 |
|
717 /** |
|
718 * The kind of an Option. This is used by the -help and -X options. |
|
719 */ |
635 public enum OptionKind { |
720 public enum OptionKind { |
636 /** A standard option, documented by -help. */ |
721 /** A standard option, documented by -help. */ |
637 STANDARD, |
722 STANDARD, |
638 /** An extended option, documented by -X. */ |
723 /** An extended option, documented by -X. */ |
639 EXTENDED, |
724 EXTENDED, |
640 /** A hidden option, not documented. */ |
725 /** A hidden option, not documented. */ |
641 HIDDEN, |
726 HIDDEN, |
642 } |
727 } |
643 |
728 |
644 /** The group for an Option. This determines the situations in which the |
729 /** |
645 * option is applicable. */ |
730 * The group for an Option. This determines the situations in which the |
|
731 * option is applicable. |
|
732 */ |
646 enum OptionGroup { |
733 enum OptionGroup { |
647 /** A basic option, available for use on the command line or via the |
734 /** A basic option, available for use on the command line or via the |
648 * Compiler API. */ |
735 * Compiler API. */ |
649 BASIC, |
736 BASIC, |
650 /** An option for javac's standard JavaFileManager. Other file managers |
737 /** An option for javac's standard JavaFileManager. Other file managers |
682 } |
771 } |
683 return false; |
772 return false; |
684 } |
773 } |
685 } |
774 } |
686 |
775 |
687 public final String text; |
776 /** |
688 |
777 * The "primary name" for this option. |
689 final OptionKind kind; |
778 * This is the name that is used to put values in the {@link Options} table. |
690 |
779 */ |
691 final OptionGroup group; |
780 public final String primaryName; |
692 |
781 |
693 /** Documentation key for arguments. |
782 /** |
694 */ |
783 * The set of names (primary name and aliases) for this option. |
695 final String argsNameKey; |
784 * Note that some names may end in a separator, to indicate that an argument must immediately |
|
785 * follow the separator (and cannot appear in the following argument position. |
|
786 */ |
|
787 public final String[] names; |
|
788 |
|
789 /** Documentation key for arguments. */ |
|
790 protected final String argsNameKey; |
696 |
791 |
697 /** Documentation key for description. |
792 /** Documentation key for description. |
698 */ |
793 */ |
699 final String descrKey; |
794 protected final String descrKey; |
700 |
795 |
701 /** Suffix option (-foo=bar or -foo:bar) |
796 /** The kind of this option. */ |
702 */ |
797 private final OptionKind kind; |
703 final boolean hasSuffix; |
798 |
704 |
799 /** The group for this option. */ |
705 /** The kind of choices for this option, if any. |
800 private final OptionGroup group; |
706 */ |
801 |
707 final ChoiceKind choiceKind; |
802 /** The kind of argument for this option. */ |
708 |
803 private final ArgKind argKind; |
709 /** The choices for this option, if any, and whether or not the choices |
804 |
710 * are hidden |
805 /** The kind of choices for this option, if any. */ |
711 */ |
806 private final ChoiceKind choiceKind; |
712 final Map<String,Boolean> choices; |
807 |
713 |
808 /** The choices for this option, if any, and whether or not the choices are hidden. */ |
|
809 private final Map<String,Boolean> choices; |
|
810 |
|
811 /** |
|
812 * Looks up the first option matching the given argument in the full set of options. |
|
813 * @param arg the argument to be matches |
|
814 * @return the first option that matches, or null if none. |
|
815 */ |
|
816 public static Option lookup(String arg) { |
|
817 return lookup(arg, EnumSet.allOf(Option.class)); |
|
818 } |
|
819 |
|
820 /** |
|
821 * Looks up the first option matching the given argument within a set of options. |
|
822 * @param arg the argument to be matches |
|
823 * @return the first option that matches, or null if none. |
|
824 */ |
|
825 public static Option lookup(String arg, Set<Option> options) { |
|
826 for (Option option: options) { |
|
827 if (option.matches(arg)) |
|
828 return option; |
|
829 } |
|
830 return null; |
|
831 } |
|
832 |
|
833 /** |
|
834 * Writes the "command line help" for given kind of option to the log. |
|
835 * @param log the log |
|
836 * @param kind the kind of options to select |
|
837 */ |
|
838 private static void showHelp(Log log, OptionKind kind) { |
|
839 Comparator<Option> comp = new Comparator<Option>() { |
|
840 final Collator collator = Collator.getInstance(Locale.US); |
|
841 { collator.setStrength(Collator.PRIMARY); } |
|
842 |
|
843 @Override |
|
844 public int compare(Option o1, Option o2) { |
|
845 return collator.compare(o1.primaryName, o2.primaryName); |
|
846 } |
|
847 }; |
|
848 |
|
849 getJavaCompilerOptions() |
|
850 .stream() |
|
851 .filter(o -> o.kind == kind) |
|
852 .sorted(comp) |
|
853 .forEach(o -> { |
|
854 o.help(log); |
|
855 }); |
|
856 } |
714 |
857 |
715 Option(String text, String descrKey, |
858 Option(String text, String descrKey, |
716 OptionKind kind, OptionGroup group) { |
859 OptionKind kind, OptionGroup group) { |
717 this(text, null, descrKey, kind, group, null, null, false); |
860 this(text, null, descrKey, kind, group, null, null, ArgKind.NONE); |
718 } |
|
719 |
|
720 Option(String text, String descrKey, |
|
721 OptionKind kind, OptionGroup group, |
|
722 boolean doHasSuffix) { |
|
723 this(text, null, descrKey, kind, group, null, null, doHasSuffix); |
|
724 } |
861 } |
725 |
862 |
726 Option(String text, String argsNameKey, String descrKey, |
863 Option(String text, String argsNameKey, String descrKey, |
727 OptionKind kind, OptionGroup group) { |
864 OptionKind kind, OptionGroup group) { |
728 this(text, argsNameKey, descrKey, kind, group, null, null, false); |
865 this(text, argsNameKey, descrKey, kind, group, null, null, ArgKind.REQUIRED); |
729 } |
866 } |
730 |
867 |
731 Option(String text, String argsNameKey, String descrKey, |
868 Option(String text, String argsNameKey, String descrKey, |
732 OptionKind kind, OptionGroup group, boolean doHasSuffix) { |
869 OptionKind kind, OptionGroup group, ArgKind ak) { |
733 this(text, argsNameKey, descrKey, kind, group, null, null, doHasSuffix); |
870 this(text, argsNameKey, descrKey, kind, group, null, null, ak); |
734 } |
871 } |
735 |
872 |
736 Option(String text, OptionKind kind, OptionGroup group, |
873 Option(String text, String argsNameKey, String descrKey, OptionKind kind, OptionGroup group, |
737 ChoiceKind choiceKind, Map<String,Boolean> choices) { |
874 ChoiceKind choiceKind, Map<String,Boolean> choices) { |
738 this(text, null, null, kind, group, choiceKind, choices, false); |
875 this(text, argsNameKey, descrKey, kind, group, choiceKind, choices, ArgKind.REQUIRED); |
739 } |
876 } |
740 |
877 |
741 Option(String text, String descrKey, |
878 Option(String text, String descrKey, |
742 OptionKind kind, OptionGroup group, |
879 OptionKind kind, OptionGroup group, |
743 ChoiceKind choiceKind, String... choices) { |
880 ChoiceKind choiceKind, String... choices) { |
744 this(text, null, descrKey, kind, group, choiceKind, |
881 this(text, null, descrKey, kind, group, choiceKind, |
745 createChoices(choices), false); |
882 createChoices(choices), ArgKind.REQUIRED); |
746 } |
883 } |
747 // where |
884 // where |
748 private static Map<String,Boolean> createChoices(String... choices) { |
885 private static Map<String,Boolean> createChoices(String... choices) { |
749 Map<String,Boolean> map = new LinkedHashMap<>(); |
886 Map<String,Boolean> map = new LinkedHashMap<>(); |
750 for (String c: choices) |
887 for (String c: choices) |
753 } |
890 } |
754 |
891 |
755 private Option(String text, String argsNameKey, String descrKey, |
892 private Option(String text, String argsNameKey, String descrKey, |
756 OptionKind kind, OptionGroup group, |
893 OptionKind kind, OptionGroup group, |
757 ChoiceKind choiceKind, Map<String,Boolean> choices, |
894 ChoiceKind choiceKind, Map<String,Boolean> choices, |
758 boolean doHasSuffix) { |
895 ArgKind argKind) { |
759 this.text = text; |
896 this.names = text.trim().split("\\s+"); |
|
897 Assert.check(names.length >= 1); |
|
898 this.primaryName = names[0]; |
760 this.argsNameKey = argsNameKey; |
899 this.argsNameKey = argsNameKey; |
761 this.descrKey = descrKey; |
900 this.descrKey = descrKey; |
762 this.kind = kind; |
901 this.kind = kind; |
763 this.group = group; |
902 this.group = group; |
764 this.choiceKind = choiceKind; |
903 this.choiceKind = choiceKind; |
765 this.choices = choices; |
904 this.choices = choices; |
766 char lastChar = text.charAt(text.length()-1); |
905 this.argKind = argKind; |
767 this.hasSuffix = doHasSuffix || lastChar == ':' || lastChar == '='; |
906 } |
768 } |
907 |
769 |
908 public String getPrimaryName() { |
770 public String getText() { |
909 return primaryName; |
771 return text; |
|
772 } |
910 } |
773 |
911 |
774 public OptionKind getKind() { |
912 public OptionKind getKind() { |
775 return kind; |
913 return kind; |
776 } |
914 } |
777 |
915 |
|
916 public ArgKind getArgKind() { |
|
917 return argKind; |
|
918 } |
|
919 |
778 public boolean hasArg() { |
920 public boolean hasArg() { |
779 return argsNameKey != null && !hasSuffix; |
921 return (argKind != ArgKind.NONE); |
780 } |
922 } |
781 |
923 |
782 public boolean matches(String option) { |
924 public boolean matches(String option) { |
|
925 for (String name: names) { |
|
926 if (matches(option, name)) |
|
927 return true; |
|
928 } |
|
929 return false; |
|
930 } |
|
931 |
|
932 private boolean matches(String option, String name) { |
|
933 if (name.startsWith("--")) { |
|
934 return option.equals(name) |
|
935 || hasArg() && option.startsWith(name + "="); |
|
936 } |
|
937 |
|
938 boolean hasSuffix = (argKind == ArgKind.ADJACENT) |
|
939 || name.endsWith(":") || name.endsWith("="); |
|
940 |
783 if (!hasSuffix) |
941 if (!hasSuffix) |
784 return option.equals(text); |
942 return option.equals(name); |
785 |
943 |
786 if (!option.startsWith(text)) |
944 if (!option.startsWith(name)) |
787 return false; |
945 return false; |
788 |
946 |
789 if (choices != null) { |
947 if (choices != null) { |
790 String arg = option.substring(text.length()); |
948 String arg = option.substring(name.length()); |
791 if (choiceKind == ChoiceKind.ONEOF) |
949 if (choiceKind == ChoiceKind.ONEOF) |
792 return choices.keySet().contains(arg); |
950 return choices.keySet().contains(arg); |
793 else { |
951 else { |
794 for (String a: arg.split(",+")) { |
952 for (String a: arg.split(",+")) { |
795 if (!choices.keySet().contains(a)) |
953 if (!choices.keySet().contains(a)) |
799 } |
957 } |
800 |
958 |
801 return true; |
959 return true; |
802 } |
960 } |
803 |
961 |
|
962 /** |
|
963 * Handles an option. |
|
964 * If an argument for the option is required, depending on spec of the option, it will be found |
|
965 * as part of the current arg (following ':' or '=') or in the following argument. |
|
966 * This is the recommended way to handle an option directly, instead of calling the underlying |
|
967 * {@link #process process} methods. |
|
968 * @param helper a helper to provide access to the environment |
|
969 * @param arg the arg string that identified this option |
|
970 * @param rest the remaining strings to be analysed |
|
971 * @return true if the operation was successful, and false otherwise |
|
972 * @implNote The return value is the opposite of that used by {@link #process}. |
|
973 */ |
|
974 public boolean handleOption(OptionHelper helper, String arg, Iterator<String> rest) { |
|
975 if (hasArg()) { |
|
976 String operand; |
|
977 int sep = findSeparator(arg); |
|
978 if (getArgKind() == Option.ArgKind.ADJACENT) { |
|
979 operand = arg.substring(primaryName.length()); |
|
980 } else if (sep > 0) { |
|
981 operand = arg.substring(sep + 1); |
|
982 } else { |
|
983 if (!rest.hasNext()) { |
|
984 helper.error("err.req.arg", arg); |
|
985 return false; |
|
986 } |
|
987 operand = rest.next(); |
|
988 } |
|
989 return !process(helper, arg, operand); |
|
990 } else { |
|
991 return !process(helper, arg); |
|
992 } |
|
993 } |
|
994 |
|
995 /** |
|
996 * Processes an option that either does not need an argument, |
|
997 * or which contains an argument within it, following a separator. |
|
998 * @param helper a helper to provide access to the environment |
|
999 * @param option the option to be processed |
|
1000 * @return true if an error occurred |
|
1001 */ |
|
1002 public boolean process(OptionHelper helper, String option) { |
|
1003 if (argKind == ArgKind.NONE) { |
|
1004 return process(helper, primaryName, option); |
|
1005 } else { |
|
1006 int sep = findSeparator(option); |
|
1007 return process(helper, primaryName, option.substring(sep + 1)); |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 /** |
|
1012 * Processes an option by updating the environment via a helper object. |
|
1013 * @param helper a helper to provide access to the environment |
|
1014 * @param option the option to be processed |
|
1015 * @param arg the value to associate with the option, or a default value |
|
1016 * to be used if the option does not otherwise take an argument. |
|
1017 * @return true if an error occurred |
|
1018 */ |
804 public boolean process(OptionHelper helper, String option, String arg) { |
1019 public boolean process(OptionHelper helper, String option, String arg) { |
805 if (choices != null) { |
1020 if (choices != null) { |
806 if (choiceKind == ChoiceKind.ONEOF) { |
1021 if (choiceKind == ChoiceKind.ONEOF) { |
807 // some clients like to see just one of option+choice set |
1022 // some clients like to see just one of option+choice set |
808 for (String s: choices.keySet()) |
1023 for (String s: choices.keySet()) |
809 helper.remove(option + s); |
1024 helper.remove(primaryName + s); |
810 String opt = option + arg; |
1025 String opt = primaryName + arg; |
811 helper.put(opt, opt); |
1026 helper.put(opt, opt); |
812 // some clients like to see option (without trailing ":") |
1027 // some clients like to see option (without trailing ":") |
813 // set to arg |
1028 // set to arg |
814 String nm = option.substring(0, option.length() - 1); |
1029 String nm = primaryName.substring(0, primaryName.length() - 1); |
815 helper.put(nm, arg); |
1030 helper.put(nm, arg); |
816 } else { |
1031 } else { |
817 // set option+word for each word in arg |
1032 // set option+word for each word in arg |
818 for (String a: arg.split(",+")) { |
1033 for (String a: arg.split(",+")) { |
819 String opt = option + a; |
1034 String opt = primaryName + a; |
820 helper.put(opt, opt); |
1035 helper.put(opt, opt); |
821 } |
1036 } |
822 } |
1037 } |
823 } |
1038 } |
824 helper.put(option, arg); |
1039 helper.put(primaryName, arg); |
825 if (group == OptionGroup.FILEMANAGER) |
1040 if (group == OptionGroup.FILEMANAGER) |
826 helper.handleFileManagerOption(this, arg); |
1041 helper.handleFileManagerOption(this, arg); |
827 return false; |
1042 return false; |
828 } |
1043 } |
829 |
1044 |
830 public boolean process(OptionHelper helper, String option) { |
1045 /** |
831 if (hasSuffix) |
1046 * Scans a word to find the first separator character, either colon or equals. |
832 return process(helper, text, option.substring(text.length())); |
1047 * @param word the word to be scanned |
833 else |
1048 * @return the position of the first':' or '=' character in the word, |
834 return process(helper, option, option); |
1049 * or -1 if none found |
835 } |
1050 */ |
836 |
1051 private static int findSeparator(String word) { |
837 private static final String HELP_LINE_FORMAT = " %-26s %s"; |
1052 for (int i = 0; i < word.length(); i++) { |
838 |
1053 switch (word.charAt(i)) { |
839 void help(Log log, OptionKind kind) { |
1054 case ':': case '=': |
840 if (this.kind != kind) |
1055 return i; |
|
1056 } |
|
1057 } |
|
1058 return -1; |
|
1059 } |
|
1060 |
|
1061 /** The indent for the option synopsis. */ |
|
1062 private static final String SMALL_INDENT = " "; |
|
1063 /** The automatic indent for the description. */ |
|
1064 private static final String LARGE_INDENT = " "; |
|
1065 /** The space allowed for the synopsis, if the description is to be shown on the same line. */ |
|
1066 private static final int DEFAULT_SYNOPSIS_WIDTH = 28; |
|
1067 /** The nominal maximum line length, when seeing if text will fit on a line. */ |
|
1068 private static final int DEFAULT_MAX_LINE_LENGTH = 80; |
|
1069 /** The format for a single-line help entry. */ |
|
1070 private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s"; |
|
1071 |
|
1072 /** |
|
1073 * Writes help text for this option to the log. |
|
1074 * @param log the log |
|
1075 */ |
|
1076 protected void help(Log log) { |
|
1077 help(log, log.localize(PrefixKind.JAVAC, descrKey)); |
|
1078 } |
|
1079 |
|
1080 protected void help(Log log, String descr) { |
|
1081 String synopses = Arrays.stream(names) |
|
1082 .map(s -> helpSynopsis(s, log)) |
|
1083 .collect(Collectors.joining(", ")); |
|
1084 |
|
1085 // If option synopses and description fit on a single line of reasonable length, |
|
1086 // display using COMPACT_FORMAT |
|
1087 if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH |
|
1088 && !descr.contains("\n") |
|
1089 && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + descr.length() <= DEFAULT_MAX_LINE_LENGTH)) { |
|
1090 log.printRawLines(WriterKind.STDOUT, String.format(COMPACT_FORMAT, synopses, descr)); |
841 return; |
1091 return; |
842 |
1092 } |
843 log.printRawLines(WriterKind.STDOUT, |
1093 |
844 String.format(HELP_LINE_FORMAT, |
1094 // If option synopses fit on a single line of reasonable length, show that; |
845 helpSynopsis(log), |
1095 // otherwise, show 1 per line |
846 log.localize(PrefixKind.JAVAC, descrKey))); |
1096 if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) { |
847 |
1097 log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + synopses); |
848 } |
1098 } else { |
849 |
1099 for (String name: names) { |
850 private String helpSynopsis(Log log) { |
1100 log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + helpSynopsis(name, log)); |
|
1101 } |
|
1102 } |
|
1103 |
|
1104 // Finally, show the description |
|
1105 log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT)); |
|
1106 } |
|
1107 |
|
1108 /** |
|
1109 * Composes the initial synopsis of one of the forms for this option. |
|
1110 * @param name the name of this form of the option |
|
1111 * @param log the log used to localize the description of the arguments |
|
1112 * @return the synopsis |
|
1113 */ |
|
1114 private String helpSynopsis(String name, Log log) { |
851 StringBuilder sb = new StringBuilder(); |
1115 StringBuilder sb = new StringBuilder(); |
852 sb.append(text); |
1116 sb.append(name); |
853 if (argsNameKey == null) { |
1117 if (argsNameKey == null) { |
854 if (choices != null) { |
1118 if (choices != null) { |
855 String sep = "{"; |
1119 String sep = "{"; |
856 for (Map.Entry<String,Boolean> e: choices.entrySet()) { |
1120 for (Map.Entry<String,Boolean> e: choices.entrySet()) { |
857 if (!e.getValue()) { |
1121 if (!e.getValue()) { |
913 choices.put("-" + c.option, c.hidden); |
1176 choices.put("-" + c.option, c.hidden); |
914 choices.put("none", false); |
1177 choices.put("none", false); |
915 return choices; |
1178 return choices; |
916 } |
1179 } |
917 |
1180 |
|
1181 /** |
|
1182 * Returns the set of options supported by the command line tool. |
|
1183 * @return the set of options. |
|
1184 */ |
918 static Set<Option> getJavaCompilerOptions() { |
1185 static Set<Option> getJavaCompilerOptions() { |
919 return EnumSet.allOf(Option.class); |
1186 return EnumSet.allOf(Option.class); |
920 } |
1187 } |
921 |
1188 |
|
1189 /** |
|
1190 * Returns the set of options supported by the built-in file manager. |
|
1191 * @return the set of options. |
|
1192 */ |
922 public static Set<Option> getJavacFileManagerOptions() { |
1193 public static Set<Option> getJavacFileManagerOptions() { |
923 return getOptions(EnumSet.of(FILEMANAGER)); |
1194 return getOptions(FILEMANAGER); |
924 } |
1195 } |
925 |
1196 |
|
1197 /** |
|
1198 * Returns the set of options supported by this implementation of |
|
1199 * the JavaCompiler API, via {@link JavaCompiler#getTask}. |
|
1200 * @return the set of options. |
|
1201 */ |
926 public static Set<Option> getJavacToolOptions() { |
1202 public static Set<Option> getJavacToolOptions() { |
927 return getOptions(EnumSet.of(BASIC)); |
1203 return getOptions(BASIC); |
928 } |
1204 } |
929 |
1205 |
930 static Set<Option> getOptions(Set<OptionGroup> desired) { |
1206 private static Set<Option> getOptions(OptionGroup group) { |
931 Set<Option> options = EnumSet.noneOf(Option.class); |
1207 return Arrays.stream(Option.values()) |
932 for (Option option : Option.values()) |
1208 .filter(o -> o.group == group) |
933 if (desired.contains(option.group)) |
1209 .collect(Collectors.toCollection(() -> EnumSet.noneOf(Option.class))); |
934 options.add(option); |
|
935 return Collections.unmodifiableSet(options); |
|
936 } |
1210 } |
937 |
1211 |
938 } |
1212 } |