Wed, 01 Oct 2008 16:26:33 -0700
6748601: javadoc API should allow varargs use
Reviewed-by: bpatel
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.util.Context;
32 import com.sun.tools.javac.util.List;
33 import com.sun.tools.javac.util.ListBuffer;
34 import com.sun.tools.javac.util.Options;
36 import java.io.IOException;
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.PrintWriter;
41 import java.util.StringTokenizer;
43 import static com.sun.tools.javac.code.Flags.*;
45 /**
46 * Main program of Javadoc.
47 * Previously named "Main".
48 *
49 * @since 1.2
50 * @author Robert Field
51 * @author Neal Gafter (rewrite)
52 */
53 class Start {
54 /** Context for this invocation. */
55 private final Context context;
57 /**
58 * Name of the program
59 */
60 private final String defaultDocletClassName;
62 private static final String javadocName = "javadoc";
64 private static final String standardDocletClassName =
65 "com.sun.tools.doclets.standard.Standard";
67 private ListBuffer<String[]> options = new ListBuffer<String[]>();
69 private ModifierFilter showAccess = null;
71 private long defaultFilter = PUBLIC | PROTECTED;
73 private Messager messager;
75 String docLocale = "";
77 boolean breakiterator = false;
78 boolean quiet = false;
79 String encoding = null;
81 private DocletInvoker docletInvoker;
83 private static final int F_VERBOSE = 1 << 0;
84 private static final int F_WARNINGS = 1 << 2;
86 /* Treat warnings as errors. */
87 private boolean rejectWarnings = false;
89 Start(String programName,
90 PrintWriter errWriter,
91 PrintWriter warnWriter,
92 PrintWriter noticeWriter,
93 String defaultDocletClassName) {
94 context = new Context();
95 messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
96 this.defaultDocletClassName = defaultDocletClassName;
97 }
99 Start(String programName, String defaultDocletClassName) {
100 context = new Context();
101 messager = new Messager(context, programName);
102 this.defaultDocletClassName = defaultDocletClassName;
103 }
105 Start(String programName) {
106 this(programName, standardDocletClassName);
107 }
109 Start() {
110 this(javadocName);
111 }
113 /**
114 * Usage
115 */
116 private void usage() {
117 messager.notice("main.usage");
119 // let doclet print usage information (does nothing on error)
120 if (docletInvoker != null) {
121 docletInvoker.optionLength("-help");
122 }
123 }
125 /**
126 * Exit
127 */
128 private void exit() {
129 messager.exit();
130 }
133 /**
134 * Main program - external wrapper
135 */
136 int begin(String... argv) {
137 boolean failed = false;
139 try {
140 failed = !parseAndExecute(argv);
141 } catch(Messager.ExitJavadoc exc) {
142 // ignore, we just exit this way
143 } catch (OutOfMemoryError ee) {
144 messager.error(null, "main.out.of.memory");
145 failed = true;
146 } catch (Error ee) {
147 ee.printStackTrace();
148 messager.error(null, "main.fatal.error");
149 failed = true;
150 } catch (Exception ee) {
151 ee.printStackTrace();
152 messager.error(null, "main.fatal.exception");
153 failed = true;
154 } finally {
155 messager.exitNotice();
156 messager.flush();
157 }
158 failed |= messager.nerrors() > 0;
159 failed |= rejectWarnings && messager.nwarnings() > 0;
160 return failed ? 1 : 0;
161 }
163 private void addToList(ListBuffer<String> list, String str){
164 StringTokenizer st = new StringTokenizer(str, ":");
165 String current;
166 while(st.hasMoreTokens()){
167 current = st.nextToken();
168 list.append(current);
169 }
170 }
172 /**
173 * Main program - internal
174 */
175 private boolean parseAndExecute(String... argv) throws IOException {
176 long tm = System.currentTimeMillis();
178 ListBuffer<String> javaNames = new ListBuffer<String>();
180 // Preprocess @file arguments
181 try {
182 argv = CommandLine.parse(argv);
183 } catch (FileNotFoundException e) {
184 messager.error(null, "main.cant.read", e.getMessage());
185 exit();
186 } catch (IOException e) {
187 e.printStackTrace();
188 exit();
189 }
191 setDocletInvoker(argv);
192 ListBuffer<String> subPackages = new ListBuffer<String>();
193 ListBuffer<String> excludedPackages = new ListBuffer<String>();
194 Options compOpts = Options.instance(context);
195 boolean docClasses = false;
197 // Parse arguments
198 for (int i = 0 ; i < argv.length ; i++) {
199 String arg = argv[i];
200 if (arg.equals("-subpackages")) {
201 oneArg(argv, i++);
202 addToList(subPackages, argv[i]);
203 } else if (arg.equals("-exclude")){
204 oneArg(argv, i++);
205 addToList(excludedPackages, argv[i]);
206 } else if (arg.equals("-verbose")) {
207 setOption(arg);
208 compOpts.put("-verbose", "");
209 } else if (arg.equals("-encoding")) {
210 oneArg(argv, i++);
211 encoding = argv[i];
212 compOpts.put("-encoding", argv[i]);
213 } else if (arg.equals("-breakiterator")) {
214 breakiterator = true;
215 setOption("-breakiterator");
216 } else if (arg.equals("-quiet")) {
217 quiet = true;
218 setOption("-quiet");
219 } else if (arg.equals("-help")) {
220 usage();
221 exit();
222 } else if (arg.equals("-Xclasses")) {
223 setOption(arg);
224 docClasses = true;
225 } else if (arg.equals("-Xwerror")) {
226 setOption(arg);
227 rejectWarnings = true;
228 } else if (arg.equals("-private")) {
229 setOption(arg);
230 setFilter(ModifierFilter.ALL_ACCESS);
231 } else if (arg.equals("-package")) {
232 setOption(arg);
233 setFilter(PUBLIC | PROTECTED |
234 ModifierFilter.PACKAGE );
235 } else if (arg.equals("-protected")) {
236 setOption(arg);
237 setFilter(PUBLIC | PROTECTED );
238 } else if (arg.equals("-public")) {
239 setOption(arg);
240 setFilter(PUBLIC);
241 } else if (arg.equals("-source")) {
242 oneArg(argv, i++);
243 if (compOpts.get("-source") != null) {
244 usageError("main.option.already.seen", arg);
245 }
246 compOpts.put("-source", argv[i]);
247 } else if (arg.equals("-prompt")) {
248 compOpts.put("-prompt", "-prompt");
249 messager.promptOnError = true;
250 } else if (arg.equals("-sourcepath")) {
251 oneArg(argv, i++);
252 if (compOpts.get("-sourcepath") != null) {
253 usageError("main.option.already.seen", arg);
254 }
255 compOpts.put("-sourcepath", argv[i]);
256 } else if (arg.equals("-classpath")) {
257 oneArg(argv, i++);
258 if (compOpts.get("-classpath") != null) {
259 usageError("main.option.already.seen", arg);
260 }
261 compOpts.put("-classpath", argv[i]);
262 } else if (arg.equals("-sysclasspath")) {
263 oneArg(argv, i++);
264 if (compOpts.get("-bootclasspath") != null) {
265 usageError("main.option.already.seen", arg);
266 }
267 compOpts.put("-bootclasspath", argv[i]);
268 } else if (arg.equals("-bootclasspath")) {
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("-extdirs")) {
275 oneArg(argv, i++);
276 if (compOpts.get("-extdirs") != null) {
277 usageError("main.option.already.seen", arg);
278 }
279 compOpts.put("-extdirs", argv[i]);
280 } else if (arg.equals("-overview")) {
281 oneArg(argv, i++);
282 } else if (arg.equals("-doclet")) {
283 i++; // handled in setDocletInvoker
284 } else if (arg.equals("-docletpath")) {
285 i++; // handled in setDocletInvoker
286 } else if (arg.equals("-locale")) {
287 if (i != 0)
288 usageError("main.locale_first");
289 oneArg(argv, i++);
290 docLocale = argv[i];
291 } else if (arg.startsWith("-XD")) {
292 String s = arg.substring("-XD".length());
293 int eq = s.indexOf('=');
294 String key = (eq < 0) ? s : s.substring(0, eq);
295 String value = (eq < 0) ? s : s.substring(eq+1);
296 compOpts.put(key, value);
297 }
298 // call doclet for its options
299 // other arg starts with - is invalid
300 else if ( arg.startsWith("-") ) {
301 int optionLength;
302 optionLength = docletInvoker.optionLength(arg);
303 if (optionLength < 0) {
304 // error already displayed
305 exit();
306 } else if (optionLength == 0) {
307 // option not found
308 usageError("main.invalid_flag", arg);
309 } else {
310 // doclet added option
311 if ((i + optionLength) > argv.length) {
312 usageError("main.requires_argument", arg);
313 }
314 ListBuffer<String> args = new ListBuffer<String>();
315 for (int j = 0; j < optionLength-1; ++j) {
316 args.append(argv[++i]);
317 }
318 setOption(arg, args.toList());
319 }
320 } else {
321 javaNames.append(arg);
322 }
323 }
325 if (javaNames.isEmpty() && subPackages.isEmpty()) {
326 usageError("main.No_packages_or_classes_specified");
327 }
329 if (!docletInvoker.validOptions(options.toList())) {
330 // error message already displayed
331 exit();
332 }
334 JavadocTool comp = JavadocTool.make0(context);
335 if (comp == null) return false;
337 if (showAccess == null) {
338 setFilter(defaultFilter);
339 }
341 LanguageVersion languageVersion = docletInvoker.languageVersion();
342 RootDocImpl root = comp.getRootDocImpl(
343 docLocale, encoding, showAccess,
344 javaNames.toList(), options.toList(), breakiterator,
345 subPackages.toList(), excludedPackages.toList(),
346 docClasses,
347 // legacy?
348 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet);
350 // pass off control to the doclet
351 boolean ok = root != null;
352 if (ok) ok = docletInvoker.start(root);
354 // We're done.
355 if (compOpts.get("-verbose") != null) {
356 tm = System.currentTimeMillis() - tm;
357 messager.notice("main.done_in", Long.toString(tm));
358 }
360 return ok;
361 }
363 private void setDocletInvoker(String[] argv) {
364 String docletClassName = null;
365 String docletPath = null;
367 // Parse doclet specifying arguments
368 for (int i = 0 ; i < argv.length ; i++) {
369 String arg = argv[i];
370 if (arg.equals("-doclet")) {
371 oneArg(argv, i++);
372 if (docletClassName != null) {
373 usageError("main.more_than_one_doclet_specified_0_and_1",
374 docletClassName, argv[i]);
375 }
376 docletClassName = argv[i];
377 } else if (arg.equals("-docletpath")) {
378 oneArg(argv, i++);
379 if (docletPath == null) {
380 docletPath = argv[i];
381 } else {
382 docletPath += File.pathSeparator + argv[i];
383 }
384 }
385 }
387 if (docletClassName == null) {
388 docletClassName = defaultDocletClassName;
389 }
391 // attempt to find doclet
392 docletInvoker = new DocletInvoker(messager,
393 docletClassName, docletPath);
394 }
396 private void setFilter(long filterBits) {
397 if (showAccess != null) {
398 messager.error(null, "main.incompatible.access.flags");
399 usage();
400 exit();
401 }
402 showAccess = new ModifierFilter(filterBits);
403 }
405 /**
406 * Set one arg option.
407 * Error and exit if one argument is not provided.
408 */
409 private void oneArg(String[] args, int index) {
410 if ((index + 1) < args.length) {
411 setOption(args[index], args[index+1]);
412 } else {
413 usageError("main.requires_argument", args[index]);
414 }
415 }
417 private void usageError(String key) {
418 messager.error(null, key);
419 usage();
420 exit();
421 }
423 private void usageError(String key, String a1) {
424 messager.error(null, key, a1);
425 usage();
426 exit();
427 }
429 private void usageError(String key, String a1, String a2) {
430 messager.error(null, key, a1, a2);
431 usage();
432 exit();
433 }
435 /**
436 * indicate an option with no arguments was given.
437 */
438 private void setOption(String opt) {
439 String[] option = { opt };
440 options.append(option);
441 }
443 /**
444 * indicate an option with one argument was given.
445 */
446 private void setOption(String opt, String argument) {
447 String[] option = { opt, argument };
448 options.append(option);
449 }
451 /**
452 * indicate an option with the specified list of arguments was given.
453 */
454 private void setOption(String opt, List<String> arguments) {
455 String[] args = new String[arguments.length() + 1];
456 int k = 0;
457 args[k++] = opt;
458 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
459 args[k++] = i.head;
460 }
461 options = options.append(args);
462 }
464 }