diff --git a/src/helma/doc/DocApplication.java b/src/helma/doc/DocApplication.java new file mode 100644 index 00000000..9a5770cb --- /dev/null +++ b/src/helma/doc/DocApplication.java @@ -0,0 +1,89 @@ +package helma.doc; + +import java.io.*; +import java.util.*; + +public class DocApplication extends DocElement { + + private DocPrototype[] prototypes; + + /** read all prototypes + * @param name application to be documented + * @param appDir directory of this application */ + public DocApplication(String name, String appDir) throws DocException { + super( name, appDir, APPLICATION ); + checkCommentFile(); + readPrototypes(); + } + + public String getFullName() { + return ( "Application " + name ); + } + + /** return number of prototypes */ + public int countPrototypes() { + return prototypes.length; + } + + /** return a single prototype */ + public DocPrototype getPrototype(String name) { + for ( int i=0; ie2.getType() ) + return 1; + else if ( mode==BY_TYPE && e1.getType()=METHOD && type<=SKIN ) return true; else return false; } + public boolean isAction() { return (type==ACTION)?true:false; } + public boolean isTemplate() { return (type==TEMPLATE)?true:false; } + public boolean isFunction() { return (type==FUNCTION)?true:false; } + public boolean isMacro() { return (type==MACRO)?true:false; } + public boolean isSkin() { return (type==SKIN)?true:false; } + + public int getType() { return type; } + public String getTypeName() { return typeNames[type]; } + + public String getDocFileName() { return (typeNames[type] + "_" + name).toLowerCase() + ".html"; } + + /** @return the text of the comment */ + public String getComment() { return (comment!=null)?comment:""; } + + public int countTags() { return countTags(-1); } + public int countTags(int kind) { + int ct=0; + for ( int i=0; ibeginLine && ct"); + else + print(""); + print(""); + print(""); + println("" + title + ""); + if ( frameset==true ) + print(""); + println(""); + } + + + public void printFrameSet() { + println (""); + println (""); + println (""); + println ("sorry, your browser doesn't understand frames!"); + } + + /** print app title for left frame */ + public void printAppIndexTitle(String title) { + print("
"); + print(""); + print("Application " + title + "
" ); + } + + /** print prototype list for left frame */ + public void printAppIndexList(DocElement[] pt) { + print("
"); + print("

Prototypes

"); + for ( int i=0; i" + pt[i].getName() + "
"); + } + print ("

"); + } + + /** navigation on top of the page **/ + public void printNavBar(String name, DocPrototype pt, int page ) { + String urlPrefix = ( page==METHOD ) ? "../" : ""; + print(""); + print(""); + print(""); + print(""); + if ( pt!=null && page!=METHOD ) { + print(""); + } + + print("
Application " + name + "
"); + print("
"); + print(""); + } + + public void printElementTitle(DocElement docEl) { + print("

" + docEl.getName() + "
"); + print(docEl.getFullName() + "

"); + print("
"); + } + + public void printComment(DocElement docEl) { + if( docEl.getComment().length()>0 || docEl.countTags()>0 ) { + print("
" + docEl.getComment() + "
"); + print("
"); + for ( int i=0; i0 ) { + print("
" + DocTag.kindDesc[i] + "
"); + DocTag[] dt = docEl.listTags(i); + for ( int j=0; j" + renderTag(dt[j],j) + ""); + } + } + } + print("
"); + } + } + + private String renderFunctionName(DocFunction func) { + StringBuffer buf = new StringBuffer (); + buf.append(""); + if ( DocRun.getOption("-f").equals("true") ) + buf.append("" ); + if ( func.isMacro() ) { + buf.append( func.getPrototype().getName()+"."+func.getName().substring(0,func.getName().length()-6) ); + } else { + buf.append(func.getName().trim()); + if( func.isTemplate() || func.isFunction() ) { + buf.append("("); + int ct = func.countTags(DocTag.ARG); + for ( int i=0; i"); + if ( func.isFunction() || func.isMacro() ) + buf.append(" in " + (new File(func.getLocation())).getName() + "" ); + return buf.toString(); + } + + private String renderTag(DocTag tag) { + return renderTag(tag,0); + } + + private String renderTag(DocTag tag, int i) { + int kind = tag.getKind(); + String text = tag.getText(); + String name = tag.getName(); + switch (kind) { + case DocTag.ARG: + return( "arg" + i + ": " + text ); + case DocTag.PARAM: + return( "" + name + " " + text ); + case DocTag.RETURNS: + case DocTag.AUTHOR: + case DocTag.VERSION: + case DocTag.RELEASE: + return( text ); + case DocTag.SEE: + if ( text.startsWith("http://") ) { + StringTokenizer tok = new StringTokenizer (text.trim()," "); + String url = (tok.countTokens()>1)?tok.nextToken():text; + return( "" + ((tok.countTokens()>0)?text.substring(url.length(),text.length()):text) + "" ); + } else { + StringBuffer buf = new StringBuffer(); + StringTokenizer tok = new StringTokenizer (text.trim(),"."); + if ( tok.countTokens()==0 ) return text; + DocPrototype dp = app.getPrototype( tok.nextToken() ); + if ( dp==null ) return text; + buf.append("0 ) + df = dp.getFunction( tok.nextToken() ); + if ( df==null ) + buf.append( link(dp) + "\">" + dp.getName() ); + else + buf.append( link(df) + "\">" + dp.getName() + "." + df.getName() ); + return(buf.toString()+""); + } + } + return text; + } + + public void printListHeader(String title) { + print(""); + print(""); + print(""); + } + + public void printPrototypeList(DocPrototype[] dl, String title) { + if ( dl.length==0 ) return; + printListHeader(title); + for ( int i=0; i"); + print(""); + } + print("
" + title + "
"); + print(""); + print(" " + dl[i].getTypeName() + "" + dl[i].getName() + ""); + print("
          " + dl[i].getComment() + "
" ); + print("

"); + } + + public void printFunctionList(DocFunction[] dl, String title) { + if ( dl.length==0 ) return; + printListHeader(title); + for ( int i=0; i"); + print(""); + print(""); + print(" " + dl[i].getTypeName() + ""); + print("
" + renderFunctionName(dl[i]) ); + print("
"); + printComment(dl[i]); + print("
"); + } + print("
"); + } + + public void printFunctionIndex(DocFunction[] dl) { + if ( dl.length==0 ) return; + String curChar = " "; + print("
"); + for ( int i=0; i

" + name.substring(0,1).toUpperCase() + "

"); + curChar = name.substring(0,1).toLowerCase(); + } + print("
" + dl[i].getName() + " - " + dl[i].getTypeName() + " in " + dl[i].getPrototype().getName() + "" ); + } + print("
"); + } + + public void printInheritance(DocPrototype pt) { + if ( pt.getName().equalsIgnoreCase("hopobject") ) + return; + DocApplication app = pt.getApplication(); + DocPrototype hopobject = (DocPrototype)app.getPrototype("hopobject"); + if ( hopobject==null || hopobject.countFunctions()==0 ) + return; + print(""); + print(""); + print(""); + print(""); + print("
Methods inherited from Prototype hopobject
"); + DocFunction[] df = hopobject.listFunctions(); + + int lastType = -1; + StringBuffer buf1 = new StringBuffer(); + StringBuffer buf2 = new StringBuffer(); + + for ( int i=0; i0 && buf2.length()>0 ) { + buf1.append("" + DocElement.typeNames[lastType] + ": " ); + buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) ); + buf1.append("
"); + buf2 = new StringBuffer(); + } + lastType = df[i].getType(); + buf2.append ( "" + df[i].getName() + ", " ); + } + if ( buf2.length()>0 ) { + buf1.append("" + DocElement.typeNames[lastType] + ": " ); + buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) ); + buf1.append("
"); + } + print ( buf1.toString() ); + print("
"); + } + + public void printFunction(DocFunction func) { + print( "

in " + func.getPrototype().getName() + "/" + (new File(func.getLocation())).getName() + ":" ); + print( "
");
+		print( HtmlEncoder.encodeAll(func.getSource()) );
+		print( "
" ); + } + + public void printStyleSheet() { + println( "/* Javadoc style sheet */"); + println( "/* Define colors, fonts and other style attributes here to override the defaults */"); + println( "* Page background color */"); + println( "body { background-color: #FFFFFF }"); + println( "/* Table colors */"); + println( "#TableHeadingColor { background: #CCCCFF } /* Dark mauve */"); + println( "#TableSubHeadingColor { background: #EEEEFF } /* Light mauve */"); + println( "#TableRowColor { background: #FFFFFF } /* White */"); + println( "/* Font used in left-hand frame lists */"); + println( "#FrameTitleFont { font-size: normal; font-family: normal }"); + println( "#FrameHeadingFont { font-size: normal; font-family: normal }"); + println( "#FrameItemFont { font-size: normal; font-family: normal }"); + println( "/* Example of smaller, sans-serif font in frames */"); + println( "/* #FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */"); + println( "/* Navigation bar fonts and colors */"); + println( "#NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */"); + println( "#NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */"); + println( "#NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;}"); + println( "#NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}"); + println( "#NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}"); + println( "#NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}"); + } + + public String link(DocElement docEl) { + if ( docEl.isPrototype() ) { + return "prototype_" + docEl.getName() + ".html"; + } else if ( docEl.isMethod() ) { + DocFunction df = (DocFunction)docEl; + return "prototype_" + df.getPrototype().getName() + ".html#" + df.getName(); + } else { + return ""; + } + } + +} + diff --git a/src/helma/doc/DocPrototype.java b/src/helma/doc/DocPrototype.java new file mode 100644 index 00000000..26807a8e --- /dev/null +++ b/src/helma/doc/DocPrototype.java @@ -0,0 +1,192 @@ +package helma.doc; + +import java.io.*; +import java.util.*; +import FESI.Parser.*; + + +public class DocPrototype extends DocElement { + + DocFunction[] functions; + DocApplication app; + + public DocPrototype( String name, String location, DocApplication app ) throws DocException { + super( name, location, PROTOTYPE ); + this.app = app; + if ( name.equals("hopobject")==false && name.equals("global")==false ) + readPropertiesFile( new File(location,"type.properties").getAbsolutePath()); + checkCommentFile(); + readFunctions(); + } + + public String getFullName() { return ( "Prototype " + name ); } + + /** return number of functions */ + public int countFunctions() { return functions.length; } + + /** return array of functions of a special type */ + public int countFunctions(int type) { + int ct = 0; + for ( int i=0; i")) ); + EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(new ASCII_CharStream(str,1,1),0); + Token tok = mgr.getNextToken(); + func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, getCommentFromToken(tok) ); + } catch ( IndexOutOfBoundsException e ) { + func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, "" ); + } + func.setSource(content); + funcVec.addElement(func); + } + + private void readSkin(String f, Vector funcVec) throws DocException { + // can't be commented yet + // simply add them + DocFunction func = new DocFunction(fileToFuncName(f),f,DocElement.SKIN, this,""); + func.readSource(f); + funcVec.addElement(func); + } + + + /** create token manager for a file */ + private EcmaScriptTokenManager createTokenManager(File f) { + try { + ASCII_CharStream is = new ASCII_CharStream(new FileReader(f), 1, 1); + EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(is,0); + return mgr; + } catch ( FileNotFoundException shouldnotappear ) { } + return null; + } + + /** connect all available specialTokens */ + private String getCommentFromToken(Token tok) { + StringBuffer buf = new StringBuffer(); + while( tok.specialToken!=null ) { + buf.append(tok.specialToken.toString() ); + tok = tok.specialToken; + } + return ( buf.toString().trim() ); + } + + private String fileToFuncName(String f) { + return fileToFuncName(new File(f)); + } + + private String fileToFuncName(File f) { + String tmp = f.getName(); + return tmp.substring(0,tmp.indexOf(".")); + } + + public String toString() { + return ( "[DocPrototype " + name + "]" ); + } + +} + diff --git a/src/helma/doc/DocRun.java b/src/helma/doc/DocRun.java new file mode 100644 index 00000000..88d1cae2 --- /dev/null +++ b/src/helma/doc/DocRun.java @@ -0,0 +1,138 @@ +package helma.doc; + +import java.io.*; +import java.util.*; +import helma.objectmodel.*; + +public class DocRun { + + public static String propfile; + public static SystemProperties sysProps, dbProps; + public static String actionExtension; + public static String scriptExtension; + public static String templateExtension; + public static String skinExtension = ".skin"; + + public static String hopHomeDir; + + private static Hashtable options; + + String appName; + DocApplication app; + + public static void main ( String args[] ) { + boolean usageError = false; + // parse options from command line + options = new Hashtable(); + StringBuffer buf = new StringBuffer(); + String name = ""; + for ( int i=0; i0 ) { + if ( buf.toString().length()==0 ) + usageError = true; + else + options.put(name,buf.toString() ); + } + name = args[i]; + buf = new StringBuffer(); + } else { + buf.append( ( (buf.toString().length()>0) ? " ":"" ) + args[i]); + } + } + options.put(name,buf.toString()); // include last option + // now check parameter + if ( options.containsKey("-h") ) { + hopHomeDir = (String)options.get("-h"); + } else { + hopHomeDir = System.getProperty("user.dir"); + } + readHopProperties(hopHomeDir); + String parAppDir = ""; + if ( options.containsKey("-a") ) { + parAppDir = (String)options.get("-a"); + } else { + usageError = true; + } + if ( usageError==true ) { + help(); + System.exit(0); + } + try { + new DocRun(parAppDir); + } catch ( DocException e ) { + System.out.println("doc error: " + e.getMessage()); + } + } + + public static void help() { + System.out.println ("usage: java helma.doc.DocApplication -a appdir [-f] [-h hopdir] [-d docdir] [-i ignore]"); + System.out.println (" -a appdir Specify source directory"); + System.out.println (" -h hopdir Specify hop home directory"); + System.out.println (" -d docdir Specify destination directory"); + System.out.println (" -f true Link functions to source code"); + System.out.println (" -i ignore Specify prototypes to ignore (like: \"-i CVS mistsack\")"); + System.out.println (" -debug"); + System.out.println ("\n"); + } + + public static boolean prototypeAllowed(String name) { + String ig = " " + getOption("-i").toLowerCase() + " "; + if ( ig.equals("") ) return true; + name = name.toLowerCase(); + if ( ig.indexOf(" "+name+" ")>-1 ) + return false; + else + return true; + } + + /** + * reads server.properties, apps.properties and db.properties from hop-home-directory + * TBD: should be cleaned up to work exactly like the helma server + * @param homeDir hop-home-directory with server.properties-file + */ + public static void readHopProperties(String hopHomeDir) { + propfile = new File (hopHomeDir, "server.properties").getAbsolutePath(); + sysProps = new SystemProperties (propfile); + dbProps = new SystemProperties ( new File(hopHomeDir,"db.properties").getAbsolutePath() ); + actionExtension = sysProps.getProperty("actionExtension",".hac"); + scriptExtension = sysProps.getProperty("scriptExtension",".js"); + templateExtension = sysProps.getProperty("templateExtension",".hsp"); + } + + public DocRun (String appDir) throws DocException { + File d = new File(appDir); + if ( !d.exists() ) + throw new DocException( d.toString() + " doesn't exist"); + if ( !d.isDirectory() ) + throw new DocException( d.toString() + " is not a directory"); + log ( "parsing application " + d.getName() + " located in " + d.getAbsolutePath() ); + log ( "writing output to " + getOption("-d", new File(hopHomeDir,"/appdocs/"+d.getName()).getAbsolutePath()) ); + app = new DocApplication(d.getName(),d.getAbsolutePath() ); + DocWriter.start( getOption("-d", new File(hopHomeDir,"/appdocs/"+d.getName()).getAbsolutePath()), app); + } + + public static String getOption(String name) { + return getOption(name,""); + } + + public static String getOption(String name, String def) { + if ( options.containsKey(name) ) + return(String)options.get(name); + else + return(def); + } + + public static void debug(String msg) { + if ( options.containsKey("-debug") ) + System.out.println(msg); + } + + public static void log( String msg ) { + System.out.println(msg); + } + +} + + + diff --git a/src/helma/doc/DocTag.java b/src/helma/doc/DocTag.java new file mode 100644 index 00000000..19fa9b17 --- /dev/null +++ b/src/helma/doc/DocTag.java @@ -0,0 +1,58 @@ +package helma.doc; + +import java.util.*; + +public class DocTag { + + public static final int ARG = 0; + public static final int PARAM = 1; + public static final int RETURNS = 2; + public static final int AUTHOR = 3; + public static final int VERSION = 4; + public static final int RELEASE = 5; + public static final int SEE = 6; + + /** number of different tag-types **/ + public static final int TYPE_COUNT = 7; + + /** constants are used as array indices! **/ + public static final String[] kindNames = {"arg","param","return","author","version","release","see"}; + public static final String[] kindDesc = {"Arguments","Parameter","Returns","Author","Version","Release","See also"}; + + private String name; + private int kind; + private String text; + + public DocTag( String rawTag ) throws DocException { + //DocRun.log(rawTag); + try { + StringTokenizer tok = new StringTokenizer(rawTag); + String kindstr = tok.nextToken().toLowerCase(); + for ( int i=0; i