Home | History | Annotate | Download | only in jdiff
      1 package jdiff;
      2 
      3 import com.sun.javadoc.*;
      4 import com.sun.javadoc.ParameterizedType;
      5 import com.sun.javadoc.Type;
      6 
      7 import java.util.*;
      8 import java.io.*;
      9 import java.lang.reflect.*;
     10 
     11 /**
     12  * Converts a Javadoc RootDoc object into a representation in an
     13  * XML file.
     14  *
     15  * See the file LICENSE.txt for copyright details.
     16  * @author Matthew Doar, mdoar (at) pobox.com
     17  */
     18 public class RootDocToXML {
     19 
     20     /** Default constructor. */
     21     public RootDocToXML() {
     22     }
     23 
     24     /**
     25      * Write the XML representation of the API to a file.
     26      *
     27      * @param root  the RootDoc object passed by Javadoc
     28      * @return true if no problems encountered
     29      */
     30     public static boolean writeXML(RootDoc root) {
     31     	String tempFileName = outputFileName;
     32     	if (outputDirectory != null) {
     33 	    tempFileName = outputDirectory;
     34 	    if (!tempFileName.endsWith(JDiff.DIR_SEP))
     35 		tempFileName += JDiff.DIR_SEP;
     36 	    tempFileName += outputFileName;
     37     	}
     38 
     39         try {
     40             FileOutputStream fos = new FileOutputStream(tempFileName);
     41             outputFile = new PrintWriter(fos);
     42             System.out.println("JDiff: writing the API to file '" + tempFileName + "'...");
     43             if (root.specifiedPackages().length != 0 || root.specifiedClasses().length != 0) {
     44                 RootDocToXML apiWriter = new RootDocToXML();
     45                 apiWriter.emitXMLHeader();
     46                 apiWriter.logOptions();
     47                 apiWriter.processPackages(root);
     48                 apiWriter.emitXMLFooter();
     49             }
     50             outputFile.close();
     51         } catch(IOException e) {
     52             System.out.println("IO Error while attempting to create " + tempFileName);
     53             System.out.println("Error: " +  e.getMessage());
     54             System.exit(1);
     55         }
     56         // If validation is desired, write out the appropriate api.xsd file
     57         // in the same directory as the XML file.
     58         if (XMLToAPI.validateXML) {
     59             writeXSD();
     60         }
     61         return true;
     62     }
     63 
     64     /**
     65      * Write the XML Schema file used for validation.
     66      */
     67     public static void writeXSD() {
     68         String xsdFileName = outputFileName;
     69         if (outputDirectory == null) {
     70 	    int idx = xsdFileName.lastIndexOf('\\');
     71 	    int idx2 = xsdFileName.lastIndexOf('/');
     72 	    if (idx == -1 && idx2 == -1) {
     73 		xsdFileName = "";
     74 	    } else if (idx == -1 && idx2 != -1) {
     75 		xsdFileName = xsdFileName.substring(0, idx2);
     76 	    } else if (idx != -1  && idx2 == -1) {
     77 		xsdFileName = xsdFileName.substring(0, idx);
     78 	    } else if (idx != -1  && idx2 != -1) {
     79 		int max = idx2 > idx ? idx2 : idx;
     80 		xsdFileName = xsdFileName.substring(0, max);
     81 	    }
     82 	} else {
     83 	    xsdFileName = outputDirectory;
     84 	    if (!xsdFileName.endsWith(JDiff.DIR_SEP))
     85 		 xsdFileName += JDiff.DIR_SEP;
     86 	}
     87         xsdFileName += "api.xsd";
     88         try {
     89             FileOutputStream fos = new FileOutputStream(xsdFileName);
     90             PrintWriter xsdFile = new PrintWriter(fos);
     91             // The contents of the api.xsd file
     92             xsdFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
     93             xsdFile.println("<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
     94             xsdFile.println("");
     95             xsdFile.println("<xsd:annotation>");
     96             xsdFile.println("  <xsd:documentation>");
     97             xsdFile.println("  Schema for JDiff API representation.");
     98             xsdFile.println("  </xsd:documentation>");
     99             xsdFile.println("</xsd:annotation>");
    100             xsdFile.println();
    101             xsdFile.println("<xsd:element name=\"api\" type=\"apiType\"/>");
    102             xsdFile.println("");
    103             xsdFile.println("<xsd:complexType name=\"apiType\">");
    104             xsdFile.println("  <xsd:sequence>");
    105             xsdFile.println("    <xsd:element name=\"package\" type=\"packageType\" minOccurs='1' maxOccurs='unbounded'/>");
    106             xsdFile.println("  </xsd:sequence>");
    107             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    108             xsdFile.println("  <xsd:attribute name=\"jdversion\" type=\"xsd:string\"/>");
    109             xsdFile.println("</xsd:complexType>");
    110             xsdFile.println();
    111             xsdFile.println("<xsd:complexType name=\"packageType\">");
    112             xsdFile.println("  <xsd:sequence>");
    113             xsdFile.println("    <xsd:choice maxOccurs='unbounded'>");
    114             xsdFile.println("      <xsd:element name=\"class\" type=\"classType\"/>");
    115             xsdFile.println("      <xsd:element name=\"interface\" type=\"classType\"/>");
    116             xsdFile.println("    </xsd:choice>");
    117             xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
    118             xsdFile.println("  </xsd:sequence>");
    119             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    120             xsdFile.println("</xsd:complexType>");
    121             xsdFile.println();
    122             xsdFile.println("<xsd:complexType name=\"classType\">");
    123             xsdFile.println("  <xsd:sequence>");
    124             xsdFile.println("    <xsd:element name=\"implements\" type=\"interfaceTypeName\" minOccurs='0' maxOccurs='unbounded'/>");
    125             xsdFile.println("    <xsd:element name=\"constructor\" type=\"constructorType\" minOccurs='0' maxOccurs='unbounded'/>");
    126             xsdFile.println("    <xsd:element name=\"method\" type=\"methodType\" minOccurs='0' maxOccurs='unbounded'/>");
    127             xsdFile.println("    <xsd:element name=\"field\" type=\"fieldType\" minOccurs='0' maxOccurs='unbounded'/>");
    128             xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
    129             xsdFile.println("  </xsd:sequence>");
    130             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    131             xsdFile.println("  <xsd:attribute name=\"extends\" type=\"xsd:string\" use='optional'/>");
    132             xsdFile.println("  <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>");
    133             xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
    134             xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
    135             xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
    136             xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
    137             xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
    138             xsdFile.println("</xsd:complexType>");
    139             xsdFile.println();
    140             xsdFile.println("<xsd:complexType name=\"interfaceTypeName\">");
    141             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    142             xsdFile.println("</xsd:complexType>");
    143             xsdFile.println();
    144             xsdFile.println("<xsd:complexType name=\"constructorType\">");
    145             xsdFile.println("  <xsd:sequence>");
    146             xsdFile.println("    <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>");
    147             xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
    148             xsdFile.println("  </xsd:sequence>");
    149             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    150             xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\" use='optional'/>");
    151             xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
    152             xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
    153             xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
    154             xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
    155             xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
    156             xsdFile.println("</xsd:complexType>");
    157             xsdFile.println();
    158             xsdFile.println("<xsd:complexType name=\"paramsType\">");
    159             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    160             xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
    161             xsdFile.println("</xsd:complexType>");
    162             xsdFile.println();
    163             xsdFile.println("<xsd:complexType name=\"exceptionType\">");
    164             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    165             xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
    166             xsdFile.println("</xsd:complexType>");
    167             xsdFile.println();
    168             xsdFile.println("<xsd:complexType name=\"methodType\">");
    169             xsdFile.println("  <xsd:sequence>");
    170             xsdFile.println("    <xsd:element name=\"param\" type=\"paramsType\" minOccurs='0' maxOccurs='unbounded'/>");
    171             xsdFile.println("    <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>");
    172             xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
    173             xsdFile.println("  </xsd:sequence>");
    174             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    175             xsdFile.println("  <xsd:attribute name=\"return\" type=\"xsd:string\" use='optional'/>");
    176             xsdFile.println("  <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>");
    177             xsdFile.println("  <xsd:attribute name=\"native\" type=\"xsd:boolean\"/>");
    178             xsdFile.println("  <xsd:attribute name=\"synchronized\" type=\"xsd:boolean\"/>");
    179             xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
    180             xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
    181             xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
    182             xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
    183             xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
    184             xsdFile.println("</xsd:complexType>");
    185             xsdFile.println();
    186             xsdFile.println("<xsd:complexType name=\"fieldType\">");
    187             xsdFile.println("  <xsd:sequence>");
    188             xsdFile.println("    <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>");
    189             xsdFile.println("  </xsd:sequence>");
    190             xsdFile.println("  <xsd:attribute name=\"name\" type=\"xsd:string\"/>");
    191             xsdFile.println("  <xsd:attribute name=\"type\" type=\"xsd:string\"/>");
    192             xsdFile.println("  <xsd:attribute name=\"transient\" type=\"xsd:boolean\"/>");
    193             xsdFile.println("  <xsd:attribute name=\"volatile\" type=\"xsd:boolean\"/>");
    194             xsdFile.println("  <xsd:attribute name=\"value\" type=\"xsd:string\" use='optional'/>");
    195             xsdFile.println("  <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>");
    196             xsdFile.println("  <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>");
    197             xsdFile.println("  <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>");
    198             xsdFile.println("  <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>");
    199             xsdFile.println("  <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>");
    200             xsdFile.println("</xsd:complexType>");
    201             xsdFile.println();
    202             xsdFile.println("</xsd:schema>");
    203             xsdFile.close();
    204         } catch(IOException e) {
    205             System.out.println("IO Error while attempting to create " + xsdFileName);
    206             System.out.println("Error: " +  e.getMessage());
    207             System.exit(1);
    208         }
    209     }
    210 
    211     /**
    212      * Write the options which were used to generate this XML file
    213      * out as XML comments.
    214      */
    215     public void logOptions() {
    216         outputFile.print("<!-- ");
    217         outputFile.print(" Command line arguments = " + Options.cmdOptions);
    218         outputFile.println(" -->");
    219     }
    220 
    221     /**
    222      * Process each package and the classes/interfaces within it.
    223      *
    224      * @param pd  an array of PackageDoc objects
    225      */
    226     public void processPackages(RootDoc root) {
    227         PackageDoc[] specified_pd = root.specifiedPackages();
    228 	Map pdl = new TreeMap();
    229         for (int i = 0; specified_pd != null && i < specified_pd.length; i++) {
    230 	    pdl.put(specified_pd[i].name(), specified_pd[i]);
    231 	}
    232 
    233 	// Classes may be specified separately, so merge their packages into the
    234 	// list of specified packages.
    235         ClassDoc[] cd = root.specifiedClasses();
    236 	// This is lists of the specific classes to document
    237 	Map classesToUse = new HashMap();
    238         for (int i = 0; cd != null && i < cd.length; i++) {
    239 	    PackageDoc cpd = cd[i].containingPackage();
    240 	    if (cpd == null && !packagesOnly) {
    241 		// If the RootDoc object has been created from a jar file
    242 		// this duplicates classes, so we have to be able to disable it.
    243 		// TODO this is still null?
    244 		cpd = root.packageNamed("anonymous");
    245 	    }
    246             String pkgName = cpd.name();
    247             String className = cd[i].name();
    248 	    if (trace) System.out.println("Found package " + pkgName + " for class " + className);
    249 	    if (!pdl.containsKey(pkgName)) {
    250 		if (trace) System.out.println("Adding new package " + pkgName);
    251 		pdl.put(pkgName, cpd);
    252 	    }
    253 
    254 	    // Keep track of the specific classes to be used for this package
    255 	    List classes;
    256 	    if (classesToUse.containsKey(pkgName)) {
    257 		classes = (ArrayList) classesToUse.get(pkgName);
    258 	    } else {
    259 		classes = new ArrayList();
    260 	    }
    261 	    classes.add(cd[i]);
    262 	    classesToUse.put(pkgName, classes);
    263 	}
    264 
    265 	PackageDoc[] pd = (PackageDoc[]) pdl.values().toArray(new PackageDoc[0]);
    266         for (int i = 0; pd != null && i < pd.length; i++) {
    267             String pkgName = pd[i].name();
    268 
    269             // Check for an exclude tag in the package doc block, but not
    270 	    // in the package.htm[l] file.
    271             if (!shownElement(pd[i], null))
    272                 continue;
    273 
    274             if (trace) System.out.println("PROCESSING PACKAGE: " + pkgName);
    275             outputFile.println("<package name=\"" + pkgName + "\">");
    276 
    277             int tagCount = pd[i].tags().length;
    278             if (trace) System.out.println("#tags: " + tagCount);
    279 
    280             List classList;
    281 	    if (classesToUse.containsKey(pkgName)) {
    282 		// Use only the specified classes in the package
    283 		System.out.println("Using the specified classes");
    284 		classList = (ArrayList) classesToUse.get(pkgName);
    285 	    } else {
    286 		// Use all classes in the package
    287 		classList = new LinkedList(Arrays.asList(pd[i].allClasses()));
    288 	    }
    289             Collections.sort(classList);
    290             ClassDoc[] classes = new ClassDoc[classList.size()];
    291             classes = (ClassDoc[])classList.toArray(classes);
    292             processClasses(classes, pkgName);
    293 
    294             addPkgDocumentation(root, pd[i], 2);
    295 
    296             outputFile.println("</package>");
    297         }
    298     } // processPackages
    299 
    300     /**
    301      * Process classes and interfaces.
    302      *
    303      * @param cd An array of ClassDoc objects.
    304      */
    305     public void processClasses(ClassDoc[] cd, String pkgName) {
    306         if (cd.length == 0)
    307             return;
    308         if (trace) System.out.println("PROCESSING CLASSES, number=" + cd.length);
    309         for (int i = 0; i < cd.length; i++) {
    310             String className = cd[i].name();
    311             if (trace) System.out.println("PROCESSING CLASS/IFC: " + className);
    312             // Only save the shown elements
    313             if (!shownElement(cd[i], classVisibilityLevel))
    314                 continue;
    315             boolean isInterface = false;
    316             if (cd[i].isInterface())
    317                 isInterface = true;
    318             if (isInterface) {
    319                 outputFile.println("  <!-- start interface " + pkgName + "." + className + " -->");
    320                 outputFile.print("  <interface name=\"" + className + "\"");
    321             } else {
    322                 outputFile.println("  <!-- start class " + pkgName + "." + className + " -->");
    323                 outputFile.print("  <class name=\"" + className + "\"");
    324             }
    325             // Add attributes to the class element
    326             Type parent = cd[i].superclassType();
    327             if (parent != null)
    328                 outputFile.println(" extends=\"" + buildEmittableTypeString(parent) + "\"");
    329             outputFile.println("    abstract=\"" + cd[i].isAbstract() + "\"");
    330             addCommonModifiers(cd[i], 4);
    331             outputFile.println(">");
    332             // Process class members. (Treat inner classes as members.)
    333             processInterfaces(cd[i].interfaceTypes());
    334             processConstructors(cd[i].constructors());
    335             processMethods(cd[i], cd[i].methods());
    336             processFields(cd[i].fields());
    337 
    338             addDocumentation(cd[i], 4);
    339 
    340             if (isInterface) {
    341                 outputFile.println("  </interface>");
    342                 outputFile.println("  <!-- end interface " + pkgName + "." + className + " -->");
    343             } else {
    344                 outputFile.println("  </class>");
    345                 outputFile.println("  <!-- end class " + pkgName + "." + className + " -->");
    346             }
    347             // Inner classes have already been added.
    348             /*
    349               ClassDoc[] ic = cd[i].innerClasses();
    350               for (int k = 0; k < ic.length; k++) {
    351               System.out.println("Inner class " + k + ", name = " + ic[k].name());
    352               }
    353             */
    354         }//for
    355     }//processClasses()
    356 
    357     /**
    358      * Add qualifiers for the program element as attributes.
    359      *
    360      * @param ped The given program element.
    361      */
    362     public void addCommonModifiers(ProgramElementDoc ped, int indent) {
    363         addSourcePosition(ped, indent);
    364         // Static and final and visibility on one line
    365         for (int i = 0; i < indent; i++) outputFile.print(" ");
    366         outputFile.print("static=\"" + ped.isStatic() + "\"");
    367         outputFile.print(" final=\"" + ped.isFinal() + "\"");
    368         // Visibility
    369         String visibility = null;
    370         if (ped.isPublic())
    371             visibility = "public";
    372         else if (ped.isProtected())
    373             visibility = "protected";
    374         else if (ped.isPackagePrivate())
    375             visibility = "package";
    376         else if (ped.isPrivate())
    377             visibility = "private";
    378         outputFile.println(" visibility=\"" + visibility + "\"");
    379 
    380         // Deprecation on its own line
    381         for (int i = 0; i < indent; i++) outputFile.print(" ");
    382         boolean isDeprecated = false;
    383         Tag[] ta = ((Doc)ped).tags("deprecated");
    384         if (ta.length != 0) {
    385             isDeprecated = true;
    386         }
    387         if (ta.length > 1) {
    388             System.out.println("JDiff: warning: multiple @deprecated tags found in comments for " + ped.name() + ". Using the first one only.");
    389             System.out.println("Text is: " + ((Doc)ped).getRawCommentText());
    390         }
    391         if (isDeprecated) {
    392             String text = ta[0].text(); // Use only one @deprecated tag
    393             if (text != null && text.compareTo("") != 0) {
    394                 int idx = endOfFirstSentence(text);
    395                 if (idx == 0) {
    396                     // No useful comment
    397                     outputFile.print("deprecated=\"deprecated, no comment\"");
    398                 } else {
    399                     String fs = null;
    400                     if (idx == -1)
    401                         fs = text;
    402                     else
    403                         fs = text.substring(0, idx+1);
    404                     String st = API.hideHTMLTags(fs);
    405                     outputFile.print("deprecated=\"" + st + "\"");
    406                 }
    407             } else {
    408                 outputFile.print("deprecated=\"deprecated, no comment\"");
    409             }
    410         } else {
    411             outputFile.print("deprecated=\"not deprecated\"");
    412         }
    413 
    414     } //addQualifiers()
    415 
    416     /**
    417      * Insert the source code details, if available.
    418      *
    419      * @param ped The given program element.
    420      */
    421     public void addSourcePosition(ProgramElementDoc ped, int indent) {
    422         if (!addSrcInfo)
    423             return;
    424         if (JDiff.javaVersion.startsWith("1.1") ||
    425             JDiff.javaVersion.startsWith("1.2") ||
    426             JDiff.javaVersion.startsWith("1.3")) {
    427             return; // position() only appeared in J2SE1.4
    428         }
    429         try {
    430             // Could cache the method for improved performance
    431             Class c = ProgramElementDoc.class;
    432             Method m = c.getMethod("position", (Class[]) null);
    433             Object sp = m.invoke(ped, (Object[]) null);
    434             if (sp != null) {
    435                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    436                 outputFile.println("src=\"" + sp + "\"");
    437             }
    438         } catch (NoSuchMethodException e2) {
    439             System.err.println("Error: method \"position\" not found");
    440             e2.printStackTrace();
    441         } catch (IllegalAccessException e4) {
    442             System.err.println("Error: class not permitted to be instantiated");
    443             e4.printStackTrace();
    444         } catch (InvocationTargetException e5) {
    445             System.err.println("Error: method \"position\" could not be invoked");
    446             e5.printStackTrace();
    447         } catch (Exception e6) {
    448             System.err.println("Error: ");
    449             e6.printStackTrace();
    450         }
    451     }
    452 
    453     /**
    454      * Process the interfaces implemented by the class.
    455      *
    456      * @param ifaces An array of ClassDoc objects
    457      */
    458     public void processInterfaces(Type[] ifaces) {
    459         if (trace) System.out.println("PROCESSING INTERFACES, number=" + ifaces.length);
    460         for (int i = 0; i < ifaces.length; i++) {
    461             String ifaceName = buildEmittableTypeString(ifaces[i]);
    462             if (trace) System.out.println("PROCESSING INTERFACE: " + ifaceName);
    463             outputFile.println("    <implements name=\"" + ifaceName + "\"/>");
    464         }//for
    465     }//processInterfaces()
    466 
    467     /**
    468      * Process the constructors in the class.
    469      *
    470      * @param ct An array of ConstructorDoc objects
    471      */
    472     public void processConstructors(ConstructorDoc[] ct) {
    473         if (trace) System.out.println("PROCESSING CONSTRUCTORS, number=" + ct.length);
    474         for (int i = 0; i < ct.length; i++) {
    475             String ctorName = ct[i].name();
    476             if (trace) System.out.println("PROCESSING CONSTRUCTOR: " + ctorName);
    477             // Only save the shown elements
    478             if (!shownElement(ct[i], memberVisibilityLevel))
    479                 continue;
    480             outputFile.print("    <constructor name=\"" + ctorName + "\"");
    481 
    482             Parameter[] params = ct[i].parameters();
    483             boolean first = true;
    484             if (params.length != 0) {
    485                 outputFile.print(" type=\"");
    486                 for (int j = 0; j < params.length; j++) {
    487                     if (!first)
    488                         outputFile.print(", ");
    489                     emitType(params[j].type());
    490                     first = false;
    491                 }
    492                 outputFile.println("\"");
    493             } else
    494                 outputFile.println();
    495             addCommonModifiers(ct[i], 6);
    496             outputFile.println(">");
    497 
    498             // Generate the exception elements if any exceptions are thrown
    499             processExceptions(ct[i].thrownExceptions());
    500 
    501             addDocumentation(ct[i], 6);
    502 
    503             outputFile.println("    </constructor>");
    504         }//for
    505     }//processConstructors()
    506 
    507     /**
    508      * Process all exceptions thrown by a constructor or method.
    509      *
    510      * @param cd An array of ClassDoc objects
    511      */
    512     public void processExceptions(ClassDoc[] cd) {
    513         if (trace) System.out.println("PROCESSING EXCEPTIONS, number=" + cd.length);
    514         for (int i = 0; i < cd.length; i++) {
    515             String exceptionName = cd[i].name();
    516             if (trace) System.out.println("PROCESSING EXCEPTION: " + exceptionName);
    517             outputFile.print("      <exception name=\"" + exceptionName + "\" type=\"");
    518             emitType(cd[i]);
    519             outputFile.println("\"/>");
    520         }//for
    521     }//processExceptions()
    522 
    523     /**
    524      * Process the methods in the class.
    525      *
    526      * @param md An array of MethodDoc objects
    527      */
    528     public void processMethods(ClassDoc cd, MethodDoc[] md) {
    529         if (trace) System.out.println("PROCESSING " +cd.name()+" METHODS, number = " + md.length);
    530         for (int i = 0; i < md.length; i++) {
    531             String methodName = md[i].name();
    532             if (trace) System.out.println("PROCESSING METHOD: " + methodName);
    533             // Skip <init> and <clinit>
    534             if (methodName.startsWith("<"))
    535                 continue;
    536             // Only save the shown elements
    537             if (!shownElement(md[i], memberVisibilityLevel))
    538                 continue;
    539             outputFile.print("    <method name=\"" + methodName + "\"");
    540             com.sun.javadoc.Type retType = md[i].returnType();
    541             if (retType.qualifiedTypeName().compareTo("void") == 0) {
    542                 // Don't add a return attribute if the return type is void
    543                 outputFile.println();
    544             } else {
    545                 outputFile.print(" return=\"");
    546                 emitType(retType);
    547                 outputFile.println("\"");
    548             }
    549             outputFile.print("      abstract=\"" + md[i].isAbstract() + "\"");
    550             outputFile.print(" native=\"" + md[i].isNative() + "\"");
    551             outputFile.println(" synchronized=\"" + md[i].isSynchronized() + "\"");
    552             addCommonModifiers(md[i], 6);
    553             outputFile.println(">");
    554             // Generate the parameter elements, if any
    555             Parameter[] params = md[i].parameters();
    556             for (int j = 0; j < params.length; j++) {
    557                 outputFile.print("      <param name=\"" + params[j].name() + "\"");
    558                 outputFile.print(" type=\"");
    559                 emitType(params[j].type());
    560                 outputFile.println("\"/>");
    561             }
    562 
    563             // Generate the exception elements if any exceptions are thrown
    564             processExceptions(md[i].thrownExceptions());
    565 
    566             addDocumentation(md[i], 6);
    567 
    568             outputFile.println("    </method>");
    569         }//for
    570     }//processMethods()
    571 
    572     /**
    573      * Process the fields in the class.
    574      *
    575      * @param fd An array of FieldDoc objects
    576      */
    577     public void processFields(FieldDoc[] fd) {
    578         if (trace) System.out.println("PROCESSING FIELDS, number=" + fd.length);
    579         for (int i = 0; i < fd.length; i++) {
    580             String fieldName = fd[i].name();
    581             if (trace) System.out.println("PROCESSING FIELD: " + fieldName);
    582             // Only save the shown elements
    583             if (!shownElement(fd[i], memberVisibilityLevel))
    584                 continue;
    585             outputFile.print("    <field name=\"" + fieldName + "\"");
    586             outputFile.print(" type=\"");
    587             emitType(fd[i].type());
    588             outputFile.println("\"");
    589             outputFile.print("      transient=\"" + fd[i].isTransient() + "\"");
    590             outputFile.println(" volatile=\"" + fd[i].isVolatile() + "\"");
    591 /* JDK 1.4 and later */
    592 /*
    593             String value = fd[i].constantValueExpression();
    594             if (value != null)
    595                 outputFile.println(" value=\"" + value + "\"");
    596 */
    597             addCommonModifiers(fd[i], 6);
    598             outputFile.println(">");
    599 
    600             addDocumentation(fd[i], 6);
    601 
    602             outputFile.println("    </field>");
    603 
    604         }//for
    605     }//processFields()
    606 
    607     /**
    608      * Emit the type name. Removed any prefixed warnings about ambiguity.
    609      * The type maybe an array.
    610      *
    611      * @param type A Type object.
    612      */
    613     public void emitType(com.sun.javadoc.Type type) {
    614         String name = buildEmittableTypeString(type);
    615         if (name == null)
    616             return;
    617         outputFile.print(name);
    618     }
    619 
    620     /**
    621      * Build the emittable type name. The type may be an array and/or
    622      * a generic type.
    623      *
    624      * @param type A Type object
    625      * @return The emittable type name
    626      */
    627     private String buildEmittableTypeString(com.sun.javadoc.Type type) {
    628         if (type == null) {
    629     	    return null;
    630         }
    631       // type.toString() returns the fully qualified name of the type
    632       // including the dimension and the parameters we just need to
    633       // escape the generic parameters brackets so that the XML
    634       // generated is correct
    635       String name = type.toString().replaceAll("<", "&lt;").replaceAll(">", "&gt;");
    636       if (name.startsWith("<<ambiguous>>")) {
    637           name = name.substring(13);
    638       }
    639       return name;
    640     }
    641 
    642     /**
    643      * Emit the XML header.
    644      */
    645     public void emitXMLHeader() {
    646         outputFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
    647         outputFile.println("<!-- Generated by the JDiff Javadoc doclet -->");
    648         outputFile.println("<!-- (" + JDiff.jDiffLocation + ") -->");
    649         outputFile.println("<!-- on " + new Date() + " -->");
    650         outputFile.println();
    651 /* No need for this any longer, since doc block text is in an CDATA element
    652         outputFile.println("<!-- XML Schema is used, but XHTML transitional DTD is needed for nbsp -->");
    653         outputFile.println("<!-- entity definitions etc.-->");
    654         outputFile.println("<!DOCTYPE api");
    655         outputFile.println("     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
    656         outputFile.println("     \"" + baseURI + "/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
    657 */
    658         outputFile.println("<api");
    659         outputFile.println("  xmlns:xsi='" + baseURI + "/2001/XMLSchema-instance'");
    660         outputFile.println("  xsi:noNamespaceSchemaLocation='api.xsd'");
    661         outputFile.println("  name=\"" + apiIdentifier + "\"");
    662         outputFile.println("  jdversion=\"" + JDiff.version + "\">");
    663         outputFile.println();
    664     }
    665 
    666     /**
    667      * Emit the XML footer.
    668      */
    669     public void emitXMLFooter() {
    670         outputFile.println();
    671         outputFile.println("</api>");
    672     }
    673 
    674     /**
    675      * Determine if the program element is shown, according to the given
    676      * level of visibility.
    677      *
    678      * @param ped The given program element.
    679      * @param visLevel The desired visibility level; "public", "protected",
    680      *   "package" or "private". If null, only check for an exclude tag.
    681      * @return boolean Set if this element is shown.
    682      */
    683     public boolean shownElement(Doc doc, String visLevel) {
    684         // If a doc block contains @exclude or a similar such tag,
    685         // then don't display it.
    686 	if (doExclude && excludeTag != null && doc != null) {
    687             String rct = doc.getRawCommentText();
    688             if (rct != null && rct.indexOf(excludeTag) != -1) {
    689                 return false;
    690 	    }
    691 	}
    692 	if (visLevel == null) {
    693 	    return true;
    694 	}
    695 	ProgramElementDoc ped = null;
    696 	if (doc instanceof ProgramElementDoc) {
    697 	    ped = (ProgramElementDoc)doc;
    698 	}
    699         if (visLevel.compareTo("private") == 0)
    700             return true;
    701         // Show all that is not private
    702         if (visLevel.compareTo("package") == 0)
    703             return !ped.isPrivate();
    704         // Show all that is not private or package
    705         if (visLevel.compareTo("protected") == 0)
    706             return !(ped.isPrivate() || ped.isPackagePrivate());
    707         // Show all that is not private or package or protected,
    708         // i.e. all that is public
    709         if (visLevel.compareTo("public") == 0)
    710             return ped.isPublic();
    711         return false;
    712     } //shownElement()
    713 
    714     /**
    715      * Strip out non-printing characters, replacing them with a character
    716      * which will not change where the end of the first sentence is found.
    717      * This character is the hash mark, '&#035;'.
    718      */
    719     public String stripNonPrintingChars(String s, Doc doc) {
    720         if (!stripNonPrintables)
    721             return s;
    722         char[] sa = s.toCharArray();
    723         for (int i = 0; i < sa.length; i++) {
    724             char c = sa[i];
    725             // TODO still have an issue with Unicode: 0xfc in java.lang.String.toUpperCase comments
    726 //            if (Character.isDefined(c))
    727             if (Character.isLetterOrDigit(c))
    728                 continue;
    729             // There must be a better way that is still platform independent!
    730             if (c == ' ' ||
    731                 c == '.' ||
    732                 c == ',' ||
    733                 c == '\r' ||
    734                 c == '\t' ||
    735                 c == '\n' ||
    736                 c == '!' ||
    737                 c == '?' ||
    738                 c == ';' ||
    739                 c == ':' ||
    740                 c == '[' ||
    741                 c == ']' ||
    742                 c == '(' ||
    743                 c == ')' ||
    744                 c == '~' ||
    745                 c == '@' ||
    746                 c == '#' ||
    747                 c == '$' ||
    748                 c == '%' ||
    749                 c == '^' ||
    750                 c == '&' ||
    751                 c == '*' ||
    752                 c == '-' ||
    753                 c == '=' ||
    754                 c == '+' ||
    755                 c == '_' ||
    756                 c == '|' ||
    757                 c == '\\' ||
    758                 c == '/' ||
    759                 c == '\'' ||
    760                 c == '}' ||
    761                 c == '{' ||
    762                 c == '"' ||
    763                 c == '<' ||
    764                 c == '>' ||
    765                 c == '`'
    766                 )
    767                 continue;
    768 /* Doesn't seem to return the expected values?
    769             int val = Character.getNumericValue(c);
    770 //            if (s.indexOf("which is also a test for non-printable") != -1)
    771 //                System.out.println("** Char " + i + "[" + c + "], val =" + val); //DEBUG
    772             // Ranges from http://www.unicode.org/unicode/reports/tr20/
    773             // Should really replace 0x2028 and  0x2029 with <br/>
    774             if (val == 0x0 ||
    775                 inRange(val, 0x2028, 0x2029) ||
    776                 inRange(val, 0x202A, 0x202E) ||
    777                 inRange(val, 0x206A, 0x206F) ||
    778                 inRange(val, 0xFFF9, 0xFFFC) ||
    779                 inRange(val, 0xE0000, 0xE007F)) {
    780                 if (trace) {
    781                     System.out.println("Warning: changed non-printing character  " + sa[i] + " in " + doc.name());
    782                 }
    783                 sa[i] = '#';
    784             }
    785 */
    786             // Replace the non-printable character with a printable character
    787             // which does not change the end of the first sentence
    788             sa[i] = '#';
    789         }
    790         return new String(sa);
    791     }
    792 
    793     /** Return true if val is in the range [min|max], inclusive. */
    794     public boolean inRange(int val, int min, int max) {
    795         if (val < min)
    796             return false;
    797         if (val > max)
    798             return false;
    799         return true;
    800     }
    801 
    802     /**
    803      * Add at least the first sentence from a doc block to the API. This is
    804      * used by the report generator if no comment is provided.
    805      * Need to make sure that HTML tags are not confused with XML tags.
    806      * This could be done by stuffing the &lt; character to another string
    807      * or by handling HTML in the parser. This second option seems neater. Note that
    808      * XML expects all element tags to have either a closing "/>" or a matching
    809      * end element tag. Due to the difficulties of converting incorrect HTML
    810      * to XHTML, the first option is used.
    811      */
    812     public void addDocumentation(ProgramElementDoc ped, int indent) {
    813         String rct = ((Doc)ped).getRawCommentText();
    814         if (rct != null) {
    815             rct = stripNonPrintingChars(rct, (Doc)ped);
    816             rct = rct.trim();
    817             if (rct.compareTo("") != 0 &&
    818                 rct.indexOf(Comments.placeHolderText) == -1 &&
    819                 rct.indexOf("InsertOtherCommentsHere") == -1) {
    820                 int idx = endOfFirstSentence(rct);
    821                 if (idx == 0)
    822                     return;
    823                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    824                 outputFile.println("<doc>");
    825                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    826                 String firstSentence = null;
    827                 if (idx == -1)
    828                     firstSentence = rct;
    829                 else
    830                     firstSentence = rct.substring(0, idx+1);
    831                 boolean checkForAts = false;
    832                 if (checkForAts && firstSentence.indexOf("@") != -1 &&
    833                     firstSentence.indexOf("@link") == -1) {
    834                     System.out.println("Warning: @ tag seen in comment: " +
    835                                        firstSentence);
    836                 }
    837                 String firstSentenceNoTags = API.stuffHTMLTags(firstSentence);
    838                 outputFile.println(firstSentenceNoTags);
    839                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    840                 outputFile.println("</doc>");
    841             }
    842         }
    843     }
    844 
    845     /**
    846      * Add at least the first sentence from a doc block for a package to the API. This is
    847      * used by the report generator if no comment is provided.
    848      * The default source tree may not include the package.html files, so
    849      * this may be unavailable in many cases.
    850      * Need to make sure that HTML tags are not confused with XML tags.
    851      * This could be done by stuffing the &lt; character to another string
    852      * or by handling HTML in the parser. This second option is neater. Note that
    853      * XML expects all element tags to have either a closing "/>" or a matching
    854      * end element tag.  Due to the difficulties of converting incorrect HTML
    855      * to XHTML, the first option is used.
    856      */
    857     public void addPkgDocumentation(RootDoc root, PackageDoc pd, int indent) {
    858         String rct = null;
    859         String filename = pd.name();
    860         try {
    861             // See if the source path was specified as part of the
    862             // options and prepend it if it was.
    863             String srcLocation = null;
    864             String[][] options = root.options();
    865             for (int opt = 0; opt < options.length; opt++) {
    866                 if ((options[opt][0]).compareTo("-sourcepath") == 0) {
    867                     srcLocation = options[opt][1];
    868                     break;
    869                 }
    870             }
    871             filename = filename.replace('.', JDiff.DIR_SEP.charAt(0));
    872             if (srcLocation != null) {
    873                 // Make a relative location absolute
    874                 if (srcLocation.startsWith("..")) {
    875                     String curDir = System.getProperty("user.dir");
    876                     while (srcLocation.startsWith("..")) {
    877                         srcLocation = srcLocation.substring(3);
    878                         int idx = curDir.lastIndexOf(JDiff.DIR_SEP);
    879                         curDir = curDir.substring(0, idx+1);
    880                     }
    881                     srcLocation = curDir + srcLocation;
    882                 }
    883                 filename = srcLocation + JDiff.DIR_SEP + filename;
    884             }
    885             // Try both ".htm" and ".html"
    886             filename += JDiff.DIR_SEP + "package.htm";
    887             File f2 = new File(filename);
    888             if (!f2.exists()) {
    889                 filename += "l";
    890             }
    891             FileInputStream f = new FileInputStream(filename);
    892             BufferedReader d = new BufferedReader(new InputStreamReader(f));
    893             String str = d.readLine();
    894  	    // Ignore everything except the lines between <body> elements
    895 	    boolean inBody = false;
    896 	    while(str != null) {
    897                 if (!inBody) {
    898 		    if (str.toLowerCase().trim().startsWith("<body")) {
    899 			inBody = true;
    900 		    }
    901 		    str = d.readLine(); // Get the next line
    902 		    continue; // Ignore the line
    903 		} else {
    904 		    if (str.toLowerCase().trim().startsWith("</body")) {
    905 			inBody = false;
    906 			continue; // Ignore the line
    907 		    }
    908 		}
    909                 if (rct == null)
    910                     rct = str + "\n";
    911                 else
    912                     rct += str + "\n";
    913                 str = d.readLine();
    914             }
    915         }  catch(java.io.FileNotFoundException e) {
    916             // If it doesn't exist, that's fine
    917             if (trace)
    918                 System.out.println("No package level documentation file at '" + filename + "'");
    919         } catch(java.io.IOException e) {
    920             System.out.println("Error reading file \"" + filename + "\": " + e.getMessage());
    921             System.exit(5);
    922         }
    923         if (rct != null) {
    924             rct = stripNonPrintingChars(rct, (Doc)pd);
    925             rct = rct.trim();
    926             if (rct.compareTo("") != 0 &&
    927                 rct.indexOf(Comments.placeHolderText) == -1 &&
    928                 rct.indexOf("InsertOtherCommentsHere") == -1) {
    929                 int idx = endOfFirstSentence(rct);
    930                 if (idx == 0)
    931                     return;
    932                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    933                 outputFile.println("<doc>");
    934                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    935                 String firstSentence = null;
    936                 if (idx == -1)
    937                     firstSentence = rct;
    938                 else
    939                     firstSentence = rct.substring(0, idx+1);
    940                 String firstSentenceNoTags = API.stuffHTMLTags(firstSentence);
    941                 outputFile.println(firstSentenceNoTags);
    942                 for (int i = 0; i < indent; i++) outputFile.print(" ");
    943                 outputFile.println("</doc>");
    944             }
    945         }
    946     }
    947 
    948     /**
    949      * Find the index of the end of the first sentence in the given text,
    950      * when writing out to an XML file.
    951      * This is an extended version of the algorithm used by the DocCheck
    952      * Javadoc doclet. It checks for @tags too.
    953      *
    954      * @param text The text to be searched.
    955      * @return The index of the end of the first sentence. If there is no
    956      *         end, return -1. If there is no useful text, return 0.
    957      *         If the whole doc block comment is wanted (default), return -1.
    958      */
    959     public static int endOfFirstSentence(String text) {
    960         return endOfFirstSentence(text, true);
    961     }
    962 
    963     /**
    964      * Find the index of the end of the first sentence in the given text.
    965      * This is an extended version of the algorithm used by the DocCheck
    966      * Javadoc doclet. It checks for &#064;tags too.
    967      *
    968      * @param text The text to be searched.
    969      * @param writingToXML Set to true when writing out XML.
    970      * @return The index of the end of the first sentence. If there is no
    971      *         end, return -1. If there is no useful text, return 0.
    972      *         If the whole doc block comment is wanted (default), return -1.
    973      */
    974     public static int endOfFirstSentence(String text, boolean writingToXML) {
    975         if (saveAllDocs && writingToXML)
    976             return -1;
    977 	int textLen = text.length();
    978 	if (textLen == 0)
    979 	    return 0;
    980         int index = -1;
    981         // Handle some special cases
    982         int fromindex = 0;
    983         int ellipsis = text.indexOf(". . ."); // Handles one instance of this
    984         if (ellipsis != -1)
    985             fromindex = ellipsis + 5;
    986         // If the first non-whitespace character is an @, go beyond it
    987         int i = 0;
    988         while (i < textLen && text.charAt(i) == ' ') {
    989             i++;
    990         }
    991         if (text.charAt(i) == '@' && fromindex < textLen-1)
    992             fromindex = i + 1;
    993         // Use the brute force approach.
    994         index = minIndex(index, text.indexOf("? ", fromindex));
    995         index = minIndex(index, text.indexOf("?\t", fromindex));
    996         index = minIndex(index, text.indexOf("?\n", fromindex));
    997         index = minIndex(index, text.indexOf("?\r", fromindex));
    998         index = minIndex(index, text.indexOf("?\f", fromindex));
    999         index = minIndex(index, text.indexOf("! ", fromindex));
   1000         index = minIndex(index, text.indexOf("!\t", fromindex));
   1001         index = minIndex(index, text.indexOf("!\n", fromindex));
   1002         index = minIndex(index, text.indexOf("!\r", fromindex));
   1003         index = minIndex(index, text.indexOf("!\f", fromindex));
   1004         index = minIndex(index, text.indexOf(". ", fromindex));
   1005         index = minIndex(index, text.indexOf(".\t", fromindex));
   1006         index = minIndex(index, text.indexOf(".\n", fromindex));
   1007         index = minIndex(index, text.indexOf(".\r", fromindex));
   1008         index = minIndex(index, text.indexOf(".\f", fromindex));
   1009         index = minIndex(index, text.indexOf("@param", fromindex));
   1010         index = minIndex(index, text.indexOf("@return", fromindex));
   1011         index = minIndex(index, text.indexOf("@throw", fromindex));
   1012         index = minIndex(index, text.indexOf("@serial", fromindex));
   1013         index = minIndex(index, text.indexOf("@exception", fromindex));
   1014         index = minIndex(index, text.indexOf("@deprecate", fromindex));
   1015         index = minIndex(index, text.indexOf("@author", fromindex));
   1016         index = minIndex(index, text.indexOf("@since", fromindex));
   1017         index = minIndex(index, text.indexOf("@see", fromindex));
   1018         index = minIndex(index, text.indexOf("@version", fromindex));
   1019         if (doExclude && excludeTag != null)
   1020             index = minIndex(index, text.indexOf(excludeTag));
   1021         index = minIndex(index, text.indexOf("@vtexclude", fromindex));
   1022         index = minIndex(index, text.indexOf("@vtinclude", fromindex));
   1023         index = minIndex(index, text.indexOf("<p>", 2)); // Not at start
   1024         index = minIndex(index, text.indexOf("<P>", 2)); // Not at start
   1025         index = minIndex(index, text.indexOf("<blockquote", 2));  // Not at start
   1026         index = minIndex(index, text.indexOf("<pre", fromindex)); // May contain anything!
   1027         // Avoid the char at the start of a tag in some cases
   1028         if (index != -1 &&
   1029             (text.charAt(index) == '@' || text.charAt(index) == '<')) {
   1030             if (index != 0)
   1031                 index--;
   1032         }
   1033 
   1034 /* Not used for jdiff, since tags are explicitly checked for above.
   1035         // Look for a sentence terminated by an HTML tag.
   1036         index = minIndex(index, text.indexOf(".<", fromindex));
   1037         if (index == -1) {
   1038             // If period-whitespace etc was not found, check to see if
   1039             // last character is a period,
   1040             int endIndex = text.length()-1;
   1041             if (text.charAt(endIndex) == '.' ||
   1042                 text.charAt(endIndex) == '?' ||
   1043                 text.charAt(endIndex) == '!')
   1044                 index = endIndex;
   1045         }
   1046 */
   1047         return index;
   1048     }
   1049 
   1050     /**
   1051      * Return the minimum of two indexes if > -1, and return -1
   1052      * only if both indexes = -1.
   1053      * @param i an int index
   1054      * @param j an int index
   1055      * @return an int equal to the minimum index > -1, or -1
   1056      */
   1057     public static int minIndex(int i, int j) {
   1058         if (i == -1) return j;
   1059         if (j == -1) return i;
   1060         return Math.min(i,j);
   1061     }
   1062 
   1063     /**
   1064      * The name of the file where the XML representing the API will be
   1065      * stored.
   1066      */
   1067     public static String outputFileName = null;
   1068 
   1069     /**
   1070      * The identifier of the API being written out in XML, e.g.
   1071      * &quotSuperProduct 1.3&quot;.
   1072      */
   1073     public static String apiIdentifier = null;
   1074 
   1075     /**
   1076      * The file where the XML representing the API will be stored.
   1077      */
   1078     private static PrintWriter outputFile = null;
   1079 
   1080     /**
   1081      * The name of the directory where the XML representing the API will be
   1082      * stored.
   1083      */
   1084     public static String outputDirectory = null;
   1085 
   1086     /**
   1087      * Do not display a class  with a lower level of visibility than this.
   1088      * Default is to display all public and protected classes.
   1089      */
   1090     public static String classVisibilityLevel = "protected";
   1091 
   1092     /**
   1093      * Do not display a member with a lower level of visibility than this.
   1094      * Default is to display all public and protected members
   1095      * (constructors, methods, fields).
   1096      */
   1097     public static String memberVisibilityLevel = "protected";
   1098 
   1099     /**
   1100      * If set, then save the entire contents of a doc block comment in the
   1101      * API file. If not set, then just save the first sentence. Default is
   1102      * that this is set.
   1103      */
   1104     public static boolean saveAllDocs = true;
   1105 
   1106     /**
   1107      * If set, exclude program elements marked with whatever the exclude tag
   1108      * is specified as, e.g. "@exclude".
   1109      */
   1110     public static boolean doExclude = false;
   1111 
   1112     /**
   1113      * Exclude program elements marked with this String, e.g. "@exclude".
   1114      */
   1115     public static String excludeTag = null;
   1116 
   1117     /**
   1118      * The base URI for locating necessary DTDs and Schemas. By default, this
   1119      * is "http://www.w3.org". A typical value to use local copies of DTD files
   1120      * might be "file:///C:/jdiff/lib"
   1121      */
   1122     public static String baseURI = "http://www.w3.org";
   1123 
   1124     /**
   1125      * If set, then strip out non-printing characters from documentation.
   1126      * Default is that this is set.
   1127      */
   1128     static boolean stripNonPrintables = true;
   1129 
   1130     /**
   1131      * If set, then add the information about the source file and line number
   1132      * which is available in J2SE1.4. Default is that this is not set.
   1133      */
   1134     static boolean addSrcInfo = false;
   1135 
   1136     /**
   1137      * If set, scan classes with no packages.
   1138      * If the source is  a jar file this may duplicates classes, so
   1139      * disable it using the -packagesonly option. Default is that this is
   1140      * not set.
   1141      */
   1142     static boolean packagesOnly = false;
   1143 
   1144     /** Set to enable increased logging verbosity for debugging. */
   1145     private static boolean trace = false;
   1146 
   1147 } //RootDocToXML
   1148