src/share/classes/com/sun/tools/javadoc/Start.java

Thu, 15 Nov 2012 14:41:31 -0800

author
jjg
date
Thu, 15 Nov 2012 14:41:31 -0800
changeset 1411
467f4f754368
parent 1392
352d130c47c5
child 1413
bdcef2ef52d2
permissions
-rw-r--r--

8003257: refactor javadoc tool option handling
Reviewed-by: darcy

duke@1 1 /*
jjg@1357 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@554 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@554 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@554 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 22 * or visit www.oracle.com if you need additional information or have any
ohair@554 23 * questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javadoc;
duke@1 27
jjg@1357 28 import java.io.File;
jjg@1357 29 import java.io.FileNotFoundException;
jjg@1357 30 import java.io.IOException;
jjg@1357 31 import java.io.PrintWriter;
jjg@1357 32
duke@1 33 import com.sun.javadoc.*;
duke@1 34 import com.sun.tools.javac.main.CommandLine;
duke@1 35 import com.sun.tools.javac.util.Context;
duke@1 36 import com.sun.tools.javac.util.List;
duke@1 37 import com.sun.tools.javac.util.ListBuffer;
jjg@1135 38 import com.sun.tools.javac.util.Log;
duke@1 39 import com.sun.tools.javac.util.Options;
duke@1 40 import static com.sun.tools.javac.code.Flags.*;
duke@1 41
duke@1 42 /**
duke@1 43 * Main program of Javadoc.
duke@1 44 * Previously named "Main".
duke@1 45 *
jjg@1359 46 * <p><b>This is NOT part of any supported API.
jjg@1359 47 * If you write code that depends on this, you do so at your own risk.
jjg@1359 48 * This code and its internal interfaces are subject to change or
jjg@1359 49 * deletion without notice.</b>
jjg@1359 50 *
duke@1 51 * @since 1.2
duke@1 52 * @author Robert Field
duke@1 53 * @author Neal Gafter (rewrite)
duke@1 54 */
jjg@1411 55 public class Start extends ToolOption.Helper {
jjg@1392 56 /** Context for this invocation. */
jjg@1392 57 private final Context context;
duke@1 58
duke@1 59 private final String defaultDocletClassName;
jjg@129 60 private final ClassLoader docletParentClassLoader;
duke@1 61
duke@1 62 private static final String javadocName = "javadoc";
duke@1 63
duke@1 64 private static final String standardDocletClassName =
duke@1 65 "com.sun.tools.doclets.standard.Standard";
duke@1 66
duke@1 67 private long defaultFilter = PUBLIC | PROTECTED;
duke@1 68
jjg@1392 69 private final Messager messager;
duke@1 70
duke@1 71 private DocletInvoker docletInvoker;
duke@1 72
duke@1 73 Start(String programName,
duke@1 74 PrintWriter errWriter,
duke@1 75 PrintWriter warnWriter,
duke@1 76 PrintWriter noticeWriter,
duke@1 77 String defaultDocletClassName) {
jjg@129 78 this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);
jjg@129 79 }
jjg@129 80
jjg@129 81 Start(String programName,
jjg@129 82 PrintWriter errWriter,
jjg@129 83 PrintWriter warnWriter,
jjg@129 84 PrintWriter noticeWriter,
jjg@129 85 String defaultDocletClassName,
jjg@129 86 ClassLoader docletParentClassLoader) {
jjg@1392 87 context = new Context();
jjg@1392 88 messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
duke@1 89 this.defaultDocletClassName = defaultDocletClassName;
jjg@129 90 this.docletParentClassLoader = docletParentClassLoader;
duke@1 91 }
duke@1 92
duke@1 93 Start(String programName, String defaultDocletClassName) {
jjg@129 94 this(programName, defaultDocletClassName, null);
jjg@129 95 }
jjg@129 96
jjg@129 97 Start(String programName, String defaultDocletClassName,
jjg@129 98 ClassLoader docletParentClassLoader) {
jjg@1392 99 context = new Context();
jjg@1392 100 messager = new Messager(context, programName);
duke@1 101 this.defaultDocletClassName = defaultDocletClassName;
jjg@129 102 this.docletParentClassLoader = docletParentClassLoader;
jjg@129 103 }
jjg@129 104
jjg@129 105 Start(String programName, ClassLoader docletParentClassLoader) {
jjg@129 106 this(programName, standardDocletClassName, docletParentClassLoader);
duke@1 107 }
duke@1 108
duke@1 109 Start(String programName) {
duke@1 110 this(programName, standardDocletClassName);
duke@1 111 }
duke@1 112
jjg@129 113 Start(ClassLoader docletParentClassLoader) {
jjg@129 114 this(javadocName, docletParentClassLoader);
jjg@129 115 }
jjg@129 116
duke@1 117 Start() {
duke@1 118 this(javadocName);
duke@1 119 }
duke@1 120
jjg@1411 121 public Start(Context context) {
jjg@1411 122 context.getClass(); // null check
jjg@1411 123 this.context = context;
jjg@1411 124 defaultDocletClassName = standardDocletClassName;
jjg@1411 125 docletParentClassLoader = null;
jjg@1411 126
jjg@1411 127 Log log = context.get(Log.logKey);
jjg@1411 128 if (log instanceof Messager)
jjg@1411 129 messager = (Messager) log;
jjg@1411 130 else {
jjg@1411 131 PrintWriter out = context.get(Log.outKey);
jjg@1411 132 messager = (out == null) ? new Messager(context, javadocName)
jjg@1411 133 : new Messager(context, javadocName, out, out, out);
jjg@1411 134 }
jjg@1411 135 }
jjg@1411 136
duke@1 137 /**
duke@1 138 * Usage
duke@1 139 */
jjg@1411 140 @Override
jjg@1411 141 void usage() {
jjg@1411 142 usage(true);
jjg@1411 143 }
jjg@1411 144
jjg@1411 145
jjg@1411 146 /**
jjg@1411 147 * Usage
jjg@1411 148 */
jjg@1411 149 private void usage(boolean exit) {
jjg@1411 150 // RFE: it would be better to replace the following with code to
jjg@1411 151 // write a header, then help for each option, then a footer.
duke@1 152 messager.notice("main.usage");
duke@1 153
duke@1 154 // let doclet print usage information (does nothing on error)
duke@1 155 if (docletInvoker != null) {
duke@1 156 docletInvoker.optionLength("-help");
duke@1 157 }
jjg@1411 158
jjg@1411 159 if (exit) exit();
jjg@1411 160 }
jjg@1411 161
jjg@1411 162 @Override
jjg@1411 163 void Xusage() {
jjg@1411 164 Xusage(true);
duke@1 165 }
duke@1 166
duke@1 167 /**
jjg@584 168 * Usage
jjg@584 169 */
jjg@1411 170 private void Xusage(boolean exit) {
jjg@584 171 messager.notice("main.Xusage");
jjg@1411 172 if (exit) exit();
jjg@584 173 }
jjg@584 174
jjg@584 175 /**
duke@1 176 * Exit
duke@1 177 */
duke@1 178 private void exit() {
duke@1 179 messager.exit();
duke@1 180 }
duke@1 181
duke@1 182
duke@1 183 /**
duke@1 184 * Main program - external wrapper
duke@1 185 */
jjg@127 186 int begin(String... argv) {
duke@1 187 boolean failed = false;
duke@1 188
duke@1 189 try {
duke@1 190 failed = !parseAndExecute(argv);
jjg@1411 191 } catch (Messager.ExitJavadoc exc) {
duke@1 192 // ignore, we just exit this way
duke@1 193 } catch (OutOfMemoryError ee) {
jjg@1411 194 messager.error(Messager.NOPOS, "main.out.of.memory");
duke@1 195 failed = true;
duke@1 196 } catch (Error ee) {
jjg@1135 197 ee.printStackTrace(System.err);
jjg@1411 198 messager.error(Messager.NOPOS, "main.fatal.error");
duke@1 199 failed = true;
duke@1 200 } catch (Exception ee) {
jjg@1135 201 ee.printStackTrace(System.err);
jjg@1411 202 messager.error(Messager.NOPOS, "main.fatal.exception");
duke@1 203 failed = true;
duke@1 204 } finally {
duke@1 205 messager.exitNotice();
duke@1 206 messager.flush();
duke@1 207 }
duke@1 208 failed |= messager.nerrors() > 0;
duke@1 209 failed |= rejectWarnings && messager.nwarnings() > 0;
duke@1 210 return failed ? 1 : 0;
duke@1 211 }
duke@1 212
duke@1 213 /**
duke@1 214 * Main program - internal
duke@1 215 */
jjg@127 216 private boolean parseAndExecute(String... argv) throws IOException {
duke@1 217 long tm = System.currentTimeMillis();
duke@1 218
duke@1 219 ListBuffer<String> javaNames = new ListBuffer<String>();
duke@1 220
duke@1 221 // Preprocess @file arguments
duke@1 222 try {
duke@1 223 argv = CommandLine.parse(argv);
duke@1 224 } catch (FileNotFoundException e) {
jjg@1411 225 messager.error(Messager.NOPOS, "main.cant.read", e.getMessage());
duke@1 226 exit();
duke@1 227 } catch (IOException e) {
jjg@1135 228 e.printStackTrace(System.err);
duke@1 229 exit();
duke@1 230 }
duke@1 231
duke@1 232 setDocletInvoker(argv);
jjg@584 233
jjg@1411 234 compOpts = Options.instance(context);
duke@1 235
duke@1 236 // Parse arguments
duke@1 237 for (int i = 0 ; i < argv.length ; i++) {
duke@1 238 String arg = argv[i];
jjg@1411 239
jjg@1411 240 ToolOption o = ToolOption.get(arg);
jjg@1411 241 if (o != null) {
jjg@1411 242 // hack: this restriction should be removed
jjg@1411 243 if (o == ToolOption.LOCALE && i > 0)
jjg@1411 244 usageError("main.locale_first");
jjg@1411 245
jjg@1411 246 if (o.hasArg) {
jjg@1411 247 oneArg(argv, i++);
jjg@1411 248 o.process(this, argv[i]);
jjg@1411 249 } else {
jjg@1411 250 setOption(arg);
jjg@1411 251 o.process(this);
duke@1 252 }
jjg@1411 253
duke@1 254 } else if (arg.startsWith("-XD")) {
jjg@1411 255 // hidden javac options
duke@1 256 String s = arg.substring("-XD".length());
duke@1 257 int eq = s.indexOf('=');
duke@1 258 String key = (eq < 0) ? s : s.substring(0, eq);
duke@1 259 String value = (eq < 0) ? s : s.substring(eq+1);
duke@1 260 compOpts.put(key, value);
duke@1 261 }
duke@1 262 // call doclet for its options
duke@1 263 // other arg starts with - is invalid
jjg@1411 264 else if (arg.startsWith("-")) {
duke@1 265 int optionLength;
duke@1 266 optionLength = docletInvoker.optionLength(arg);
duke@1 267 if (optionLength < 0) {
duke@1 268 // error already displayed
duke@1 269 exit();
duke@1 270 } else if (optionLength == 0) {
duke@1 271 // option not found
duke@1 272 usageError("main.invalid_flag", arg);
duke@1 273 } else {
duke@1 274 // doclet added option
duke@1 275 if ((i + optionLength) > argv.length) {
duke@1 276 usageError("main.requires_argument", arg);
duke@1 277 }
duke@1 278 ListBuffer<String> args = new ListBuffer<String>();
duke@1 279 for (int j = 0; j < optionLength-1; ++j) {
duke@1 280 args.append(argv[++i]);
duke@1 281 }
duke@1 282 setOption(arg, args.toList());
duke@1 283 }
duke@1 284 } else {
duke@1 285 javaNames.append(arg);
duke@1 286 }
duke@1 287 }
jjg@1392 288 compOpts.notifyListeners();
duke@1 289
duke@1 290 if (javaNames.isEmpty() && subPackages.isEmpty()) {
duke@1 291 usageError("main.No_packages_or_classes_specified");
duke@1 292 }
duke@1 293
duke@1 294 if (!docletInvoker.validOptions(options.toList())) {
duke@1 295 // error message already displayed
duke@1 296 exit();
duke@1 297 }
duke@1 298
duke@1 299 JavadocTool comp = JavadocTool.make0(context);
duke@1 300 if (comp == null) return false;
duke@1 301
duke@1 302 if (showAccess == null) {
duke@1 303 setFilter(defaultFilter);
duke@1 304 }
duke@1 305
duke@1 306 LanguageVersion languageVersion = docletInvoker.languageVersion();
duke@1 307 RootDocImpl root = comp.getRootDocImpl(
jjg@1411 308 docLocale,
jjg@1411 309 encoding,
jjg@1411 310 showAccess,
jjg@1411 311 javaNames.toList(),
jjg@1411 312 options.toList(),
jjg@1411 313 breakiterator,
jjg@1411 314 subPackages.toList(),
jjg@1411 315 excludedPackages.toList(),
duke@1 316 docClasses,
duke@1 317 // legacy?
jjg@1411 318 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1,
jjg@1411 319 quiet);
duke@1 320
jjg@1391 321 // release resources
jjg@1391 322 comp = null;
jjg@1391 323
duke@1 324 // pass off control to the doclet
duke@1 325 boolean ok = root != null;
duke@1 326 if (ok) ok = docletInvoker.start(root);
duke@1 327
duke@1 328 // We're done.
duke@1 329 if (compOpts.get("-verbose") != null) {
duke@1 330 tm = System.currentTimeMillis() - tm;
duke@1 331 messager.notice("main.done_in", Long.toString(tm));
duke@1 332 }
duke@1 333
duke@1 334 return ok;
duke@1 335 }
duke@1 336
duke@1 337 private void setDocletInvoker(String[] argv) {
duke@1 338 String docletClassName = null;
duke@1 339 String docletPath = null;
duke@1 340
duke@1 341 // Parse doclet specifying arguments
duke@1 342 for (int i = 0 ; i < argv.length ; i++) {
duke@1 343 String arg = argv[i];
duke@1 344 if (arg.equals("-doclet")) {
duke@1 345 oneArg(argv, i++);
duke@1 346 if (docletClassName != null) {
duke@1 347 usageError("main.more_than_one_doclet_specified_0_and_1",
duke@1 348 docletClassName, argv[i]);
duke@1 349 }
duke@1 350 docletClassName = argv[i];
duke@1 351 } else if (arg.equals("-docletpath")) {
duke@1 352 oneArg(argv, i++);
duke@1 353 if (docletPath == null) {
duke@1 354 docletPath = argv[i];
duke@1 355 } else {
duke@1 356 docletPath += File.pathSeparator + argv[i];
duke@1 357 }
duke@1 358 }
duke@1 359 }
duke@1 360
duke@1 361 if (docletClassName == null) {
duke@1 362 docletClassName = defaultDocletClassName;
duke@1 363 }
duke@1 364
duke@1 365 // attempt to find doclet
duke@1 366 docletInvoker = new DocletInvoker(messager,
jjg@129 367 docletClassName, docletPath,
jjg@129 368 docletParentClassLoader);
duke@1 369 }
duke@1 370
duke@1 371 /**
duke@1 372 * Set one arg option.
duke@1 373 * Error and exit if one argument is not provided.
duke@1 374 */
duke@1 375 private void oneArg(String[] args, int index) {
duke@1 376 if ((index + 1) < args.length) {
duke@1 377 setOption(args[index], args[index+1]);
duke@1 378 } else {
duke@1 379 usageError("main.requires_argument", args[index]);
duke@1 380 }
duke@1 381 }
duke@1 382
jjg@1411 383 @Override
jjg@1411 384 void usageError(String key, Object... args) {
jjg@1411 385 messager.error(Messager.NOPOS, key, args);
jjg@1411 386 usage(true);
duke@1 387 }
duke@1 388
duke@1 389 /**
duke@1 390 * indicate an option with no arguments was given.
duke@1 391 */
duke@1 392 private void setOption(String opt) {
duke@1 393 String[] option = { opt };
duke@1 394 options.append(option);
duke@1 395 }
duke@1 396
duke@1 397 /**
duke@1 398 * indicate an option with one argument was given.
duke@1 399 */
duke@1 400 private void setOption(String opt, String argument) {
duke@1 401 String[] option = { opt, argument };
duke@1 402 options.append(option);
duke@1 403 }
duke@1 404
duke@1 405 /**
duke@1 406 * indicate an option with the specified list of arguments was given.
duke@1 407 */
duke@1 408 private void setOption(String opt, List<String> arguments) {
duke@1 409 String[] args = new String[arguments.length() + 1];
duke@1 410 int k = 0;
duke@1 411 args[k++] = opt;
duke@1 412 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
duke@1 413 args[k++] = i.head;
duke@1 414 }
jjg@1411 415 options.append(args);
duke@1 416 }
duke@1 417 }

mercurial