Start.java revision 3573:c4a18ee691c4
1249259Sdim/*
2249259Sdim * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3249259Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4249259Sdim *
5249259Sdim * This code is free software; you can redistribute it and/or modify it
6249259Sdim * under the terms of the GNU General Public License version 2 only, as
7249259Sdim * published by the Free Software Foundation.  Oracle designates this
8249259Sdim * particular file as subject to the "Classpath" exception as provided
9249259Sdim * by Oracle in the LICENSE file that accompanied this code.
10249259Sdim *
11249259Sdim * This code is distributed in the hope that it will be useful, but WITHOUT
12263508Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13249259Sdim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14249259Sdim * version 2 for more details (a copy is included in the LICENSE file that
15249259Sdim * accompanied this code).
16249259Sdim *
17249259Sdim * You should have received a copy of the GNU General Public License version
18249259Sdim * 2 along with this work; if not, write to the Free Software Foundation,
19249259Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20249259Sdim *
21249259Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22249259Sdim * or visit www.oracle.com if you need additional information or have any
23249259Sdim * questions.
24249259Sdim */
25249259Sdim
26249259Sdimpackage com.sun.tools.javadoc.main;
27249259Sdim
28263508Sdimimport java.io.File;
29263508Sdimimport java.io.FileNotFoundException;
30249259Sdimimport java.io.IOException;
31249259Sdimimport java.io.PrintWriter;
32263508Sdimimport java.nio.file.Path;
33249259Sdimimport java.util.ArrayList;
34249259Sdimimport java.util.Collection;
35263508Sdimimport java.util.Collections;
36249259Sdimimport java.util.Objects;
37249259Sdim
38263508Sdimimport javax.tools.JavaFileManager;
39263508Sdimimport javax.tools.JavaFileObject;
40249259Sdimimport javax.tools.StandardJavaFileManager;
41263508Sdimimport javax.tools.StandardLocation;
42249259Sdim
43249259Sdimimport com.sun.javadoc.*;
44249259Sdimimport com.sun.tools.javac.file.JavacFileManager;
45263508Sdimimport com.sun.tools.javac.main.CommandLine;
46263508Sdimimport com.sun.tools.javac.main.Option;
47249259Sdimimport com.sun.tools.javac.file.BaseFileManager;
48249259Sdimimport com.sun.tools.javac.main.OptionHelper;
49249259Sdimimport com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
50263508Sdimimport com.sun.tools.javac.platform.PlatformDescription;
51263508Sdimimport com.sun.tools.javac.platform.PlatformUtils;
52263508Sdimimport com.sun.tools.javac.util.ClientCodeException;
53263508Sdimimport com.sun.tools.javac.util.Context;
54263508Sdimimport com.sun.tools.javac.util.List;
55263508Sdimimport com.sun.tools.javac.util.ListBuffer;
56263508Sdimimport com.sun.tools.javac.util.Log;
57263508Sdimimport com.sun.tools.javac.util.Options;
58263508Sdim
59263508Sdimimport static com.sun.tools.javac.code.Flags.*;
60263508Sdim
61263508Sdim/**
62263508Sdim * Main program of Javadoc.
63263508Sdim * Previously named "Main".
64263508Sdim *
65263508Sdim *  <p><b>This is NOT part of any supported API.
66263508Sdim *  If you write code that depends on this, you do so at your own risk.
67263508Sdim *  This code and its internal interfaces are subject to change or
68263508Sdim *  deletion without notice.</b>
69263508Sdim *
70263508Sdim * @since 1.2
71263508Sdim * @author Robert Field
72263508Sdim * @author Neal Gafter (rewrite)
73263508Sdim */
74263508Sdim@Deprecated
75263508Sdimpublic class Start extends ToolOption.Helper {
76263508Sdim    /** Context for this invocation. */
77263508Sdim    private final Context context;
78263508Sdim
79263508Sdim    private final String defaultDocletClassName;
80263508Sdim    private final ClassLoader docletParentClassLoader;
81249259Sdim
82263508Sdim    private static final String javadocName = "javadoc";
83263508Sdim
84249259Sdim    private static final String standardDocletClassName =
85249259Sdim        "com.sun.tools.doclets.standard.Standard";
86249259Sdim
87263508Sdim    private final long defaultFilter = PUBLIC | PROTECTED;
88263508Sdim
89263508Sdim    private final Messager messager;
90263508Sdim
91263508Sdim    private DocletInvoker docletInvoker;
92263508Sdim
93263508Sdim    /**
94263508Sdim     * In API mode, exceptions thrown while calling the doclet are
95263508Sdim     * propagated using ClientCodeException.
96263508Sdim     */
97263508Sdim    private boolean apiMode;
98263508Sdim
99249259Sdim    private JavaFileManager fileManager;
100249259Sdim
101263508Sdim    public Start(String programName,
102263508Sdim          PrintWriter errWriter,
103263508Sdim          PrintWriter warnWriter,
104263508Sdim          PrintWriter noticeWriter,
105263508Sdim          String defaultDocletClassName) {
106263508Sdim        this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);
107263508Sdim    }
108263508Sdim
109263508Sdim    public Start(PrintWriter pw) {
110263508Sdim        this(javadocName, pw, pw, pw, standardDocletClassName);
111263508Sdim    }
112263508Sdim
113263508Sdim    public Start(String programName,
114263508Sdim          PrintWriter errWriter,
115263508Sdim          PrintWriter warnWriter,
116263508Sdim          PrintWriter noticeWriter,
117263508Sdim          String defaultDocletClassName,
118263508Sdim          ClassLoader docletParentClassLoader) {
119263508Sdim        context = new Context();
120263508Sdim        messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
121263508Sdim        this.defaultDocletClassName = defaultDocletClassName;
122263508Sdim        this.docletParentClassLoader = docletParentClassLoader;
123263508Sdim    }
124263508Sdim
125263508Sdim    public Start(String programName, String defaultDocletClassName) {
126263508Sdim        this(programName, defaultDocletClassName, null);
127263508Sdim    }
128263508Sdim
129263508Sdim    public Start(String programName, String defaultDocletClassName,
130263508Sdim          ClassLoader docletParentClassLoader) {
131263508Sdim        context = new Context();
132263508Sdim        messager = new Messager(context, programName);
133263508Sdim        this.defaultDocletClassName = defaultDocletClassName;
134263508Sdim        this.docletParentClassLoader = docletParentClassLoader;
135263508Sdim    }
136263508Sdim
137263508Sdim    public Start(String programName, ClassLoader docletParentClassLoader) {
138263508Sdim        this(programName, standardDocletClassName, docletParentClassLoader);
139263508Sdim    }
140263508Sdim
141263508Sdim    public Start(String programName) {
142263508Sdim        this(programName, standardDocletClassName);
143263508Sdim    }
144263508Sdim
145263508Sdim    public Start(ClassLoader docletParentClassLoader) {
146263508Sdim        this(javadocName, docletParentClassLoader);
147263508Sdim    }
148263508Sdim
149263508Sdim    public Start() {
150263508Sdim        this(javadocName);
151263508Sdim    }
152263508Sdim
153263508Sdim    public Start(Context context) {
154263508Sdim        this.context = Objects.requireNonNull(context);
155263508Sdim        apiMode = true;
156263508Sdim        defaultDocletClassName = standardDocletClassName;
157263508Sdim        docletParentClassLoader = null;
158263508Sdim
159263508Sdim        Log log = context.get(Log.logKey);
160263508Sdim        if (log instanceof Messager)
161263508Sdim            messager = (Messager) log;
162263508Sdim        else {
163263508Sdim            PrintWriter out = context.get(Log.errKey);
164263508Sdim            messager = (out == null) ? new Messager(context, javadocName)
165263508Sdim                    : new Messager(context, javadocName, out, out, out);
166263508Sdim        }
167263508Sdim    }
168263508Sdim
169263508Sdim    /**
170263508Sdim     * Usage
171263508Sdim     */
172263508Sdim    @Override
173263508Sdim    void usage() {
174263508Sdim        usage(true);
175263508Sdim    }
176263508Sdim
177263508Sdim    void usage(boolean exit) {
178263508Sdim        usage("main.usage", "-help", "main.usage.foot", exit);
179263508Sdim    }
180263508Sdim
181263508Sdim    @Override
182263508Sdim    void Xusage() {
183263508Sdim        Xusage(true);
184263508Sdim    }
185263508Sdim
186263508Sdim    void Xusage(boolean exit) {
187263508Sdim        usage("main.Xusage", "-X", "main.Xusage.foot", exit);
188263508Sdim    }
189263508Sdim
190263508Sdim    private void usage(String main, String doclet, String foot, boolean exit) {
191263508Sdim        // RFE: it would be better to replace the following with code to
192263508Sdim        // write a header, then help for each option, then a footer.
193263508Sdim        messager.notice(main);
194263508Sdim
195263508Sdim        // let doclet print usage information (does nothing on error)
196263508Sdim        if (docletInvoker != null) {
197263508Sdim            // RFE: this is a pretty bad way to get the doclet to show
198263508Sdim            // help info. Moreover, the output appears on stdout,
199263508Sdim            // and <i>not</i> on any of the standard streams passed
200263508Sdim            // to javadoc, and in particular, not to the noticeWriter
201263508Sdim            // But, to fix this, we need to fix the Doclet API.
202263508Sdim            docletInvoker.optionLength(doclet);
203263508Sdim        }
204263508Sdim
205263508Sdim        if (foot != null)
206263508Sdim            messager.notice(foot);
207263508Sdim
208263508Sdim        if (exit) exit();
209263508Sdim    }
210263508Sdim
211263508Sdim    /**
212263508Sdim     * Exit
213263508Sdim     */
214263508Sdim    private void exit() {
215263508Sdim        messager.exit();
216263508Sdim    }
217263508Sdim
218263508Sdim
219263508Sdim    /**
220263508Sdim     * Main program - external wrapper
221263508Sdim     */
222263508Sdim    public int begin(String... argv) {
223263508Sdim        boolean ok = begin(null, argv, Collections.<JavaFileObject> emptySet());
224263508Sdim        return ok ? 0 : 1;
225263508Sdim    }
226263508Sdim
227263508Sdim    public boolean begin(Class<?> docletClass, Iterable<String> options, Iterable<? extends JavaFileObject> fileObjects) {
228263508Sdim        Collection<String> opts = new ArrayList<>();
229263508Sdim        for (String opt: options) opts.add(opt);
230263508Sdim        return begin(docletClass, opts.toArray(new String[opts.size()]), fileObjects);
231263508Sdim    }
232263508Sdim
233263508Sdim    private boolean begin(Class<?> docletClass, String[] options, Iterable<? extends JavaFileObject> fileObjects) {
234263508Sdim        boolean failed = false;
235263508Sdim
236263508Sdim        try {
237263508Sdim            failed = !parseAndExecute(docletClass, options, fileObjects);
238263508Sdim        } catch (Messager.ExitJavadoc exc) {
239263508Sdim            // ignore, we just exit this way
240263508Sdim        } catch (OutOfMemoryError ee) {
241263508Sdim            messager.error(Messager.NOPOS, "main.out.of.memory");
242263508Sdim            failed = true;
243263508Sdim        } catch (ClientCodeException e) {
244263508Sdim            // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl
245263508Sdim            throw e;
246263508Sdim        } catch (Error ee) {
247263508Sdim            ee.printStackTrace(System.err);
248263508Sdim            messager.error(Messager.NOPOS, "main.fatal.error");
249263508Sdim            failed = true;
250263508Sdim        } catch (Exception ee) {
251263508Sdim            ee.printStackTrace(System.err);
252263508Sdim            messager.error(Messager.NOPOS, "main.fatal.exception");
253263508Sdim            failed = true;
254263508Sdim        } finally {
255263508Sdim            if (fileManager != null
256263508Sdim                    && fileManager instanceof BaseFileManager
257263508Sdim                    && ((BaseFileManager) fileManager).autoClose) {
258249259Sdim                try {
259249259Sdim                    fileManager.close();
260249259Sdim                } catch (IOException ignore) {
261249259Sdim                }
262249259Sdim            }
263263508Sdim            messager.exitNotice();
264263508Sdim            messager.flush();
265263508Sdim        }
266249259Sdim        failed |= messager.nerrors() > 0;
267249259Sdim        failed |= rejectWarnings && messager.nwarnings() > 0;
268249259Sdim        return !failed;
269249259Sdim    }
270249259Sdim
271249259Sdim    /**
272249259Sdim     * Main program - internal
273263508Sdim     */
274263508Sdim    private boolean parseAndExecute(
275263508Sdim            Class<?> docletClass,
276263508Sdim            String[] argv,
277263508Sdim            Iterable<? extends JavaFileObject> fileObjects) throws IOException {
278263508Sdim        long tm = System.currentTimeMillis();
279263508Sdim
280263508Sdim        ListBuffer<String> javaNames = new ListBuffer<>();
281249259Sdim
282263508Sdim        // Preprocess @file arguments
283263508Sdim        try {
284263508Sdim            argv = CommandLine.parse(argv);
285263508Sdim        } catch (FileNotFoundException e) {
286249259Sdim            messager.error(Messager.NOPOS, "main.cant.read", e.getMessage());
287263508Sdim            exit();
288263508Sdim        } catch (IOException e) {
289249259Sdim            e.printStackTrace(System.err);
290263508Sdim            exit();
291263508Sdim        }
292263508Sdim
293263508Sdim
294263508Sdim        fileManager = context.get(JavaFileManager.class);
295263508Sdim
296263508Sdim        setDocletInvoker(docletClass, fileManager, argv);
297263508Sdim
298263508Sdim        compOpts = Options.instance(context);
299263508Sdim        // Make sure no obsolete source/target messages are reported
300263508Sdim        compOpts.put("-Xlint:-options", "-Xlint:-options");
301263508Sdim
302263508Sdim        // Parse arguments
303263508Sdim        for (int i = 0 ; i < argv.length ; i++) {
304263508Sdim            String arg = argv[i];
305263508Sdim
306263508Sdim            ToolOption o = ToolOption.get(arg);
307263508Sdim            if (o != null) {
308263508Sdim                // hack: this restriction should be removed
309263508Sdim                if (o == ToolOption.LOCALE && i > 0)
310263508Sdim                    usageError("main.locale_first");
311263508Sdim
312263508Sdim                if (o.hasArg) {
313263508Sdim                    oneArg(argv, i++);
314263508Sdim                    o.process(this, argv[i]);
315263508Sdim                } else {
316263508Sdim                    setOption(arg);
317263508Sdim                    o.process(this);
318249259Sdim                }
319249259Sdim            } else if (arg.equals("-XDaccessInternalAPI")) {
320249259Sdim                // pass this hidden option down to the doclet, if it wants it
321249259Sdim                if (docletInvoker.optionLength("-XDaccessInternalAPI") == 1) {
322249259Sdim                    setOption(arg);
323263508Sdim                }
324263508Sdim            } else if (arg.startsWith("-XD")) {
325263508Sdim                // hidden javac options
326263508Sdim                String s = arg.substring("-XD".length());
327263508Sdim                int eq = s.indexOf('=');
328263508Sdim                String key = (eq < 0) ? s : s.substring(0, eq);
329263508Sdim                String value = (eq < 0) ? s : s.substring(eq+1);
330263508Sdim                compOpts.put(key, value);
331263508Sdim            }
332263508Sdim            // call doclet for its options
333263508Sdim            // other arg starts with - is invalid
334263508Sdim            else if (arg.startsWith("-")) {
335263508Sdim                int optionLength;
336263508Sdim                optionLength = docletInvoker.optionLength(arg);
337263508Sdim                if (optionLength < 0) {
338263508Sdim                    // error already displayed
339263508Sdim                    exit();
340263508Sdim                } else if (optionLength == 0) {
341263508Sdim                    // option not found
342263508Sdim                    usageError("main.invalid_flag", arg);
343263508Sdim                } else {
344263508Sdim                    // doclet added option
345263508Sdim                    if ((i + optionLength) > argv.length) {
346263508Sdim                        usageError("main.requires_argument", arg);
347249259Sdim                    }
348249259Sdim                    ListBuffer<String> args = new ListBuffer<>();
349249259Sdim                    for (int j = 0; j < optionLength-1; ++j) {
350249259Sdim                        args.append(argv[++i]);
351249259Sdim                    }
352249259Sdim                    setOption(arg, args.toList());
353263508Sdim                }
354251662Sdim            } else {
355251662Sdim                javaNames.append(arg);
356263508Sdim            }
357263508Sdim        }
358263508Sdim
359263508Sdim        if (fileManager == null) {
360263508Sdim            JavacFileManager.preRegister(context);
361263508Sdim            fileManager = context.get(JavaFileManager.class);
362263508Sdim            if (fileManager instanceof BaseFileManager) {
363263508Sdim                ((BaseFileManager) fileManager).autoClose = true;
364263508Sdim            }
365263508Sdim        }
366263508Sdim        if (fileManager instanceof BaseFileManager) {
367263508Sdim            ((BaseFileManager) fileManager).handleOptions(fileManagerOpts);
368263508Sdim        }
369263508Sdim
370263508Sdim        String platformString = compOpts.get("--release");
371263508Sdim
372263508Sdim        if (platformString != null) {
373263508Sdim            if (compOpts.isSet("-source")) {
374263508Sdim                usageError("main.release.bootclasspath.conflict", "-source");
375263508Sdim            }
376263508Sdim            if (fileManagerOpts.containsKey(Option.BOOT_CLASS_PATH)) {
377263508Sdim                usageError("main.release.bootclasspath.conflict", Option.BOOT_CLASS_PATH.getPrimaryName());
378263508Sdim            }
379263508Sdim
380263508Sdim            PlatformDescription platformDescription =
381263508Sdim                    PlatformUtils.lookupPlatformDescription(platformString);
382263508Sdim
383263508Sdim            if (platformDescription == null) {
384263508Sdim                usageError("main.unsupported.release.version", platformString);
385263508Sdim            }
386263508Sdim
387263508Sdim            compOpts.put(Option.SOURCE, platformDescription.getSourceVersion());
388263508Sdim
389263508Sdim            context.put(PlatformDescription.class, platformDescription);
390263508Sdim
391263508Sdim            Collection<Path> platformCP = platformDescription.getPlatformPath();
392263508Sdim
393263508Sdim            if (platformCP != null) {
394263508Sdim                if (fileManager instanceof StandardJavaFileManager) {
395263508Sdim                    StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
396263508Sdim
397263508Sdim                    sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
398263508Sdim                } else {
399263508Sdim                    usageError("main.release.not.standard.file.manager", platformString);
400263508Sdim                }
401263508Sdim            }
402263508Sdim        }
403263508Sdim
404263508Sdim        compOpts.notifyListeners();
405263508Sdim
406263508Sdim        if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) {
407263508Sdim            usageError("main.No_packages_or_classes_specified");
408263508Sdim        }
409263508Sdim
410263508Sdim        if (!docletInvoker.validOptions(options.toList())) {
411263508Sdim            // error message already displayed
412263508Sdim            exit();
413263508Sdim        }
414263508Sdim
415263508Sdim        JavadocTool comp = JavadocTool.make0(context);
416263508Sdim        if (comp == null) return false;
417263508Sdim
418263508Sdim        if (showAccess == null) {
419263508Sdim            setFilter(defaultFilter);
420263508Sdim        }
421263508Sdim
422263508Sdim        LanguageVersion languageVersion = docletInvoker.languageVersion();
423263508Sdim        RootDocImpl root = comp.getRootDocImpl(
424263508Sdim                docLocale,
425263508Sdim                encoding,
426263508Sdim                showAccess,
427263508Sdim                javaNames.toList(),
428263508Sdim                options.toList(),
429263508Sdim                fileObjects,
430263508Sdim                breakiterator,
431263508Sdim                subPackages.toList(),
432263508Sdim                excludedPackages.toList(),
433263508Sdim                docClasses,
434263508Sdim                // legacy?
435263508Sdim                languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1,
436263508Sdim                quiet);
437263508Sdim
438263508Sdim        // release resources
439263508Sdim        comp = null;
440263508Sdim
441263508Sdim        // pass off control to the doclet
442263508Sdim        boolean ok = root != null;
443263508Sdim        if (ok) ok = docletInvoker.start(root);
444263508Sdim
445263508Sdim        // We're done.
446263508Sdim        if (compOpts.get("-verbose") != null) {
447263508Sdim            tm = System.currentTimeMillis() - tm;
448263508Sdim            messager.notice("main.done_in", Long.toString(tm));
449263508Sdim        }
450263508Sdim
451263508Sdim        return ok;
452263508Sdim    }
453263508Sdim
454263508Sdim    private <T> boolean isEmpty(Iterable<T> iter) {
455263508Sdim        return !iter.iterator().hasNext();
456263508Sdim    }
457263508Sdim
458263508Sdim    /**
459263508Sdim     * Init the doclet invoker.
460263508Sdim     * The doclet class may be given explicitly, or via the -doclet option in
461263508Sdim     * argv.
462263508Sdim     * If the doclet class is not given explicitly, it will be loaded from
463263508Sdim     * the file manager's DOCLET_PATH location, if available, or via the
464263508Sdim     * -doclet path option in argv.
465263508Sdim     * @param docletClass The doclet class. May be null.
466263508Sdim     * @param fileManager The file manager used to get the class loader to load
467263508Sdim     * the doclet class if required. May be null.
468263508Sdim     * @param argv Args containing -doclet and -docletpath, in case they are required.
469263508Sdim     */
470263508Sdim    private void setDocletInvoker(Class<?> docletClass, JavaFileManager fileManager, String[] argv) {
471263508Sdim        boolean exportInternalAPI = false;
472263508Sdim        String docletClassName = null;
473263508Sdim        String docletPath = null;
474263508Sdim
475263508Sdim        // Parse doclet specifying arguments
476263508Sdim        for (int i = 0 ; i < argv.length ; i++) {
477263508Sdim            String arg = argv[i];
478263508Sdim            if (arg.equals(ToolOption.DOCLET.opt)) {
479263508Sdim                oneArg(argv, i++);
480263508Sdim                if (docletClassName != null) {
481263508Sdim                    usageError("main.more_than_one_doclet_specified_0_and_1",
482263508Sdim                               docletClassName, argv[i]);
483263508Sdim                }
484263508Sdim                docletClassName = argv[i];
485263508Sdim            } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
486263508Sdim                oneArg(argv, i++);
487263508Sdim                if (docletPath == null) {
488263508Sdim                    docletPath = argv[i];
489263508Sdim                } else {
490263508Sdim                    docletPath += File.pathSeparator + argv[i];
491263508Sdim                }
492263508Sdim            } else if (arg.equals("-XDaccessInternalAPI")) {
493263508Sdim                exportInternalAPI = true;
494263508Sdim            }
495263508Sdim        }
496263508Sdim
497263508Sdim        if (docletClass != null) {
498263508Sdim            // TODO, check no -doclet, -docletpath
499263508Sdim            docletInvoker = new DocletInvoker(messager, docletClass, apiMode, exportInternalAPI);
500263508Sdim        } else {
501263508Sdim            if (docletClassName == null) {
502263508Sdim                docletClassName = defaultDocletClassName;
503263508Sdim            }
504263508Sdim
505263508Sdim            // attempt to find doclet
506263508Sdim            docletInvoker = new DocletInvoker(messager, fileManager,
507263508Sdim                    docletClassName, docletPath,
508263508Sdim                    docletParentClassLoader,
509263508Sdim                    apiMode,
510263508Sdim                    exportInternalAPI);
511263508Sdim        }
512263508Sdim    }
513263508Sdim
514263508Sdim    /**
515263508Sdim     * Set one arg option.
516263508Sdim     * Error and exit if one argument is not provided.
517263508Sdim     */
518263508Sdim    private void oneArg(String[] args, int index) {
519263508Sdim        if ((index + 1) < args.length) {
520263508Sdim            setOption(args[index], args[index+1]);
521251662Sdim        } else {
522249259Sdim            usageError("main.requires_argument", args[index]);
523249259Sdim        }
524263508Sdim    }
525263508Sdim
526263508Sdim    @Override
527263508Sdim    void usageError(String key, Object... args) {
528263508Sdim        messager.error(Messager.NOPOS, key, args);
529263508Sdim        usage(true);
530263508Sdim    }
531263508Sdim
532263508Sdim    /**
533263508Sdim     * indicate an option with no arguments was given.
534263508Sdim     */
535263508Sdim    private void setOption(String opt) {
536263508Sdim        String[] option = { opt };
537263508Sdim        options.append(option);
538263508Sdim    }
539263508Sdim
540263508Sdim    /**
541263508Sdim     * indicate an option with one argument was given.
542263508Sdim     */
543263508Sdim    private void setOption(String opt, String argument) {
544263508Sdim        String[] option = { opt, argument };
545263508Sdim        options.append(option);
546263508Sdim    }
547263508Sdim
548263508Sdim    /**
549263508Sdim     * indicate an option with the specified list of arguments was given.
550263508Sdim     */
551263508Sdim    private void setOption(String opt, List<String> arguments) {
552263508Sdim        String[] args = new String[arguments.length() + 1];
553263508Sdim        int k = 0;
554263508Sdim        args[k++] = opt;
555263508Sdim        for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
556263508Sdim            args[k++] = i.head;
557263508Sdim        }
558263508Sdim        options.append(args);
559263508Sdim    }
560263508Sdim
561263508Sdim    @Override
562263508Sdim    OptionHelper getOptionHelper() {
563263508Sdim        return new GrumpyHelper(null) {
564263508Sdim            @Override
565263508Sdim            public String get(com.sun.tools.javac.main.Option option) {
566263508Sdim                return compOpts.get(option);
567263508Sdim            }
568263508Sdim
569263508Sdim            @Override
570263508Sdim            public void put(String name, String value) {
571263508Sdim                compOpts.put(name, value);
572263508Sdim            }
573263508Sdim        };
574263508Sdim    }
575263508Sdim}
576263508Sdim