URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [gnu/] [classpath/] [tools/] [gjdoc/] [Main.java] - Rev 779
Compare with Previous | Blame | View Log
/* gnu.classpath.tools.gjdoc.Main Copyright (C) 2001 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath 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 for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package gnu.classpath.tools.gjdoc; import com.sun.javadoc.*; import java.io.*; import java.util.*; import java.lang.reflect.*; import java.text.Collator; import gnu.classpath.tools.FileSystemClassLoader; /** * Class that will launch the gjdoc tool. */ public final class Main { /** * Do we load classes that are referenced as base class? */ static final boolean DESCEND_SUPERCLASS = true; /** * Do we load classes that are referenced as interface? */ static final boolean DESCEND_INTERFACES = false; /** * Do we load classes that are imported in a source file? */ static final boolean DESCEND_IMPORTED = true; /** * Document only public members. */ static final int COVERAGE_PUBLIC = 0; /** * Document only public and protected members. */ static final int COVERAGE_PROTECTED = 1; /** * Document public, protected and package private members. */ static final int COVERAGE_PACKAGE = 2; /** * Document all members. */ static final int COVERAGE_PRIVATE = 3; /* * FIXME: This should come from a ResourceBundle */ private static final String STRING_TRY_GJDOC_HELP = "Try `gjdoc --help' for more information."; /** * Grid for looking up whether a particular access level is included in the * documentation. */ static final boolean[][] coverageTemplates = new boolean[][] { new boolean[] { true, false, false, false }, // public new boolean[] { true, true, false, false }, // protected new boolean[] { true, true, true, false }, // package new boolean[] { true, true, true, true }, // private }; /** * Holds the Singleton instance of this class. */ private static Main instance = new Main(); /** * Avoid re-instantiation of this class. */ private Main() { } private static RootDocImpl rootDoc; private ErrorReporter reporter; /** * Cache for version string from resource /version.properties */ private String gjdocVersion; /** * <code>false</code> during Phase I: preparation of the documentation data. * <code>true</code> during Phase II: documentation output by doclet. */ boolean docletRunning = false; //---- Command line options /** * Option "-doclet": name of the Doclet class to use. */ private String option_doclet = "gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet"; /** * Option "-overview": path to the special overview file. */ private String option_overview; /** * Option "-coverage": which members to include in generated documentation. */ private int option_coverage = COVERAGE_PROTECTED; /** * Option "-help": display command line usage. */ private boolean option_help; /** * Option "-docletpath": path to doclet classes. */ private String option_docletpath; /** * Option "-classpath": path to additional classes. */ private String option_classpath; /** * Option "-sourcepath": path to the Java source files to be documented. * FIXME: this should be a list of paths */ private List option_sourcepath = new ArrayList(); /** * Option "-extdirs": path to Java extension files. */ private String option_extdirs; /** * Option "-verbose": Be verbose when generating documentation. */ private boolean option_verbose; /** * Option "-nowarn": Do not print warnings. */ private boolean option_nowarn; /** * Option "-locale:" Specify the locale charset of Java source files. */ private Locale option_locale = new Locale("en", "us"); /** * Option "-encoding": Specify character encoding of Java source files. */ private String option_encoding; /** * Option "-J": Specify flags to be passed to Java runtime. */ private List option_java_flags = new LinkedList(); //ArrayList(); /** * Option "-source:" should be 1.4 to handle assertions, 1.1 is no * longer supported. */ private String option_source = "1.2"; /** * Option "-subpackages": list of subpackages to be recursively * added. */ private List option_subpackages = new ArrayList(); /** * Option "-exclude": list of subpackages to exclude. */ private List option_exclude = new ArrayList(); /** * Option "-breakiterator" - whether to use BreakIterator for * detecting the end of the first sentence. */ private boolean option_breakiterator; /** * Option "-licensetext" - whether to copy license text. */ private boolean option_licensetext; /** * The locale-dependent collator used for sorting. */ private Collator collator; /** * true when --version has been specified on the command line. */ private boolean option_showVersion; /** * true when -bootclasspath has been specified on the command line. */ private boolean option_bootclasspath_specified; /** * true when -all has been specified on the command line. */ private boolean option_all; /** * true when -reflection has been specified on the command line. */ private boolean option_reflection; // TODO: add the rest of the options as instance variables /** * Parse all source files/packages and subsequentially start the Doclet given * on the command line. * * @param allOptions List of all command line tokens */ private boolean startDoclet(List allOptions) { try { //--- Fetch the Class object for the Doclet. Debug.log(1, "loading doclet class..."); Class docletClass; if (null != option_docletpath) { try { FileSystemClassLoader docletPathClassLoader = new FileSystemClassLoader(option_docletpath); System.err.println("trying to load class " + option_doclet + " from path " + option_docletpath); docletClass = docletPathClassLoader.findClass(option_doclet); } catch (Exception e) { docletClass = Class.forName(option_doclet); } } else { docletClass = Class.forName(option_doclet); } //Object docletInstance = docletClass.newInstance(); Debug.log(1, "doclet class loaded..."); Method startTempMethod = null; Method startMethod = null; Method optionLenMethod = null; Method validOptionsMethod = null; //--- Try to find the optionLength method in the Doclet class. try { optionLenMethod = docletClass.getMethod("optionLength", new Class[] { String.class }); } catch (NoSuchMethodException e) { // Ignore if not found; it's OK it the Doclet class doesn't define // this method. } //--- Try to find the validOptions method in the Doclet class. try { validOptionsMethod = docletClass.getMethod("validOptions", new Class[] { String[][].class, DocErrorReporter.class }); } catch (NoSuchMethodException e) { // Ignore if not found; it's OK it the Doclet class doesn't define // this method. } //--- Find the start method in the Doclet class; complain if not found try { startTempMethod = docletClass.getMethod("start", new Class[] { TemporaryStore.class }); } catch (Exception e) { // ignore } startMethod = docletClass.getMethod("start", new Class[] { RootDoc.class }); //--- Feed the custom command line tokens to the Doclet // stores all recognized options List options = new LinkedList(); // stores packages and classes defined on the command line List packageAndClasses = new LinkedList(); for (Iterator it = allOptions.iterator(); it.hasNext();) { String option = (String) it.next(); Debug.log(9, "parsing option '" + option + "'"); if (option.startsWith("-")) { //--- Parse option int optlen = optionLength(option); //--- Try to get option length from Doclet class if (optlen <= 0 && optionLenMethod != null) { optionLenMethod.invoke(null, new Object[] { option }); Debug.log(3, "invoking optionLen method"); optlen = ((Integer) optionLenMethod.invoke(null, new Object[] { option })).intValue(); Debug.log(3, "done"); } if (optlen <= 0) { if (option.startsWith("-JD")) { // Simulate VM option -D String propertyValue = option.substring(3); int ndx = propertyValue.indexOf('='); if (ndx <= 0) { reporter.printError("Illegal format in option " + option + ": use -JDproperty=value"); return false; } else { String property = propertyValue.substring(0, ndx); String value = propertyValue.substring(ndx + 1); System.setProperty(property, value); } } else if (option.startsWith("-J")) { //--- Warn if VM option is encountered reporter.printWarning("Ignored option " + option + ". Pass this option to the VM if required."); } else { //--- Complain if not found reporter.printError("Unknown option " + option); reporter.printNotice(STRING_TRY_GJDOC_HELP); return false; } } else { //--- Read option values String[] optionAndValues = new String[optlen]; optionAndValues[0] = option; for (int i = 1; i < optlen; ++i) { if (!it.hasNext()) { reporter.printError("Missing value for option " + option); return false; } else { optionAndValues[i] = (String) it.next(); } } //--- Store option for processing later options.add(optionAndValues); } } else if (option.length() > 0) { //--- Add to list of packages/classes if not option or option // value packageAndClasses.add(option); } } Debug.log(9, "options parsed..."); //--- For each package specified with the -subpackages option on // the command line, recursively find all valid java files // beneath it. //--- For each class or package specified on the command line, // check that it exists and find out whether it is a class // or a package for (Iterator it = option_subpackages.iterator(); it.hasNext();) { String subpackage = (String) it.next(); Set foundPackages = new LinkedHashSet(); for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) { File sourceDir = (File)pit.next(); File packageDir = new File(sourceDir, subpackage.replace('.', File.separatorChar)); findPackages(subpackage, packageDir, foundPackages); } addFoundPackages(subpackage, foundPackages); } if (option_all) { Set foundPackages = new LinkedHashSet(); for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) { File sourceDir = (File)pit.next(); findPackages("", sourceDir, foundPackages); } addFoundPackages(null, foundPackages); for (Iterator packageIt = foundPackages.iterator(); packageIt.hasNext(); ) { String packageName = (String)packageIt.next(); if (null == packageName) { packageName = ""; } rootDoc.addSpecifiedPackageName(packageName); } } for (Iterator it = packageAndClasses.iterator(); it.hasNext();) { String classOrPackage = (String) it.next(); boolean foundSourceFile = false; if (classOrPackage.endsWith(".java")) { for (Iterator pit = option_sourcepath.iterator(); pit.hasNext() && !foundSourceFile; ) { File sourceDir = (File)pit.next(); File sourceFile = new File(sourceDir, classOrPackage); if (sourceFile.exists() && !sourceFile.isDirectory()) { rootDoc.addSpecifiedSourceFile(sourceFile); foundSourceFile = true; break; } } if (!foundSourceFile) { File sourceFile = new File(classOrPackage); if (sourceFile.exists() && !sourceFile.isDirectory()) { rootDoc.addSpecifiedSourceFile(sourceFile); foundSourceFile = true; } } } if (!foundSourceFile) { //--- Check for illegal name if (classOrPackage.startsWith(".") || classOrPackage.endsWith(".") || classOrPackage.indexOf("..") > 0 || !checkCharSet(classOrPackage, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) { throw new ParseException("Illegal class or package name '" + classOrPackage + "'"); } //--- Assemble absolute path to package String classOrPackageRelPath = classOrPackage.replace('.', File.separatorChar); //--- Create one file object each for a possible package directory // and a possible class file, and find out if they exist. List packageDirs = rootDoc.findSourceFiles(classOrPackageRelPath); List sourceFiles = rootDoc.findSourceFiles(classOrPackageRelPath + ".java"); boolean packageDirExists = !packageDirs.isEmpty(); boolean sourceFileExists = !sourceFiles.isEmpty(); //--- Complain if neither exists: not found if (!packageDirExists && !sourceFileExists) { reporter.printError("Class or package " + classOrPackage + " not found."); return false; } //--- Complain if both exist: ambigious else if (packageDirExists && sourceFileExists) { reporter.printError("Ambigious class/package name " + classOrPackage + "."); return false; } //--- Otherwise, if the package directory exists, it is a package else if (packageDirExists) { Iterator packageDirIt = packageDirs.iterator(); boolean packageDirFound = false; while (packageDirIt.hasNext()) { File packageDir = (File)packageDirIt.next(); if (packageDir.isDirectory()) { rootDoc.addSpecifiedPackageName(classOrPackage); packageDirFound = true; break; } } if (!packageDirFound) { reporter.printError("No suitable file or directory found for" + classOrPackage); return false; } } //--- Otherwise, emit error message else { reporter.printError("No sources files found for package " + classOrPackage); } } } //--- Complain if no packages or classes specified if (option_help) { usage(); return true; } //--- Validate custom options passed on command line // by asking the Doclet if they are OK. String[][] customOptionArr = (String[][]) options .toArray(new String[0][0]); if (validOptionsMethod != null && !((Boolean) validOptionsMethod.invoke(null, new Object[] { customOptionArr, reporter })).booleanValue()) { // Not ok: shutdown system. reporter.printNotice(STRING_TRY_GJDOC_HELP); return false; } if (!rootDoc.hasSpecifiedPackagesOrClasses()) { reporter.printError("No packages or classes specified."); reporter.printNotice(STRING_TRY_GJDOC_HELP); return false; } rootDoc.setOptions(customOptionArr); rootDoc.build(); //--- Bail out if no classes found if (0 == rootDoc.classes().length && 0 == rootDoc.specifiedPackages().length && 0 == rootDoc.specifiedClasses().length) { reporter.printError("No packages or classes found(!)."); return false; } //--- Our work is done, tidy up memory System.gc(); System.gc(); //--- Set flag indicating Phase II of documentation generation docletRunning = true; //--- Invoke the start method on the Doclet: produce output reporter.printNotice("Running doclet..."); TemporaryStore tstore = new TemporaryStore(Main.rootDoc); Thread.currentThread().setContextClassLoader(docletClass.getClassLoader()); if (null != startTempMethod) { startTempMethod.invoke(null, new Object[] { tstore }); } else { startMethod.invoke(null, new Object[] { tstore.getAndClear() }); } //--- Let the user know how many warnings/errors occured if (reporter.getWarningCount() > 0) { reporter.printNotice(reporter.getWarningCount() + " warnings"); } if (reporter.getErrorCount() > 0) { reporter.printNotice(reporter.getErrorCount() + " errors"); } System.gc(); //--- Done. return true; } catch (Exception e) { e.printStackTrace(); return false; } } private void addFoundPackages(String subpackage, Set foundPackages) { if (foundPackages.isEmpty()) { reporter.printWarning("No classes found under subpackage " + subpackage); } else { boolean onePackageAdded = false; for (Iterator rit = foundPackages.iterator(); rit.hasNext();) { String foundPackage = (String)rit.next(); boolean excludeThisPackage = false; for (Iterator eit = option_exclude.iterator(); eit.hasNext();) { String excludePackage = (String)eit.next(); if (foundPackage.equals(excludePackage) || foundPackage.startsWith(excludePackage + ":")) { excludeThisPackage = true; break; } } if (!excludeThisPackage) { rootDoc.addSpecifiedPackageName(foundPackage); onePackageAdded = true; } } if (!onePackageAdded) { if (null != subpackage) { reporter.printWarning("No non-excluded classes found under subpackage " + subpackage); } else { reporter.printWarning("No non-excluded classes found."); } } } } /** * Verify that the given file is a valid Java source file and that * it specifies the given package. */ private boolean isValidJavaFile(File file, String expectedPackage) { try { InputStream in = new BufferedInputStream(new FileInputStream(file)); int ch, prevChar = 0; final int STATE_DEFAULT = 0; final int STATE_COMMENT = 1; final int STATE_LINE_COMMENT = 2; int state = STATE_DEFAULT; StringBuffer word = new StringBuffer(); int wordIndex = 0; while ((ch = in.read()) >= 0) { String completeWord = null; switch (state) { case STATE_COMMENT: if (prevChar == '*' && ch == '/') { state = STATE_DEFAULT; } break; case STATE_LINE_COMMENT: if (ch == '\n') { state = STATE_DEFAULT; } break; case STATE_DEFAULT: if (prevChar == '/' && ch == '*') { word.deleteCharAt(word.length() - 1); if (word.length() > 0) { completeWord = word.toString(); word.setLength(0); } state = STATE_COMMENT; } else if (prevChar == '/' && ch == '/') { word.deleteCharAt(word.length() - 1); if (word.length() > 0) { completeWord = word.toString(); word.setLength(0); } state = STATE_LINE_COMMENT; } else if (" \t\r\n".indexOf(ch) >= 0) { if (word.length() > 0) { completeWord = word.toString(); word.setLength(0); } } else if (1 == wordIndex && ';' == ch) { if (word.length() > 0) { completeWord = word.toString(); word.setLength(0); } else { // empty package name in source file: "package ;" -> invalid source file in.close(); return false; } } else { word.append((char)ch); } break; } if (null != completeWord) { if (0 == wordIndex && !"package".equals(completeWord)) { in.close(); return "".equals(expectedPackage); } else if (1 == wordIndex) { in.close(); return expectedPackage.equals(completeWord); } ++ wordIndex; } prevChar = ch; } // no package or class found before end-of-file -> invalid source file in.close(); return false; } catch (IOException e) { reporter.printWarning("Could not examine file " + file + ": " + e); return false; } } /** * Recursively try to locate valid Java packages under the given * package specified by its name and its directory. Add the names * of all valid packages to the result list. */ private void findPackages(String subpackage, File packageDir, Set result) { File[] files = packageDir.listFiles(); if (null != files) { for (int i=0; i<files.length; ++i) { File file = files[i]; if (!file.isDirectory() && file.getName().endsWith(".java")) { if (isValidJavaFile(file, subpackage)) { if ("".equals(subpackage)) { result.add(null); } else { result.add(subpackage); } break; } } } for (int i=0; i<files.length; ++i) { File file = files[i]; if (file.isDirectory()) { String newSubpackage; if (null != subpackage && subpackage.length() > 0) { newSubpackage = subpackage + "." + file.getName(); } else { newSubpackage = file.getName(); } findPackages(newSubpackage, file, result); } } } } /** * */ private static boolean validOptions(String options[][], DocErrorReporter reporter) { boolean foundDocletOption = false; for (int i = 0; i < options.length; i++) { String[] opt = options[i]; if (opt[0].equalsIgnoreCase("-doclet")) { if (foundDocletOption) { reporter.printError("Only one -doclet option allowed."); return false; } else { foundDocletOption = true; } } } return true; } /** * Main entry point. This is the method called when gjdoc is invoked from the * command line. * * @param args * command line arguments */ public static void main(String[] args) { try { //--- Remember current time for profiling purposes Timer.setStartTime(); //--- Handle control to the Singleton instance of this class int result = instance.start(args); if (result < 0) { // fatal error System.exit(5); } else if (result > 0) { // errors encountered System.exit(1); } else { // success System.exit(0); } } catch (Exception e) { //--- unexpected error e.printStackTrace(); System.exit(1); } } /** * Parses command line arguments and subsequentially handles control to the * startDoclet() method * * @param args The command line parameters. */ public static int execute(String[] args) { try { int result = instance.start(args); if (result < 0) { // fatal error return 5; } else if (result > 0) { // errors encountered return 1; } else { // success return 0; } } catch (Exception e) { // unexpected error return 1; } } /** * @param programName Name of the program (for error messages). *disregarded* * @param args The command line parameters. * @returns The return code. */ public static int execute(String programName, String[] args) { return execute(args); } /** * @param programName Name of the program (for error messages). * @param defaultDocletClassName Fully qualified class name. * @param args The command line parameters. * @returns The return code. *//* public static int execute(String programName, String defaultDocletClassName, String[] args) { // not yet implemented }*/ /** * @param programName Name of the program (for error messages). * @param defaultDocletClassName Fully qualified class name. * @param args The command line parameters. * @returns The return code. *//* public static int execute(String programName, String defaultDocletClassName, String[] args) { // not yet implemented }*/ /** * @param programName Name of the program (for error messages). * @param errWriter PrintWriter to receive error messages. * @param warnWriter PrintWriter to receive error messages. * @param noticeWriter PrintWriter to receive error messages. * @param defaultDocletClassName Fully qualified class name. * @param args The command line parameters. * @returns The return code. *//* public static int execute(String programName, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter, String defaultDocletClassName, String[] args) { // not yet implemented }*/ /** * Parses command line arguments and subsequentially handles control to the * startDoclet() method * * @param args * Command line arguments, as passed to the main() method * @return {@code -1} in case of a fatal error (invalid arguments), * or the number of errors encountered. * @exception ParseException * FIXME * @exception IOException * if an IO problem occur */ public int start(String[] args) throws ParseException, IOException { //--- Collect unparsed arguments in array and resolve references // to external argument files. List arguments = new ArrayList(args.length); for (int i = 0; i < args.length; ++i) { if (!args[i].startsWith("@")) { arguments.add(args[i]); } else { FileReader reader = new FileReader(args[i].substring(1)); StreamTokenizer st = new StreamTokenizer(reader); st.resetSyntax(); st.wordChars('\u0000', '\uffff'); st.quoteChar('\"'); st.quoteChar('\''); st.whitespaceChars(' ', ' '); st.whitespaceChars('\t', '\t'); st.whitespaceChars('\r', '\r'); st.whitespaceChars('\n', '\n'); while (st.nextToken() != StreamTokenizer.TT_EOF) { arguments.add(st.sval); } } } //--- Initialize Map for option parsing initOptions(); //--- This will hold all options recognized by gjdoc itself // and their associated arguments. // Contains objects of type String[], where each entry // specifies an option along with its aguments. List options = new LinkedList(); //--- This will hold all command line tokens not recognized // to be part of a standard option. // These options are intended to be processed by the doclet // Contains objects of type String, where each entry is // one unrecognized token. List customOptions = new LinkedList(); rootDoc = new RootDocImpl(); reporter = rootDoc.getReporter(); //--- Iterate over all options given on the command line for (Iterator it = arguments.iterator(); it.hasNext();) { String arg = (String) it.next(); //--- Check if gjdoc recognizes this option as a standard option // and remember the options' argument count int optlen = optionLength(arg); //--- Argument count == 0 indicates that the option is not recognized. // Add it to the list of custom option tokens //--- Otherwise the option is recognized as a standard option. // if all required arguments are supplied. Create a new String // array for the option and its arguments, and store it // in the options array. if (optlen > 0) { String[] option = new String[optlen]; option[0] = arg; boolean optargs_ok = true; for (int j = 1; j < optlen && optargs_ok; ++j) { if (it.hasNext()) { option[j] = (String) it.next(); if (option[j].startsWith("-")) { optargs_ok = false; } } else { optargs_ok = false; } } if (optargs_ok) options.add(option); else { // If the option requires more arguments than given on the // command line, issue a fatal error reporter.printFatal("Missing value for option " + arg + "."); } } } //--- Create an array of String arrays from the dynamic array built above String[][] optionArr = (String[][]) options.toArray(new String[options .size()][0]); //--- Validate all options and issue warnings/errors if (validOptions(optionArr, rootDoc)) { //--- We got valid options; parse them and store the parsed values // in 'option_*' fields. readOptions(optionArr); //--- Show version and exit if requested by user if (option_showVersion) { System.out.println("gjdoc " + getGjdocVersion()); System.exit(0); } if (option_bootclasspath_specified) { reporter.printWarning("-bootclasspath ignored: not supported by" + " gjdoc wrapper script, or no wrapper script in use."); } // If we have an empty source path list, add the current directory ('.') if (option_sourcepath.size() == 0) option_sourcepath.add(new File(".")); //--- We have all information we need to start the doclet at this time if (null != option_encoding) { rootDoc.setSourceEncoding(option_encoding); } else { // be quiet about this for now: // reporter.printNotice("No encoding specified, using platform default: " + System.getProperty("file.encoding")); rootDoc.setSourceEncoding(System.getProperty("file.encoding")); } rootDoc.setSourcePath(option_sourcepath); //addJavaLangClasses(); if (!startDoclet(arguments)) { return -1; } } return reporter.getErrorCount(); } private void addJavaLangClasses() throws IOException { String resourceName = "/java.lang-classes-" + option_source + ".txt"; InputStream in = getClass().getResourceAsStream(resourceName); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; while ((line = reader.readLine()) != null) { String className = line.trim(); if (className.length() > 0) { ClassDocImpl classDoc = new ClassDocImpl(null, new PackageDocImpl("java.lang"), ProgramElementDocImpl.ACCESS_PUBLIC, false, false, null); classDoc.setClass(className); rootDoc.addClassDoc(classDoc); } } } /** * Helper class for parsing command line arguments. An instance of this class * represents a particular option accepted by gjdoc (e.g. '-sourcepath') along * with the number of expected arguments and behavior to parse the arguments. */ private abstract class OptionProcessor { /** * Number of arguments expected by this option. */ private int argCount; /** * Initializes this instance. * * @param argCount * number of arguments */ public OptionProcessor(int argCount) { this.argCount = argCount; } /** * Overridden by derived classes with behavior to parse the arguments * specified with this option. * * @param args * command line arguments */ abstract void process(String[] args); } /** * Maps option tags (e.g. '-sourcepath') to OptionProcessor objects. * Initialized only once by method initOptions(). FIXME: Rename to * 'optionProcessors'. */ private static Map options = null; /** * Initialize all OptionProcessor objects needed to scan/parse command line * options. This cannot be done in a static initializer block because * OptionProcessors need access to the Singleton instance of the Main class. */ private void initOptions() { options = new HashMap(); //--- Put one OptionProcessor object into the map // for each option recognized. options.put("-overview", new OptionProcessor(2) { void process(String[] args) { option_overview = args[0]; } }); options.put("-public", new OptionProcessor(1) { void process(String[] args) { option_coverage = COVERAGE_PUBLIC; } }); options.put("-protected", new OptionProcessor(1) { void process(String[] args) { option_coverage = COVERAGE_PROTECTED; } }); options.put("-package", new OptionProcessor(1) { void process(String[] args) { option_coverage = COVERAGE_PACKAGE; } }); options.put("-private", new OptionProcessor(1) { void process(String[] args) { option_coverage = COVERAGE_PRIVATE; } }); OptionProcessor helpProcessor = new OptionProcessor(1) { void process(String[] args) { option_help = true; } }; options.put("-help", helpProcessor); options.put("--help", helpProcessor); options.put("-doclet", new OptionProcessor(2) { void process(String[] args) { option_doclet = args[0]; } }); options.put("-docletpath", new OptionProcessor(2) { void process(String[] args) { option_docletpath = args[0]; } }); options.put("-nowarn", new OptionProcessor(1) { void process(String[] args) { option_nowarn = true; } }); options.put("-source", new OptionProcessor(2) { void process(String[] args) { option_source = args[0]; if (!"1.2".equals(option_source) && !"1.3".equals(option_source) && !"1.4".equals(option_source)) { throw new RuntimeException("Only he following values are currently" + " supported for option -source: 1.2, 1.3, 1.4."); } } }); OptionProcessor sourcePathProcessor = new OptionProcessor(2) { void process(String[] args) { Debug.log(1, "-sourcepath is '" + args[0] + "'"); for (StringTokenizer st = new StringTokenizer(args[0], File.pathSeparator); st.hasMoreTokens();) { String path = st.nextToken(); File file = new File(path); if (!(file.exists())) { throw new RuntimeException("The source path " + path + " does not exist."); } option_sourcepath.add(file); } } }; options.put("-s", sourcePathProcessor); options.put("-sourcepath", sourcePathProcessor); options.put("-subpackages", new OptionProcessor(2) { void process(String[] args) { StringTokenizer st = new StringTokenizer(args[0], ":"); while (st.hasMoreTokens()) { String packageName = st.nextToken(); if (packageName.startsWith(".") || packageName.endsWith(".") || packageName.indexOf("..") > 0 || !checkCharSet(packageName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) { throw new RuntimeException("Illegal package name '" + packageName + "'"); } option_subpackages.add(packageName); } } }); options.put("-exclude", new OptionProcessor(2) { void process(String[] args) { StringTokenizer st = new StringTokenizer(args[0], ":"); while (st.hasMoreTokens()) { String packageName = st.nextToken(); if (packageName.startsWith(".") || packageName.endsWith(".") || packageName.indexOf("..") > 0 || !checkCharSet(packageName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) { throw new RuntimeException("Illegal package name '" + packageName + "'"); } option_exclude.add(packageName); } } }); // TODO include other options here options.put("-verbose", new OptionProcessor(1) { void process(String[] args) { option_verbose = true; System.err.println("WARNING: Unsupported option -verbose ignored"); } }); options.put("-quiet", new OptionProcessor(1) { void process(String[] args) { reporter.setQuiet(true); } }); options.put("-locale", new OptionProcessor(2) { void process(String[] args) { String localeName = args[0]; String language = null; String country = null; String variant = null; StringTokenizer st = new StringTokenizer(localeName, "_"); if (st.hasMoreTokens()) { language = st.nextToken(); } if (st.hasMoreTokens()) { country = st.nextToken(); } if (st.hasMoreTokens()) { variant = st.nextToken(); } if (variant != null) { option_locale = new Locale(language, country, variant); } else if (country != null) { option_locale = new Locale(language, country); } else if (language != null) { option_locale = new Locale(language); } else { throw new RuntimeException("Illegal locale specification '" + localeName + "'"); } } }); options.put("-encoding", new OptionProcessor(2) { void process(String[] args) { option_encoding = args[0]; } }); options.put("-breakiterator", new OptionProcessor(1) { void process(String[] args) { option_breakiterator = true; } }); options.put("-licensetext", new OptionProcessor(1) { void process(String[] args) { option_licensetext = true; } }); options.put("-overview", new OptionProcessor(2) { void process(String[] args) { try { getRootDoc().setRawCommentText(RootDocImpl.readHtmlBody(new File(args[0]))); } catch (IOException e) { throw new RuntimeException("Cannot read file specified in option -overview: " + e.getMessage()); } } }); options.put("-classpath", new OptionProcessor(2) { void process(String[] args) { reporter.printWarning("-classpath option could not be passed to the VM. Faking it with "); reporter.printWarning(" System.setProperty(\"java.class.path\", \"" + args[0] + "\");"); System.setProperty("java.class.path", args[0]); } }); options.put("--version", new OptionProcessor(1) { void process(String[] args) { option_showVersion = true; } }); options.put("-bootclasspath", new OptionProcessor(1) { void process(String[] args) { option_bootclasspath_specified = true; } }); options.put("-all", new OptionProcessor(1) { void process(String[] args) { option_all = true; } }); options.put("-reflection", new OptionProcessor(1) { void process(String[] args) { option_reflection = true; } }); } /** * Determine how many arguments the given option requires. * * @param option * The name of the option without leading dash. */ private static int optionLength(String option) { OptionProcessor op = (OptionProcessor) options.get(option.toLowerCase()); if (op != null) return op.argCount; else return 0; } /** * Process all given options. Assumes that the options have been validated * before. * * @param optionArr * Each element is a series of Strings where [0] is the name of the * option and [1..n] are the arguments to the option. */ private void readOptions(String[][] optionArr) { //--- For each option, find the appropriate OptionProcessor // and call its process() method for (int i = 0; i < optionArr.length; ++i) { String[] opt = optionArr[i]; String[] args = new String[opt.length - 1]; System.arraycopy(opt, 1, args, 0, opt.length - 1); OptionProcessor op = (OptionProcessor) options.get(opt[0].toLowerCase()); op.process(args); } } /** * Print command line usage. */ private static void usage() { System.out .print("\n" + "USAGE: gjdoc [options] [packagenames] " + "[sourcefiles] [@files]\n\n" + " --version Show version information and exit\n" + " -all Process all source files found in the source path\n" + " -overview <file> Read overview documentation from HTML file\n" + " -public Include only public classes and members\n" + " -protected Include protected and public classes and members\n" + " This is the default\n" + " -package Include package/protected/public classes and members\n" + " -private Include all classes and members\n" + " -help, --help Show this information\n" + " -doclet <class> Doclet class to use for generating output\n" + " -docletpath <classpath> Specifies the search path for the doclet and\n" + " dependencies\n" + " -source <release> Provide source compatibility with specified\n" + " release (1.4 to handle assertion)\n" + " -sourcepath <pathlist> Where to look for source files\n" + " -s <pathlist> Alias for -sourcepath\n" + " -subpackages <spkglist> List of subpackages to recursively load\n" + " -exclude <pkglist> List of packages to exclude\n" + " -verbose Output messages about what Gjdoc is doing [ignored]\n" + " -quiet Do not print non-error and non-warning messages\n" + " -locale <name> Locale to be used, e.g. en_US or en_US_WIN\n" + " -encoding <name> Source file encoding name\n" + " -breakiterator Compute first sentence with BreakIterator\n" + " -classpath <pathlist> Set the path used for loading auxilliary classes\n" + "\n" + "Standard doclet options:\n" + " -d Set target directory\n" + " -use Includes the 'Use' page for each documented class\n" + " and package\n" + " -version Includes the '@version' tag\n" + " -author Includes the '@author' tag\n" + " -splitindex Splits the index file into multiple files\n" + " -windowtitle <text> Browser window title\n" + " -doctitle <text> Title near the top of the overview summary file\n" + " (HTML allowed)\n" + " -title <text> Title for this set of API documentation\n" + " (deprecated, -doctitle should be used instead)\n" + " -header <text> Text to include in the top navigation bar\n" + " (HTML allowed)\n" + " -footer <text> Text to include in the bottom navigation bar\n" + " (HTML allowed)\n" + " -bottom <text> Text to include at the bottom of each output file\n" + " (HTML allowed)\n" + " -link <extdoc URL> Link to external generated documentation at URL\n" + " -linkoffline <extdoc URL> <packagelistLoc>\n" + " Link to external generated documentation for\n" + " the specified package-list\n" + " -linksource Creates an HTML version of each source file\n" + " -group <groupheading> <packagepattern:packagepattern:...>\n" + " Separates packages on the overview page into groups\n" + " -nodeprecated Prevents the generation of any deprecated API\n" + " -nodeprecatedlist Prevents the generation of the file containing\n" + " the list of deprecated APIs and the link to the\n" + " navigation bar to that page\n" + " -nosince Omit the '@since' tag\n" + " -notree Do not generate the class/interface hierarchy page\n" + " -noindex Do not generate the index file\n" + " -nohelp Do not generate the help link\n" + " -nonavbar Do not generate the navbar, header and footer\n" + " -helpfile <filen> Path to an alternate help file\n" + " -stylesheetfile <file> Path to an alternate CSS stylesheet\n" + " -addstylesheet <file> Path to an additional CSS stylesheet\n" + " -serialwarn Complain about missing '@serial' tags [ignored]\n" + " -charset <IANACharset> Specifies the HTML charset\n" + " -docencoding <IANACharset>\n" + " Specifies the encoding of the generated HTML files\n" + " -tag <tagname>:Xaoptcmf:\"<taghead>\"\n" + " Enables gjdoc to interpret a custom tag\n" + " -taglet Adds a Taglet class to the map of taglets\n" + " -tagletpath Sets the CLASSPATH to load subsequent Taglets from\n" + " -docfilessubdirs Enables deep copy of 'doc-files' directories\n" + " -excludedocfilessubdir <name1:name2:...>\n" + " Excludes 'doc-files' subdirectories with a give name\n" + " -noqualifier all|<packagename1:packagename2:...>\n" + " Do never fully qualify given package names\n" + " -nocomment Suppress the entire comment body including the main\n" + " description and all tags, only generate declarations\n" + "\n" + "Gjdoc extension options:\n" + " -reflection Use reflection for resolving unqualified class names\n" + " -licensetext Include license text from source files\n" + " -validhtml Use valid HTML/XML names (breaks compatibility)\n" + " -baseurl <url> Hardwire the given base URL into generated pages\n" /** + " -genhtml Generate HTML code instead of XML code. This is the\n" + " default.\n" + " -geninfo Generate Info code instead of XML code.\n" + " -xslsheet <file> If specified, XML files will be written to a\n" + " temporary directory and transformed using the\n" + " given XSL sheet. The result of the transformation\n" + " is written to the output directory. Not required if\n" + " -genhtml or -geninfo has been specified.\n" + " -xmlonly Generate XML code only, do not generate HTML code.\n" + " -bottomnote HTML code to include at the bottom of each page.\n" + " -nofixhtml If not specified, heurestics will be applied to\n" + " fix broken HTML code in comments.\n" + " -nohtmlwarn Do not emit warnings when encountering broken HTML\n" + " code.\n" + " -noemailwarn Do not emit warnings when encountering strings like\n" + " <abc@foo.com>.\n" + " -indentstep <n> How many spaces to indent each tag level in\n" + " generated XML code.\n" + " -xsltdriver <class> Specifies the XSLT driver to use for transformation.\n" + " By default, xsltproc is used.\n" + " -postprocess <class> XmlDoclet postprocessor class to apply after XSL\n" + " transformation.\n" + " -compress Generated info pages will be Zip-compressed.\n" + " -workpath Specify a temporary directory to use.\n" + " -authormail <type> Specify handling of mail addresses in @author tags.\n" + " no-replace do not replace mail addresses (default).\n" + " mailto-name replace by <a>Real Name</a>.\n" + " name-mailto-address replace by Real Name (<a>abc@foo.com</a>).\n" + " name-mangled-address replace by Real Name (<a>abc AT foo DOT com</a>).\n" **/ ); } /** * The root of the gjdoc tool. * * @return all the options of the gjdoc application. */ public static RootDocImpl getRootDoc() { return rootDoc; } /** * Get the gjdoc singleton. * * @return the gjdoc instance. */ public static Main getInstance() { return instance; } /** * Is this access level covered? * * @param accessLevel * the access level we want to know if it is covered. * @return true if the access level is covered. */ public boolean includeAccessLevel(int accessLevel) { return coverageTemplates[option_coverage][accessLevel]; } /** * Is the doclet running? * * @return true if it's running */ public boolean isDocletRunning() { return docletRunning; } /** * Check the charset. Check that all the characters of the string 'toCheck' * and query if they exist in the 'charSet'. The order does not matter. The * number of times a character is in the variable does not matter. * * @param toCheck * the charset to check. * @param charSet * the reference charset * @return true if they match. */ public static boolean checkCharSet(String toCheck, String charSet) { for (int i = 0; i < toCheck.length(); ++i) { if (charSet.indexOf(toCheck.charAt(i)) < 0) return false; } return true; } /** * Makes the RootDoc eligible for the GC. */ public static void releaseRootDoc() { rootDoc.flush(); } /** * Return whether the -breakiterator option has been specified. */ public boolean isUseBreakIterator() { return this.option_breakiterator || !getLocale().getLanguage().equals(Locale.ENGLISH.getLanguage()); } /** * Return whether boilerplate license text should be copied. */ public boolean isCopyLicenseText() { return this.option_licensetext; } /** * Return the locale specified using the -locale option or the * default locale; */ public Locale getLocale() { return this.option_locale; } /** * Return the collator to use based on the specified -locale * option. If no collator can be found for the given locale, a * warning is emitted and the default collator is used instead. */ public Collator getCollator() { if (null == this.collator) { Locale locale = getLocale(); this.collator = Collator.getInstance(locale); Locale defaultLocale = Locale.getDefault(); if (null == this.collator && !defaultLocale.equals(locale)) { this.collator = Collator.getInstance(defaultLocale); if (null != this.collator) { reporter.printWarning("No collator found for locale " + locale.getDisplayName() + "; using collator for default locale " + defaultLocale.getDisplayName() + "."); } else { this.collator = Collator.getInstance(); reporter.printWarning("No collator found for specified locale " + locale.getDisplayName() + " or default locale " + defaultLocale.getDisplayName() + ": using default collator."); } } if (null == this.collator) { this.collator = Collator.getInstance(); reporter.printWarning("No collator found for locale " + locale.getDisplayName() + ": using default collator."); } } return this.collator; } public boolean isCacheRawComments() { return true; } public String getGjdocVersion() { if (null == gjdocVersion) { gjdocVersion = gnu.classpath.Configuration.CLASSPATH_VERSION; } return gjdocVersion; } public boolean isReflectionEnabled() { return this.option_reflection; } }