| /* |
| * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| package com.sun.tools.javadoc; |
| |
| import com.sun.javadoc.*; |
| |
| import com.sun.tools.javac.main.CommandLine; |
| import com.sun.tools.javac.util.Context; |
| import com.sun.tools.javac.util.List; |
| import com.sun.tools.javac.util.ListBuffer; |
| import com.sun.tools.javac.util.Options; |
| |
| import java.io.IOException; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.PrintWriter; |
| |
| import java.util.StringTokenizer; |
| |
| import static com.sun.tools.javac.code.Flags.*; |
| |
| /** |
| * Main program of Javadoc. |
| * Previously named "Main". |
| * |
| * @since 1.2 |
| * @author Robert Field |
| * @author Neal Gafter (rewrite) |
| */ |
| class Start { |
| /** Context for this invocation. */ |
| private final Context context; |
| |
| private final String defaultDocletClassName; |
| private final ClassLoader docletParentClassLoader; |
| |
| private static final String javadocName = "javadoc"; |
| |
| private static final String standardDocletClassName = |
| "com.sun.tools.doclets.standard.Standard"; |
| |
| private ListBuffer<String[]> options = new ListBuffer<String[]>(); |
| |
| private ModifierFilter showAccess = null; |
| |
| private long defaultFilter = PUBLIC | PROTECTED; |
| |
| private Messager messager; |
| |
| String docLocale = ""; |
| |
| boolean breakiterator = false; |
| boolean quiet = false; |
| String encoding = null; |
| |
| private DocletInvoker docletInvoker; |
| |
| private static final int F_VERBOSE = 1 << 0; |
| private static final int F_WARNINGS = 1 << 2; |
| |
| /* Treat warnings as errors. */ |
| private boolean rejectWarnings = false; |
| |
| Start(String programName, |
| PrintWriter errWriter, |
| PrintWriter warnWriter, |
| PrintWriter noticeWriter, |
| String defaultDocletClassName) { |
| this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null); |
| } |
| |
| Start(String programName, |
| PrintWriter errWriter, |
| PrintWriter warnWriter, |
| PrintWriter noticeWriter, |
| String defaultDocletClassName, |
| ClassLoader docletParentClassLoader) { |
| context = new Context(); |
| messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter); |
| this.defaultDocletClassName = defaultDocletClassName; |
| this.docletParentClassLoader = docletParentClassLoader; |
| } |
| |
| Start(String programName, String defaultDocletClassName) { |
| this(programName, defaultDocletClassName, null); |
| } |
| |
| Start(String programName, String defaultDocletClassName, |
| ClassLoader docletParentClassLoader) { |
| context = new Context(); |
| messager = new Messager(context, programName); |
| this.defaultDocletClassName = defaultDocletClassName; |
| this.docletParentClassLoader = docletParentClassLoader; |
| } |
| |
| Start(String programName, ClassLoader docletParentClassLoader) { |
| this(programName, standardDocletClassName, docletParentClassLoader); |
| } |
| |
| Start(String programName) { |
| this(programName, standardDocletClassName); |
| } |
| |
| Start(ClassLoader docletParentClassLoader) { |
| this(javadocName, docletParentClassLoader); |
| } |
| |
| Start() { |
| this(javadocName); |
| } |
| |
| /** |
| * Usage |
| */ |
| private void usage() { |
| messager.notice("main.usage"); |
| |
| // let doclet print usage information (does nothing on error) |
| if (docletInvoker != null) { |
| docletInvoker.optionLength("-help"); |
| } |
| } |
| |
| /** |
| * Exit |
| */ |
| private void exit() { |
| messager.exit(); |
| } |
| |
| |
| /** |
| * Main program - external wrapper |
| */ |
| int begin(String... argv) { |
| boolean failed = false; |
| |
| try { |
| failed = !parseAndExecute(argv); |
| } catch(Messager.ExitJavadoc exc) { |
| // ignore, we just exit this way |
| } catch (OutOfMemoryError ee) { |
| messager.error(null, "main.out.of.memory"); |
| failed = true; |
| } catch (Error ee) { |
| ee.printStackTrace(); |
| messager.error(null, "main.fatal.error"); |
| failed = true; |
| } catch (Exception ee) { |
| ee.printStackTrace(); |
| messager.error(null, "main.fatal.exception"); |
| failed = true; |
| } finally { |
| messager.exitNotice(); |
| messager.flush(); |
| } |
| failed |= messager.nerrors() > 0; |
| failed |= rejectWarnings && messager.nwarnings() > 0; |
| return failed ? 1 : 0; |
| } |
| |
| private void addToList(ListBuffer<String> list, String str){ |
| StringTokenizer st = new StringTokenizer(str, ":"); |
| String current; |
| while(st.hasMoreTokens()){ |
| current = st.nextToken(); |
| list.append(current); |
| } |
| } |
| |
| /** |
| * Main program - internal |
| */ |
| private boolean parseAndExecute(String... argv) throws IOException { |
| long tm = System.currentTimeMillis(); |
| |
| ListBuffer<String> javaNames = new ListBuffer<String>(); |
| |
| // Preprocess @file arguments |
| try { |
| argv = CommandLine.parse(argv); |
| } catch (FileNotFoundException e) { |
| messager.error(null, "main.cant.read", e.getMessage()); |
| exit(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| exit(); |
| } |
| |
| setDocletInvoker(argv); |
| ListBuffer<String> subPackages = new ListBuffer<String>(); |
| ListBuffer<String> excludedPackages = new ListBuffer<String>(); |
| Options compOpts = Options.instance(context); |
| boolean docClasses = false; |
| |
| // Parse arguments |
| for (int i = 0 ; i < argv.length ; i++) { |
| String arg = argv[i]; |
| if (arg.equals("-subpackages")) { |
| oneArg(argv, i++); |
| addToList(subPackages, argv[i]); |
| } else if (arg.equals("-exclude")){ |
| oneArg(argv, i++); |
| addToList(excludedPackages, argv[i]); |
| } else if (arg.equals("-verbose")) { |
| setOption(arg); |
| compOpts.put("-verbose", ""); |
| } else if (arg.equals("-encoding")) { |
| oneArg(argv, i++); |
| encoding = argv[i]; |
| compOpts.put("-encoding", argv[i]); |
| } else if (arg.equals("-breakiterator")) { |
| breakiterator = true; |
| setOption("-breakiterator"); |
| } else if (arg.equals("-quiet")) { |
| quiet = true; |
| setOption("-quiet"); |
| } else if (arg.equals("-help")) { |
| usage(); |
| exit(); |
| } else if (arg.equals("-Xclasses")) { |
| setOption(arg); |
| docClasses = true; |
| } else if (arg.equals("-Xwerror")) { |
| setOption(arg); |
| rejectWarnings = true; |
| } else if (arg.equals("-private")) { |
| setOption(arg); |
| setFilter(ModifierFilter.ALL_ACCESS); |
| } else if (arg.equals("-package")) { |
| setOption(arg); |
| setFilter(PUBLIC | PROTECTED | |
| ModifierFilter.PACKAGE ); |
| } else if (arg.equals("-protected")) { |
| setOption(arg); |
| setFilter(PUBLIC | PROTECTED ); |
| } else if (arg.equals("-public")) { |
| setOption(arg); |
| setFilter(PUBLIC); |
| } else if (arg.equals("-source")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-source") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-source", argv[i]); |
| } else if (arg.equals("-prompt")) { |
| compOpts.put("-prompt", "-prompt"); |
| messager.promptOnError = true; |
| } else if (arg.equals("-sourcepath")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-sourcepath") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-sourcepath", argv[i]); |
| } else if (arg.equals("-classpath")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-classpath") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-classpath", argv[i]); |
| } else if (arg.equals("-sysclasspath")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-bootclasspath") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-bootclasspath", argv[i]); |
| } else if (arg.equals("-bootclasspath")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-bootclasspath") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-bootclasspath", argv[i]); |
| } else if (arg.equals("-extdirs")) { |
| oneArg(argv, i++); |
| if (compOpts.get("-extdirs") != null) { |
| usageError("main.option.already.seen", arg); |
| } |
| compOpts.put("-extdirs", argv[i]); |
| } else if (arg.equals("-overview")) { |
| oneArg(argv, i++); |
| } else if (arg.equals("-doclet")) { |
| i++; // handled in setDocletInvoker |
| } else if (arg.equals("-docletpath")) { |
| i++; // handled in setDocletInvoker |
| } else if (arg.equals("-locale")) { |
| if (i != 0) |
| usageError("main.locale_first"); |
| oneArg(argv, i++); |
| docLocale = argv[i]; |
| } else if (arg.startsWith("-XD")) { |
| String s = arg.substring("-XD".length()); |
| int eq = s.indexOf('='); |
| String key = (eq < 0) ? s : s.substring(0, eq); |
| String value = (eq < 0) ? s : s.substring(eq+1); |
| compOpts.put(key, value); |
| } |
| // call doclet for its options |
| // other arg starts with - is invalid |
| else if ( arg.startsWith("-") ) { |
| int optionLength; |
| optionLength = docletInvoker.optionLength(arg); |
| if (optionLength < 0) { |
| // error already displayed |
| exit(); |
| } else if (optionLength == 0) { |
| // option not found |
| usageError("main.invalid_flag", arg); |
| } else { |
| // doclet added option |
| if ((i + optionLength) > argv.length) { |
| usageError("main.requires_argument", arg); |
| } |
| ListBuffer<String> args = new ListBuffer<String>(); |
| for (int j = 0; j < optionLength-1; ++j) { |
| args.append(argv[++i]); |
| } |
| setOption(arg, args.toList()); |
| } |
| } else { |
| javaNames.append(arg); |
| } |
| } |
| |
| if (javaNames.isEmpty() && subPackages.isEmpty()) { |
| usageError("main.No_packages_or_classes_specified"); |
| } |
| |
| if (!docletInvoker.validOptions(options.toList())) { |
| // error message already displayed |
| exit(); |
| } |
| |
| JavadocTool comp = JavadocTool.make0(context); |
| if (comp == null) return false; |
| |
| if (showAccess == null) { |
| setFilter(defaultFilter); |
| } |
| |
| LanguageVersion languageVersion = docletInvoker.languageVersion(); |
| RootDocImpl root = comp.getRootDocImpl( |
| docLocale, encoding, showAccess, |
| javaNames.toList(), options.toList(), breakiterator, |
| subPackages.toList(), excludedPackages.toList(), |
| docClasses, |
| // legacy? |
| languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet); |
| |
| // pass off control to the doclet |
| boolean ok = root != null; |
| if (ok) ok = docletInvoker.start(root); |
| |
| // We're done. |
| if (compOpts.get("-verbose") != null) { |
| tm = System.currentTimeMillis() - tm; |
| messager.notice("main.done_in", Long.toString(tm)); |
| } |
| |
| return ok; |
| } |
| |
| private void setDocletInvoker(String[] argv) { |
| String docletClassName = null; |
| String docletPath = null; |
| |
| // Parse doclet specifying arguments |
| for (int i = 0 ; i < argv.length ; i++) { |
| String arg = argv[i]; |
| if (arg.equals("-doclet")) { |
| oneArg(argv, i++); |
| if (docletClassName != null) { |
| usageError("main.more_than_one_doclet_specified_0_and_1", |
| docletClassName, argv[i]); |
| } |
| docletClassName = argv[i]; |
| } else if (arg.equals("-docletpath")) { |
| oneArg(argv, i++); |
| if (docletPath == null) { |
| docletPath = argv[i]; |
| } else { |
| docletPath += File.pathSeparator + argv[i]; |
| } |
| } |
| } |
| |
| if (docletClassName == null) { |
| docletClassName = defaultDocletClassName; |
| } |
| |
| // attempt to find doclet |
| docletInvoker = new DocletInvoker(messager, |
| docletClassName, docletPath, |
| docletParentClassLoader); |
| } |
| |
| private void setFilter(long filterBits) { |
| if (showAccess != null) { |
| messager.error(null, "main.incompatible.access.flags"); |
| usage(); |
| exit(); |
| } |
| showAccess = new ModifierFilter(filterBits); |
| } |
| |
| /** |
| * Set one arg option. |
| * Error and exit if one argument is not provided. |
| */ |
| private void oneArg(String[] args, int index) { |
| if ((index + 1) < args.length) { |
| setOption(args[index], args[index+1]); |
| } else { |
| usageError("main.requires_argument", args[index]); |
| } |
| } |
| |
| private void usageError(String key) { |
| messager.error(null, key); |
| usage(); |
| exit(); |
| } |
| |
| private void usageError(String key, String a1) { |
| messager.error(null, key, a1); |
| usage(); |
| exit(); |
| } |
| |
| private void usageError(String key, String a1, String a2) { |
| messager.error(null, key, a1, a2); |
| usage(); |
| exit(); |
| } |
| |
| /** |
| * indicate an option with no arguments was given. |
| */ |
| private void setOption(String opt) { |
| String[] option = { opt }; |
| options.append(option); |
| } |
| |
| /** |
| * indicate an option with one argument was given. |
| */ |
| private void setOption(String opt, String argument) { |
| String[] option = { opt, argument }; |
| options.append(option); |
| } |
| |
| /** |
| * indicate an option with the specified list of arguments was given. |
| */ |
| private void setOption(String opt, List<String> arguments) { |
| String[] args = new String[arguments.length() + 1]; |
| int k = 0; |
| args[k++] = opt; |
| for (List<String> i = arguments; i.nonEmpty(); i=i.tail) { |
| args[k++] = i.head; |
| } |
| options = options.append(args); |
| } |
| |
| } |