/*
* THIS IS FREE SOFTWARE.
* Permission to use, copy, modify, and distribute this software and documentation
* in all settings is hereby granted, provided that NO FEE is charged for this
* software and provided that this copyright notice appears in all copies of any
* software which is or includes a copy or modification of this software. In all
* advertising materials, documentation, and publications mentioning features or
* use of this software you must credit the author.
*
* JACK PERDUE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* OR NON-INFRINGEMENT. JACK PERDUE SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY THE USER AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
* Developed by Jack Perdue (a.k.a. Silicon Slick) - si_slick@cy-net.net
* Copyright (c) 1998 Silicon Slick's Software, Supplies and Support Services
* All Rights Reserved
*/
import java.io.*;
import java.util.StringTokenizer;
/**
* Adds javadoc comment templates to source by using output of
* iDoc by Reto Kramer.
* Currently adds class/interface/variable/method descriptor templates,
* method parameter templates and method return value templates.
* Additionally generates javadoc comments indicating obsolete
* and nonjavadoc tags. See the variable
* unjavadocumentedvariablefortesting
* and the method testAddJavaDoc
* below for an example.
*
* Typical usage is:
*
* java iDoc.Tools -s -n -t %classname%.java >%classname%.idoc
* java AddJavaDoc %classname%.idoc %classname%.java [%header_file%]
*
*
* The output (source with javadoc templates) PROVIDED NOTHING BAD HAPPENS is
* put into %classname%.jdoc. I strongly recommend verification (a compile
* and run of javadoc should be sufficient) before toasting the original.
*
* If you run it on this class, it should look something like:
*
* C:\myJava>java iDoc.Tool -s -n -t AddJavaDoc.java >AddJavaDoc.idoc
* C:\myJava>java AddJavaDoc AddJavaDoc.idoc AddJavaDoc.java
* 0 306 iDoc.Variable Title
* 1 311 NONJAVADOC
* 2 311 OBSOLETE iDoc.Method params obsoleteparm
* 3 311 iDoc.Method Title
* 4 311 iDoc.Method params missingparm returns
*
* optionally
*
* C:\myJava>copy AddJavaDoc.jdoc t.java
* C:\myJava>javadoc -private -author -version -notree t.java
*
* will generate AddJavaDoc.html which will look very much like what
* you are reading now.
*
* VERIFY THE .JDOC BEFORE COPYING BACK TO THE .JAVA --
* I think this code is correct for now, but iDoc could change or
* an exception could happen and if you didn't verify it with
* at least a compile and a run of javadoc then you will
* lose your original source when copying the .jdoc to .java.
* Backups are always good too.
*
* It should System.exit(1) if it encounters a problem, and you can test
* this in the shell (eg. IF ERRORLEVEL 1 in DOS) to see if it completed
* successfully. Again, there are no guarantees -- keep backups of your source.
*
* Just as an example, here is the .BAT file I use.
*
* java iDoc.Tool -s -n -t %1.java >%1.idoc
* if errorlevel 1 goto :errorexit
* java AddJavaDoc %1.idoc %1.java c:\myjava\freeheader.txt
* if errorlevel 1 goto :errorexit
* copy %1.java %1.jbak
* if errorlevel 1 goto :errorexit
* copy %1.jdoc %1.java
* echo Completed...
* goto :exit
* :errorexit
* echo ERROR!!!
* :exit
* echo exiting.
*
* Obviously, I make backups of the source before running it (in addition to
* the one it makes) JUST IN CASE.
*
* Ideally, the source is available with this
* page by clicking on "the source".
*
*
Be sure to check AddJavaDoc's "home page" at
* http://www.cs.tamu.edu/people/jkp2866/java/AddJavaDoc/AddJavaDoc.html for updates.
*
* Revisions:
*
* - 06JUL98-jkp - updated to handle iDoc scanner exceptions and tabbed indentation
*
- 08JUL98-jkp - added interface support. can also now error on "/***" which I
* use a lot in C to denote major code blocks but causes all kinds of problems for iDoc
* when following lines don't begin with "*" (iDoc thinks, quite rightly, that
* it is in a javadoc comment) -- this feature is disabled by default.
*
- 13JUL98-jkp - updated link to iDoc 0.2b3. I haven't done any testing with
* 0.2b3 yet, but it looks like the output is exactly the same as 0.1b so I
* don't expect it to cause problems. If it does, try using
* v0.1b.
*
* @author Jack Perdue j-perdue@tamu.edu si_slick@cy-net.net
* @version 0.0004 13 Jul 1998
**/
public class AddJavaDoc {
/**
* Error file size limit
**/
static int MAXREADFORMARK = 128 * 1024;
/**
* maximum number of parameters a method can have
**/
static int MAXPARAMS = 20;
/**
* code for iDoc unlabeled class error
**/
final static int CLASSTITLE = 1;
/**
* code for iDoc unlabeled interface error
**/
final static int INTERFACETITLE = 2;
/**
* code for iDoc unlabeled variable error
**/
final static int VARIABLETITLE = 3;
/**
* code for iDoc unlabeled method error
**/
final static int METHODTITLE = 4;
/**
* code for iDoc method parameters error
**/
final static int METHODPARAMVOID = 11;
/**
* code for iDoc method parameters and return error
**/
final static int METHODPARAMRETURN = 12;
/**
* code for iDoc non-javadoc comment error
**/
final static int NONJAVADOC = 21;
/**
* code for iDoc obsolete parameter tag error
**/
final static int OBSOLETETAG = 22;
/**
* indicates user needs to provide info for javadoc
**/
static String FILL = "+XX+";
/**
* indicates user needs to service a parameter tag
**/
static String FILLOBSOLETETAG = "OBSOLETETAG";
/**
* indicates user needs to service some unrecognized javadoc comments
**/
static String FILLNONJAVADOC = "NONJAVADOC";
/**
* iDoc Scanner exception tag
**/
static String IDOCSCANNEREXCEPTIONTAG = "Scanner exception";
/**
* iDoc class tag
**/
static String IDOCCLASSTAG = "iDoc.Class";
/**
* iDoc interface tag
**/
static String IDOCINTERFACETAG = "iDoc.Interface";
/**
* iDoc variable tag
**/
static String IDOCVARIABLETAG = "iDoc.Variable";
/**
* iDoc method tag
**/
static String IDOCMETHODTAG = "iDoc.Method";
/**
* iDoc error tag
**/
static String IDOCERRORTAG = "error";
/**
* iDoc non-javadoc comment tag
**/
static String IDOCNONJAVADOCTAG = "non-javadoc";
/**
* iDoc comment tag
**/
static String IDOCCOMMENTTAG = "comment";
/**
* iDoc missing tag
**/
static String IDOCMISSINGTAG = "missing";
/**
* iDoc obsolete tag
**/
static String IDOCOBSOLETETAG = "obsolete";
/**
* iDoc param tag
**/
static String IDOCPARAMTAG = "param";
/**
* iDoc return tag
**/
static String IDOCRETURNTAG = "return";
/**
* Disable bad comment check. Change if desired.
* However, enabling will cause errors when processing this class.
**/
final static boolean dobadcommentcheck = false;
/**
* Disallowed comment starter (change if desired)
**/
final static String BADCOMMENT = "/***";
/**
* javadoc start comment
**/
final static String JAVADOCSTARTCOMMENT = "/**";
/**
* javadoc middle comment
**/
final static String JAVADOCMIDDLECOMMENT = " * ";
/**
* javadoc endcomment
**/
final static String JAVADOCENDCOMMENT = "**/";
/**
* javadoc parameter tag
**/
final static String JAVADOCPARAM = "@param";
/**
* javadoc return tag
**/
final static String JAVADOCRETURN = "@return";
/**
* javadoc author tag
**/
final static String JAVADOCAUTHOR = "@author";
/**
* javadoc version tag
**/
final static String JAVADOCVERSION = "@version";
/**
* customized javadoc author tag (hard-coded for now -- needs servicing)
**/
static String authortag = JAVADOCAUTHOR + " Duke (service AddJavaDoc's authortag)";
/**
* customized javadoc version tag (hard-coded for now -- needs servicing)
**/
static String versiontag = JAVADOCVERSION + " 0.001 01 Jan 1970 (service AddJavaDoc's version tag)";
/**
* line number the errorcode occurred
**/
int lineno;
/**
* code for iDoc error
**/
int errorcode;
/**
* parameters for method
**/
String [] params;
/**
* Constructs an iDoc errorcode entry (a future javadoc comment)
* @param lineno line number in source where javadoc comments are needed
* @param errorcode type of iDoc error
* @param params method parameters (to generate lines like this one)
**/
public AddJavaDoc(int lineno, int errorcode, String [] params) {
this.errorcode = errorcode;
this.lineno = lineno;
this.params = params;
}
/**
* Adds javadoc comments to code.
* @param args iDoc filename, source filename, header filename
**/
public static void main (String [] args) {
if (args.length >= 2) { // if specified, load given file
AddJavaDoc [] errors = iDocErrors(args[0]);
String [] header = null;
if( args.length == 3) {
header = readHeaders(args[2]);
}
addJavaDocs(args[1], errors, header);
} else {
System.out.println("Usage - java AddJavaDoc <.java source> []");
System.exit(1);
}
System.exit(0); // everything was okay(???)
} // main()
// some testing material (next line tests tabbed indentation as well)
static final int unjavadocumentedvariablefortesting=0; // needs title
/**
* @param obsoleteparm this should generate an obsolete error in iDoc
* @parm badparm this should generate a nonjavadoc error in iDoc
**/
final int testAddJavaDoc(int missingparm) { // tests AddJavaDoc's interface with iDoc
return 1; // note this method needs a javadoc title
}
/**
* reads header (copyright) file into buffer
* @param headername name of header file
* @return buffer containing text of header file
**/
static String [] readHeaders( String headername) {
try {
FileInputStream is = new FileInputStream(headername);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr, MAXREADFORMARK);
br.mark(MAXREADFORMARK);
int linecounter = 0;
String line;
while ( null != (line = br.readLine())) {
++linecounter;
}
br.reset();
String [] headers = new String [linecounter];
linecounter = 0;
while ( null != (line = br.readLine())) {
headers[linecounter] = new String(line);
++linecounter;
}
br.close();
return(headers);
} catch( Exception e) {
System.out.println("Exception " + e);
return null;
}
} // readHeaders()
/**
* parses iDoc error
* @param line line of text from iDoc errorcode listing
* @return a iDoc errorcode (future javadoc addition)
**/
static public AddJavaDoc parseError(String line) {
StringTokenizer st = new StringTokenizer(line, ", :[]");
String s;
if( st.hasMoreTokens()) s = st.nextToken(); // file name
else return null;
if( st.hasMoreTokens())s = st.nextToken().trim(); // line number
else return null;
int lineno;
try{
lineno = new Integer(s).intValue();
} catch(Exception e) {
System.out.println("Exception: " + e);
System.out.println("Ignoring: "+line);
return null;
}
if( st.hasMoreTokens())s = st.nextToken(); // "idoc"
else return null;
if( st.hasMoreTokens())s = st.nextToken().trim(); // "error" or not
else return null;
int errorcode = 0;
int paramcounter = 0;
String [] maxparams = null;
if (s.equals(IDOCERRORTAG)) {
if( st.hasMoreTokens()) s = st.nextToken().trim(); // iDoc.Class or .Variable or .Method
else return null;
if (s.equals(IDOCCLASSTAG)) { // set assuming it will be a comment title error
errorcode = CLASSTITLE;
} else if (s.equals(IDOCINTERFACETAG)) {
errorcode = INTERFACETITLE;
} else if (s.equals(IDOCVARIABLETAG)) {
errorcode = VARIABLETITLE;
} else if (s.equals(IDOCMETHODTAG)) {
errorcode = METHODTITLE;
} else {
System.out.println("Unparsable iDoc line - " + line);
System.exit(1);
}
if( st.hasMoreTokens()) s = st.nextToken().trim(); // Class / method / variable name
else return null;
if( st.hasMoreTokens()) s = st.nextToken().trim(); // "comment" or "non-javadoc"
else return null;
if (s.equals(IDOCNONJAVADOCTAG)) {
errorcode = NONJAVADOC;
} else if(!s.equals(IDOCCOMMENTTAG)) {
return null; // unknown iDoc line
}
} else { // method param error
if (s.equals(IDOCMETHODTAG)) {
errorcode = METHODPARAMVOID;
if( st.hasMoreTokens()) s = st.nextToken(); // method name
else return null;
if( st.hasMoreTokens()) s = st.nextToken(); // "missing" or "obsolete"
else return null;
if( s.equals(IDOCMISSINGTAG)) {
errorcode = METHODPARAMVOID;
} else if (s.equals(IDOCOBSOLETETAG)) {
errorcode = OBSOLETETAG;
} else {
return null; // unrecognized iDoc error
}
if( st.hasMoreTokens()) s = st.nextToken(); // "tags"
else return null;
maxparams = new String [MAXPARAMS];
while (st.hasMoreTokens()) {
s = st.nextToken().trim();
if (s.equals(IDOCPARAMTAG)) {
if( st.hasMoreTokens()) s = st.nextToken().trim();
maxparams[paramcounter] = s;
++paramcounter;
} else if (s.equals( IDOCRETURNTAG)) {
if( errorcode == METHODPARAMVOID) errorcode = METHODPARAMRETURN;
}
}
} else {
return null; // unrecognized iDoc error
}
}
if( maxparams != null) {
String [] foundparams = new String[paramcounter];
System.arraycopy( maxparams, 0, foundparams, 0, paramcounter);
maxparams = foundparams;
}
return new AddJavaDoc(lineno, errorcode, maxparams);
} // parseError()
/**
* reads iDoc errorcode file
* @param idocname name of iDoc errorcode listing
* @return list of iDoc errors (future javadoc additions)
**/
static AddJavaDoc [] iDocErrors( String idocname) {
try {
FileInputStream is = new FileInputStream(idocname);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr, MAXREADFORMARK);
br.mark(MAXREADFORMARK);
int linecounter = 0;
String line;
while ( null != (line = br.readLine())) {
++linecounter;
}
br.reset();
AddJavaDoc [] errors = new AddJavaDoc [linecounter];
int errorcounter = 0;
while ( null != (line = br.readLine())) {
if( ! line.startsWith(IDOCSCANNEREXCEPTIONTAG)) {
AddJavaDoc parseerror = parseError(line);
if (parseerror != null) {
errors[errorcounter] = parseerror;
++errorcounter;
}
}
}
AddJavaDoc [] trimmederrors = new AddJavaDoc[errorcounter];
System.arraycopy( errors, 0, trimmederrors, 0, errorcounter);
errors = trimmederrors;
sortErrors(errors);
return errors;
} catch( Exception e) {
System.out.println("Exception " + e);
return null;
}
} // iDocErrors()
/**
* adds javadoc comments to source code
* @param srcname name of source code (.java) file
* @param errors list of iDoc errors (future javadoc additions)
* @param headers new header for source file
**/
static void addJavaDocs( String srcname, AddJavaDoc [] errors, String [] headers) {
if( srcname.endsWith(".java")) {
srcname = srcname.substring(0,srcname.length() - 5);
}
String dstname = srcname + ".jdoc";
srcname = srcname + ".java";
BufferedReader br = null;
PrintWriter pw = null;
try {
FileInputStream fis = new FileInputStream(srcname);
InputStreamReader isr = new InputStreamReader(fis);
br = new BufferedReader(isr, MAXREADFORMARK);
FileOutputStream fos = new FileOutputStream(dstname);
OutputStreamWriter osw = new OutputStreamWriter(fos);
pw = new PrintWriter(osw,true);
} catch (Exception e) {
System.out.println("Exception opening input/outputfiles " + e);
System.exit(1);
}
if( headers != null) {
for( int i = 0; i < headers.length; i++) {
pw.println(headers[i]);
}
}
int errorcounter = 0;
int linecounter = 1;
String line = null;
try {
line = br.readLine();
} catch (IOException ioe) {
System.out.println("Error reading input file " + srcname + " " + ioe);
System.exit(1);
}
while ( null != line) {
if( dobadcommentcheck && (line.indexOf(BADCOMMENT) >= 0)) {
System.out.println("Sorry... bad comment starter detected..." + BADCOMMENT + " modify this class if desired.");
System.out.println(linecounter + " " + line);
System.exit(1);
}
if( errorcounter < errors.length) {
if( errors[ errorcounter].lineno == linecounter) {
// determine indentation
int indent = 0;
String indentstring = "";
boolean done = false;
while( ! done) {
char c = line.charAt(indent);
if( (c == ' ') || (c == '\t')) {
indentstring = indentstring + c;
} else {
done = true;
}
++indent;
}
pw.println(indentstring + JAVADOCSTARTCOMMENT);
while ((errorcounter < errors.length) &&
(errors[ errorcounter].lineno == linecounter)) {
AddJavaDoc thiserror = errors[ errorcounter];
String doc = indentstring + JAVADOCMIDDLECOMMENT;
switch( thiserror.errorcode) {
case CLASSTITLE: // fall through
case INTERFACETITLE:
String classdoc = doc + FILL;
pw.println(classdoc);
pw.println(doc);
classdoc = doc + authortag;
pw.println(classdoc);
classdoc = doc + versiontag;
pw.println(classdoc);
break;
case VARIABLETITLE: // fall through
case METHODTITLE:
doc = doc + FILL;
pw.println(doc);
break;
case OBSOLETETAG:
if( thiserror.params != null) {
String paramdoc;
for( int i = 0; i < thiserror.params.length; i++) {
paramdoc = doc + FILLOBSOLETETAG + " " + thiserror.params[i] + " " + FILL;
pw.println(paramdoc);
}
}
break;
case NONJAVADOC:
doc = doc + FILLNONJAVADOC;
pw.println(doc);
break;
case METHODPARAMVOID: // fall through
case METHODPARAMRETURN:
if( thiserror.params != null) {
String paramdoc;
for( int i = 0; i < thiserror.params.length; i++) {
paramdoc = doc + JAVADOCPARAM + " " + thiserror.params[i] + " " + FILL;
pw.println(paramdoc);
}
}
if( thiserror.errorcode == METHODPARAMRETURN) {
doc = doc + JAVADOCRETURN + " " + FILL;
pw.println(doc);
}
break;
default:
System.out.println("Invalid errorcode code: " + thiserror.errorcode );
System.exit(1);
break;
}
++errorcounter;
}
pw.println(indentstring + JAVADOCENDCOMMENT);
}
} // end errorcounter < errors.length
pw.println(line);
++linecounter;
try {
line = br.readLine();
} catch (IOException ioe) {
System.out.println("Error reading input file " + srcname + " " + ioe);
System.exit(1);
}
} // endwhile()
try{
br.close();
pw.close();
} catch (Exception e) {
System.out.println("Exception closing input/outputfiles " + e);
System.exit(1);
}
} // addJavaDocs()
/**
* swaps two iDoc errors
* @param errors list of iDoc errors
* @param i errorcode to swap
* @param j errorcode to swap
**/
static void swap(AddJavaDoc [] errors, int i, int j) {
AddJavaDoc tmp = errors[i];
errors[i] = errors[j];
errors[j] = tmp;
return;
} // swap()
/**
* sorts errors by line number and type
* @param errors list of iDoc errors (future javadoc addition)
**/
static void sortErrors( AddJavaDoc [] errors) {
for( int i = 0; i < errors.length - 1; i++) {
for( int j = i + 1; j < errors.length; j++) {
if( errors[ i].lineno > errors[j].lineno) swap(errors, i, j);
else if (errors[i].lineno == errors[j].lineno) {
if ((errors[i].errorcode == METHODPARAMRETURN) ||
(errors[i].errorcode == METHODPARAMVOID)) swap(errors, i, j);
}
}
}
for( int i = 0; i < errors.length; i++) {
System.out.println(i + " " + errors[i]);
}
} // sortErrors()
/**
* converts an iDoc errorcode (future javadoc addition) to a string
* @return string describing iDoc errorcode (future javadoc addition)
**/
public String toString() {
String s = lineno + " ";
switch( errorcode) {
case CLASSTITLE: s = s + IDOCCLASSTAG + " Title "; break;
case INTERFACETITLE: s = s + IDOCINTERFACETAG + " Title "; break;
case VARIABLETITLE: s = s + IDOCVARIABLETAG + " Title "; break;
case METHODTITLE: s = s + IDOCMETHODTAG + " Title "; break;
case NONJAVADOC: s = s + " NONJAVADOC "; break;
case OBSOLETETAG: s = s + " OBSOLETE "; // fall through
case METHODPARAMVOID: // fall through
case METHODPARAMRETURN:
s = s + IDOCMETHODTAG + " ";
if( params != null) {
s = s + "params ";
for( int i = 0; i < params.length; i++) {
s = s + params[i] + " ";
}
}
break;
default: s = s + "Unknown error code"; break;
}
if (errorcode == METHODPARAMRETURN) s = s + "returns ";
return s;
} // toString()
} // AddJavaDoc