001: /*
002: * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javadoc;
027:
028: import com.sun.javadoc.*;
029:
030: import com.sun.tools.javac.main.CommandLine;
031: import com.sun.tools.javac.main.JavaCompiler;
032: import com.sun.tools.javac.util.Context;
033: import com.sun.tools.javac.util.List;
034: import com.sun.tools.javac.util.ListBuffer;
035: import com.sun.tools.javac.util.Options;
036:
037: import com.sun.tools.javadoc.Messager;
038: import com.sun.tools.javadoc.DocletInvoker;
039: import com.sun.tools.javadoc.RootDocImpl;
040: import com.sun.tools.javadoc.ModifierFilter;
041:
042: import java.io.IOException;
043: import java.io.File;
044: import java.io.FileNotFoundException;
045: import java.io.PrintWriter;
046:
047: import java.util.StringTokenizer;
048:
049: import static com.sun.tools.javac.code.Flags.*;
050:
051: /**
052: * Main program of Javadoc.
053: * Previously named "Main".
054: *
055: * @since 1.2
056: * @author Robert Field
057: * @author Neal Gafter (rewrite)
058: */
059: class Start {
060: /** Context for this invocation. */
061: private final Context context;
062:
063: /**
064: * Name of the program
065: */
066: private final String defaultDocletClassName;
067:
068: private static final String javadocName = "javadoc";
069:
070: private static final String standardDocletClassName = "com.sun.tools.doclets.standard.Standard";
071:
072: private ListBuffer<String[]> options = new ListBuffer<String[]>();
073:
074: private ModifierFilter showAccess = null;
075:
076: private long defaultFilter = PUBLIC | PROTECTED;
077:
078: private Messager messager;
079:
080: String docLocale = "";
081:
082: boolean breakiterator = false;
083: boolean quiet = false;
084: String encoding = null;
085:
086: private DocletInvoker docletInvoker;
087:
088: private static final int F_VERBOSE = 1 << 0;
089: private static final int F_WARNINGS = 1 << 2;
090:
091: /* Treat warnings as errors. */
092: private boolean rejectWarnings = false;
093:
094: Start(String programName, PrintWriter errWriter,
095: PrintWriter warnWriter, PrintWriter noticeWriter,
096: String defaultDocletClassName) {
097: context = new Context();
098: messager = new Messager(context, programName, errWriter,
099: warnWriter, noticeWriter);
100: this .defaultDocletClassName = defaultDocletClassName;
101: }
102:
103: Start(String programName, String defaultDocletClassName) {
104: context = new Context();
105: messager = new Messager(context, programName);
106: this .defaultDocletClassName = defaultDocletClassName;
107: }
108:
109: Start(String programName) {
110: this (programName, standardDocletClassName);
111: }
112:
113: Start() {
114: this (javadocName);
115: }
116:
117: /**
118: * Usage
119: */
120: private void usage() {
121: messager.notice("main.usage");
122:
123: // let doclet print usage information (does nothing on error)
124: if (docletInvoker != null) {
125: docletInvoker.optionLength("-help");
126: }
127: }
128:
129: /**
130: * Exit
131: */
132: private void exit() {
133: messager.exit();
134: }
135:
136: /**
137: * Main program - external wrapper
138: */
139: int begin(String argv[]) {
140: boolean failed = false;
141:
142: try {
143: failed = !parseAndExecute(argv);
144: } catch (Messager.ExitJavadoc exc) {
145: // ignore, we just exit this way
146: } catch (OutOfMemoryError ee) {
147: messager.error(null, "main.out.of.memory");
148: failed = true;
149: } catch (Error ee) {
150: ee.printStackTrace();
151: messager.error(null, "main.fatal.error");
152: failed = true;
153: } catch (Exception ee) {
154: ee.printStackTrace();
155: messager.error(null, "main.fatal.exception");
156: failed = true;
157: } finally {
158: messager.exitNotice();
159: messager.flush();
160: }
161: failed |= messager.nerrors() > 0;
162: failed |= rejectWarnings && messager.nwarnings() > 0;
163: return failed ? 1 : 0;
164: }
165:
166: private void addToList(ListBuffer<String> list, String str) {
167: StringTokenizer st = new StringTokenizer(str, ":");
168: String current;
169: while (st.hasMoreTokens()) {
170: current = st.nextToken();
171: list.append(current);
172: }
173: }
174:
175: /**
176: * Main program - internal
177: */
178: private boolean parseAndExecute(String argv[]) throws IOException {
179: long tm = System.currentTimeMillis();
180:
181: ListBuffer<String> javaNames = new ListBuffer<String>();
182:
183: // Preprocess @file arguments
184: try {
185: argv = CommandLine.parse(argv);
186: } catch (FileNotFoundException e) {
187: messager.error(null, "main.cant.read", e.getMessage());
188: exit();
189: } catch (IOException e) {
190: e.printStackTrace();
191: exit();
192: }
193:
194: setDocletInvoker(argv);
195: ListBuffer<String> subPackages = new ListBuffer<String>();
196: ListBuffer<String> excludedPackages = new ListBuffer<String>();
197: Options compOpts = Options.instance(context);
198: boolean docClasses = false;
199:
200: // Parse arguments
201: for (int i = 0; i < argv.length; i++) {
202: String arg = argv[i];
203: if (arg.equals("-subpackages")) {
204: oneArg(argv, i++);
205: addToList(subPackages, argv[i]);
206: } else if (arg.equals("-exclude")) {
207: oneArg(argv, i++);
208: addToList(excludedPackages, argv[i]);
209: } else if (arg.equals("-verbose")) {
210: setOption(arg);
211: compOpts.put("-verbose", "");
212: } else if (arg.equals("-encoding")) {
213: oneArg(argv, i++);
214: encoding = argv[i];
215: compOpts.put("-encoding", argv[i]);
216: } else if (arg.equals("-breakiterator")) {
217: breakiterator = true;
218: setOption("-breakiterator");
219: } else if (arg.equals("-quiet")) {
220: quiet = true;
221: setOption("-quiet");
222: } else if (arg.equals("-help")) {
223: usage();
224: exit();
225: } else if (arg.equals("-Xclasses")) {
226: setOption(arg);
227: docClasses = true;
228: } else if (arg.equals("-Xwerror")) {
229: setOption(arg);
230: rejectWarnings = true;
231: } else if (arg.equals("-private")) {
232: setOption(arg);
233: setFilter(ModifierFilter.ALL_ACCESS);
234: } else if (arg.equals("-package")) {
235: setOption(arg);
236: setFilter(PUBLIC | PROTECTED | ModifierFilter.PACKAGE);
237: } else if (arg.equals("-protected")) {
238: setOption(arg);
239: setFilter(PUBLIC | PROTECTED);
240: } else if (arg.equals("-public")) {
241: setOption(arg);
242: setFilter(PUBLIC);
243: } else if (arg.equals("-source")) {
244: oneArg(argv, i++);
245: if (compOpts.get("-source") != null) {
246: usageError("main.option.already.seen", arg);
247: }
248: compOpts.put("-source", argv[i]);
249: } else if (arg.equals("-prompt")) {
250: compOpts.put("-prompt", "-prompt");
251: messager.promptOnError = true;
252: } else if (arg.equals("-sourcepath")) {
253: oneArg(argv, i++);
254: if (compOpts.get("-sourcepath") != null) {
255: usageError("main.option.already.seen", arg);
256: }
257: compOpts.put("-sourcepath", argv[i]);
258: } else if (arg.equals("-classpath")) {
259: oneArg(argv, i++);
260: if (compOpts.get("-classpath") != null) {
261: usageError("main.option.already.seen", arg);
262: }
263: compOpts.put("-classpath", argv[i]);
264: } else if (arg.equals("-sysclasspath")) {
265: oneArg(argv, i++);
266: if (compOpts.get("-bootclasspath") != null) {
267: usageError("main.option.already.seen", arg);
268: }
269: compOpts.put("-bootclasspath", argv[i]);
270: } else if (arg.equals("-bootclasspath")) {
271: oneArg(argv, i++);
272: if (compOpts.get("-bootclasspath") != null) {
273: usageError("main.option.already.seen", arg);
274: }
275: compOpts.put("-bootclasspath", argv[i]);
276: } else if (arg.equals("-extdirs")) {
277: oneArg(argv, i++);
278: if (compOpts.get("-extdirs") != null) {
279: usageError("main.option.already.seen", arg);
280: }
281: compOpts.put("-extdirs", argv[i]);
282: } else if (arg.equals("-overview")) {
283: oneArg(argv, i++);
284: } else if (arg.equals("-doclet")) {
285: i++; // handled in setDocletInvoker
286: } else if (arg.equals("-docletpath")) {
287: i++; // handled in setDocletInvoker
288: } else if (arg.equals("-locale")) {
289: if (i != 0)
290: usageError("main.locale_first");
291: oneArg(argv, i++);
292: docLocale = argv[i];
293: } else if (arg.startsWith("-XD")) {
294: String s = arg.substring("-XD".length());
295: int eq = s.indexOf('=');
296: String key = (eq < 0) ? s : s.substring(0, eq);
297: String value = (eq < 0) ? s : s.substring(eq + 1);
298: compOpts.put(key, value);
299: }
300: // call doclet for its options
301: // other arg starts with - is invalid
302: else if (arg.startsWith("-")) {
303: int optionLength;
304: optionLength = docletInvoker.optionLength(arg);
305: if (optionLength < 0) {
306: // error already displayed
307: exit();
308: } else if (optionLength == 0) {
309: // option not found
310: usageError("main.invalid_flag", arg);
311: } else {
312: // doclet added option
313: if ((i + optionLength) > argv.length) {
314: usageError("main.requires_argument", arg);
315: }
316: ListBuffer<String> args = new ListBuffer<String>();
317: for (int j = 0; j < optionLength - 1; ++j) {
318: args.append(argv[++i]);
319: }
320: setOption(arg, args.toList());
321: }
322: } else {
323: javaNames.append(arg);
324: }
325: }
326:
327: if (javaNames.isEmpty() && subPackages.isEmpty()) {
328: usageError("main.No_packages_or_classes_specified");
329: }
330:
331: if (!docletInvoker.validOptions(options.toList())) {
332: // error message already displayed
333: exit();
334: }
335:
336: JavadocTool comp = JavadocTool.make0(context);
337: if (comp == null)
338: return false;
339:
340: if (showAccess == null) {
341: setFilter(defaultFilter);
342: }
343:
344: LanguageVersion languageVersion = docletInvoker
345: .languageVersion();
346: RootDocImpl root = comp.getRootDocImpl(docLocale, encoding,
347: showAccess, javaNames.toList(), options.toList(),
348: breakiterator, subPackages.toList(), excludedPackages
349: .toList(), docClasses,
350: // legacy?
351: languageVersion == null
352: || languageVersion == LanguageVersion.JAVA_1_1,
353: quiet);
354:
355: // pass off control to the doclet
356: boolean ok = root != null;
357: if (ok)
358: ok = docletInvoker.start(root);
359:
360: // We're done.
361: if (compOpts.get("-verbose") != null) {
362: tm = System.currentTimeMillis() - tm;
363: messager.notice("main.done_in", Long.toString(tm));
364: }
365:
366: return ok;
367: }
368:
369: private void setDocletInvoker(String[] argv) {
370: String docletClassName = null;
371: String docletPath = null;
372:
373: // Parse doclet specifying arguments
374: for (int i = 0; i < argv.length; i++) {
375: String arg = argv[i];
376: if (arg.equals("-doclet")) {
377: oneArg(argv, i++);
378: if (docletClassName != null) {
379: usageError(
380: "main.more_than_one_doclet_specified_0_and_1",
381: docletClassName, argv[i]);
382: }
383: docletClassName = argv[i];
384: } else if (arg.equals("-docletpath")) {
385: oneArg(argv, i++);
386: if (docletPath == null) {
387: docletPath = argv[i];
388: } else {
389: docletPath += File.pathSeparator + argv[i];
390: }
391: }
392: }
393:
394: if (docletClassName == null) {
395: docletClassName = defaultDocletClassName;
396: }
397:
398: // attempt to find doclet
399: docletInvoker = new DocletInvoker(messager, docletClassName,
400: docletPath);
401: }
402:
403: private void setFilter(long filterBits) {
404: if (showAccess != null) {
405: messager.error(null, "main.incompatible.access.flags");
406: usage();
407: exit();
408: }
409: showAccess = new ModifierFilter(filterBits);
410: }
411:
412: /**
413: * Set one arg option.
414: * Error and exit if one argument is not provided.
415: */
416: private void oneArg(String[] args, int index) {
417: if ((index + 1) < args.length) {
418: setOption(args[index], args[index + 1]);
419: } else {
420: usageError("main.requires_argument", args[index]);
421: }
422: }
423:
424: private void usageError(String key) {
425: messager.error(null, key);
426: usage();
427: exit();
428: }
429:
430: private void usageError(String key, String a1) {
431: messager.error(null, key, a1);
432: usage();
433: exit();
434: }
435:
436: private void usageError(String key, String a1, String a2) {
437: messager.error(null, key, a1, a2);
438: usage();
439: exit();
440: }
441:
442: /**
443: * indicate an option with no arguments was given.
444: */
445: private void setOption(String opt) {
446: String[] option = { opt };
447: options.append(option);
448: }
449:
450: /**
451: * indicate an option with one argument was given.
452: */
453: private void setOption(String opt, String argument) {
454: String[] option = { opt, argument };
455: options.append(option);
456: }
457:
458: /**
459: * indicate an option with the specified list of arguments was given.
460: */
461: private void setOption(String opt, List<String> arguments) {
462: String[] args = new String[arguments.length() + 1];
463: int k = 0;
464: args[k++] = opt;
465: for (List<String> i = arguments; i.nonEmpty(); i = i.tail) {
466: args[k++] = i.head;
467: }
468: options = options.append(args);
469: }
470:
471: }
|