Sat, 01 Dec 2007 00:00:00 +0000
Initial load
1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javadoc;
28 import com.sun.javadoc.*;
30 import com.sun.tools.javac.main.CommandLine;
31 import com.sun.tools.javac.main.JavaCompiler;
32 import com.sun.tools.javac.util.Context;
33 import com.sun.tools.javac.util.List;
34 import com.sun.tools.javac.util.ListBuffer;
35 import com.sun.tools.javac.util.Options;
37 import com.sun.tools.javadoc.Messager;
38 import com.sun.tools.javadoc.DocletInvoker;
39 import com.sun.tools.javadoc.RootDocImpl;
40 import com.sun.tools.javadoc.ModifierFilter;
42 import java.io.IOException;
43 import java.io.File;
44 import java.io.FileNotFoundException;
45 import java.io.PrintWriter;
47 import java.util.StringTokenizer;
49 import static com.sun.tools.javac.code.Flags.*;
51 /**
52 * Main program of Javadoc.
53 * Previously named "Main".
54 *
55 * @since 1.2
56 * @author Robert Field
57 * @author Neal Gafter (rewrite)
58 */
59 class Start {
60 /** Context for this invocation. */
61 private final Context context;
63 /**
64 * Name of the program
65 */
66 private final String defaultDocletClassName;
68 private static final String javadocName = "javadoc";
70 private static final String standardDocletClassName =
71 "com.sun.tools.doclets.standard.Standard";
73 private ListBuffer<String[]> options = new ListBuffer<String[]>();
75 private ModifierFilter showAccess = null;
77 private long defaultFilter = PUBLIC | PROTECTED;
79 private Messager messager;
81 String docLocale = "";
83 boolean breakiterator = false;
84 boolean quiet = false;
85 String encoding = null;
87 private DocletInvoker docletInvoker;
89 private static final int F_VERBOSE = 1 << 0;
90 private static final int F_WARNINGS = 1 << 2;
92 /* Treat warnings as errors. */
93 private boolean rejectWarnings = false;
95 Start(String programName,
96 PrintWriter errWriter,
97 PrintWriter warnWriter,
98 PrintWriter noticeWriter,
99 String defaultDocletClassName) {
100 context = new Context();
101 messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
102 this.defaultDocletClassName = defaultDocletClassName;
103 }
105 Start(String programName, String defaultDocletClassName) {
106 context = new Context();
107 messager = new Messager(context, programName);
108 this.defaultDocletClassName = defaultDocletClassName;
109 }
111 Start(String programName) {
112 this(programName, standardDocletClassName);
113 }
115 Start() {
116 this(javadocName);
117 }
119 /**
120 * Usage
121 */
122 private void usage() {
123 messager.notice("main.usage");
125 // let doclet print usage information (does nothing on error)
126 if (docletInvoker != null) {
127 docletInvoker.optionLength("-help");
128 }
129 }
131 /**
132 * Exit
133 */
134 private void exit() {
135 messager.exit();
136 }
139 /**
140 * Main program - external wrapper
141 */
142 int begin(String argv[]) {
143 boolean failed = false;
145 try {
146 failed = !parseAndExecute(argv);
147 } catch(Messager.ExitJavadoc exc) {
148 // ignore, we just exit this way
149 } catch (OutOfMemoryError ee) {
150 messager.error(null, "main.out.of.memory");
151 failed = true;
152 } catch (Error ee) {
153 ee.printStackTrace();
154 messager.error(null, "main.fatal.error");
155 failed = true;
156 } catch (Exception ee) {
157 ee.printStackTrace();
158 messager.error(null, "main.fatal.exception");
159 failed = true;
160 } finally {
161 messager.exitNotice();
162 messager.flush();
163 }
164 failed |= messager.nerrors() > 0;
165 failed |= rejectWarnings && messager.nwarnings() > 0;
166 return failed ? 1 : 0;
167 }
169 private void addToList(ListBuffer<String> list, String str){
170 StringTokenizer st = new StringTokenizer(str, ":");
171 String current;
172 while(st.hasMoreTokens()){
173 current = st.nextToken();
174 list.append(current);
175 }
176 }
178 /**
179 * Main program - internal
180 */
181 private boolean parseAndExecute(String argv[]) throws IOException {
182 long tm = System.currentTimeMillis();
184 ListBuffer<String> javaNames = new ListBuffer<String>();
186 // Preprocess @file arguments
187 try {
188 argv = CommandLine.parse(argv);
189 } catch (FileNotFoundException e) {
190 messager.error(null, "main.cant.read", e.getMessage());
191 exit();
192 } catch (IOException e) {
193 e.printStackTrace();
194 exit();
195 }
197 setDocletInvoker(argv);
198 ListBuffer<String> subPackages = new ListBuffer<String>();
199 ListBuffer<String> excludedPackages = new ListBuffer<String>();
200 Options compOpts = Options.instance(context);
201 boolean docClasses = false;
203 // Parse arguments
204 for (int i = 0 ; i < argv.length ; i++) {
205 String arg = argv[i];
206 if (arg.equals("-subpackages")) {
207 oneArg(argv, i++);
208 addToList(subPackages, argv[i]);
209 } else if (arg.equals("-exclude")){
210 oneArg(argv, i++);
211 addToList(excludedPackages, argv[i]);
212 } else if (arg.equals("-verbose")) {
213 setOption(arg);
214 compOpts.put("-verbose", "");
215 } else if (arg.equals("-encoding")) {
216 oneArg(argv, i++);
217 encoding = argv[i];
218 compOpts.put("-encoding", argv[i]);
219 } else if (arg.equals("-breakiterator")) {
220 breakiterator = true;
221 setOption("-breakiterator");
222 } else if (arg.equals("-quiet")) {
223 quiet = true;
224 setOption("-quiet");
225 } else if (arg.equals("-help")) {
226 usage();
227 exit();
228 } else if (arg.equals("-Xclasses")) {
229 setOption(arg);
230 docClasses = true;
231 } else if (arg.equals("-Xwerror")) {
232 setOption(arg);
233 rejectWarnings = true;
234 } else if (arg.equals("-private")) {
235 setOption(arg);
236 setFilter(ModifierFilter.ALL_ACCESS);
237 } else if (arg.equals("-package")) {
238 setOption(arg);
239 setFilter(PUBLIC | PROTECTED |
240 ModifierFilter.PACKAGE );
241 } else if (arg.equals("-protected")) {
242 setOption(arg);
243 setFilter(PUBLIC | PROTECTED );
244 } else if (arg.equals("-public")) {
245 setOption(arg);
246 setFilter(PUBLIC);
247 } else if (arg.equals("-source")) {
248 oneArg(argv, i++);
249 if (compOpts.get("-source") != null) {
250 usageError("main.option.already.seen", arg);
251 }
252 compOpts.put("-source", argv[i]);
253 } else if (arg.equals("-prompt")) {
254 compOpts.put("-prompt", "-prompt");
255 messager.promptOnError = true;
256 } else if (arg.equals("-sourcepath")) {
257 oneArg(argv, i++);
258 if (compOpts.get("-sourcepath") != null) {
259 usageError("main.option.already.seen", arg);
260 }
261 compOpts.put("-sourcepath", argv[i]);
262 } else if (arg.equals("-classpath")) {
263 oneArg(argv, i++);
264 if (compOpts.get("-classpath") != null) {
265 usageError("main.option.already.seen", arg);
266 }
267 compOpts.put("-classpath", argv[i]);
268 } else if (arg.equals("-sysclasspath")) {
269 oneArg(argv, i++);
270 if (compOpts.get("-bootclasspath") != null) {
271 usageError("main.option.already.seen", arg);
272 }
273 compOpts.put("-bootclasspath", argv[i]);
274 } else if (arg.equals("-bootclasspath")) {
275 oneArg(argv, i++);
276 if (compOpts.get("-bootclasspath") != null) {
277 usageError("main.option.already.seen", arg);
278 }
279 compOpts.put("-bootclasspath", argv[i]);
280 } else if (arg.equals("-extdirs")) {
281 oneArg(argv, i++);
282 if (compOpts.get("-extdirs") != null) {
283 usageError("main.option.already.seen", arg);
284 }
285 compOpts.put("-extdirs", argv[i]);
286 } else if (arg.equals("-overview")) {
287 oneArg(argv, i++);
288 } else if (arg.equals("-doclet")) {
289 i++; // handled in setDocletInvoker
290 } else if (arg.equals("-docletpath")) {
291 i++; // handled in setDocletInvoker
292 } else if (arg.equals("-locale")) {
293 if (i != 0)
294 usageError("main.locale_first");
295 oneArg(argv, i++);
296 docLocale = argv[i];
297 } else if (arg.startsWith("-XD")) {
298 String s = arg.substring("-XD".length());
299 int eq = s.indexOf('=');
300 String key = (eq < 0) ? s : s.substring(0, eq);
301 String value = (eq < 0) ? s : s.substring(eq+1);
302 compOpts.put(key, value);
303 }
304 // call doclet for its options
305 // other arg starts with - is invalid
306 else if ( arg.startsWith("-") ) {
307 int optionLength;
308 optionLength = docletInvoker.optionLength(arg);
309 if (optionLength < 0) {
310 // error already displayed
311 exit();
312 } else if (optionLength == 0) {
313 // option not found
314 usageError("main.invalid_flag", arg);
315 } else {
316 // doclet added option
317 if ((i + optionLength) > argv.length) {
318 usageError("main.requires_argument", arg);
319 }
320 ListBuffer<String> args = new ListBuffer<String>();
321 for (int j = 0; j < optionLength-1; ++j) {
322 args.append(argv[++i]);
323 }
324 setOption(arg, args.toList());
325 }
326 } else {
327 javaNames.append(arg);
328 }
329 }
331 if (javaNames.isEmpty() && subPackages.isEmpty()) {
332 usageError("main.No_packages_or_classes_specified");
333 }
335 if (!docletInvoker.validOptions(options.toList())) {
336 // error message already displayed
337 exit();
338 }
340 JavadocTool comp = JavadocTool.make0(context);
341 if (comp == null) return false;
343 if (showAccess == null) {
344 setFilter(defaultFilter);
345 }
347 LanguageVersion languageVersion = docletInvoker.languageVersion();
348 RootDocImpl root = comp.getRootDocImpl(
349 docLocale, encoding, showAccess,
350 javaNames.toList(), options.toList(), breakiterator,
351 subPackages.toList(), excludedPackages.toList(),
352 docClasses,
353 // legacy?
354 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet);
356 // pass off control to the doclet
357 boolean ok = root != null;
358 if (ok) ok = docletInvoker.start(root);
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 }
366 return ok;
367 }
369 private void setDocletInvoker(String[] argv) {
370 String docletClassName = null;
371 String docletPath = null;
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("main.more_than_one_doclet_specified_0_and_1",
380 docletClassName, argv[i]);
381 }
382 docletClassName = argv[i];
383 } else if (arg.equals("-docletpath")) {
384 oneArg(argv, i++);
385 if (docletPath == null) {
386 docletPath = argv[i];
387 } else {
388 docletPath += File.pathSeparator + argv[i];
389 }
390 }
391 }
393 if (docletClassName == null) {
394 docletClassName = defaultDocletClassName;
395 }
397 // attempt to find doclet
398 docletInvoker = new DocletInvoker(messager,
399 docletClassName, docletPath);
400 }
402 private void setFilter(long filterBits) {
403 if (showAccess != null) {
404 messager.error(null, "main.incompatible.access.flags");
405 usage();
406 exit();
407 }
408 showAccess = new ModifierFilter(filterBits);
409 }
411 /**
412 * Set one arg option.
413 * Error and exit if one argument is not provided.
414 */
415 private void oneArg(String[] args, int index) {
416 if ((index + 1) < args.length) {
417 setOption(args[index], args[index+1]);
418 } else {
419 usageError("main.requires_argument", args[index]);
420 }
421 }
423 private void usageError(String key) {
424 messager.error(null, key);
425 usage();
426 exit();
427 }
429 private void usageError(String key, String a1) {
430 messager.error(null, key, a1);
431 usage();
432 exit();
433 }
435 private void usageError(String key, String a1, String a2) {
436 messager.error(null, key, a1, a2);
437 usage();
438 exit();
439 }
441 /**
442 * indicate an option with no arguments was given.
443 */
444 private void setOption(String opt) {
445 String[] option = { opt };
446 options.append(option);
447 }
449 /**
450 * indicate an option with one argument was given.
451 */
452 private void setOption(String opt, String argument) {
453 String[] option = { opt, argument };
454 options.append(option);
455 }
457 /**
458 * indicate an option with the specified list of arguments was given.
459 */
460 private void setOption(String opt, List<String> arguments) {
461 String[] args = new String[arguments.length() + 1];
462 int k = 0;
463 args[k++] = opt;
464 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
465 args[k++] = i.head;
466 }
467 options = options.append(args);
468 }
470 }