genhtml.beh.html
Program{
(@
// various HTML tags
final static String HTML = "<HTML>";
final static String _HTML = "</HTML>";
final static String HEAD = "<HEAD>";
final static String _HEAD = "</HEAD>";
final static String TITLE = "<TITLE>";
final static String _TITLE = "</TITLE>";
final static String PRE = "<PRE>";
final static String _PRE = "</PRE>";
// Background White, Visited Links HotPink, Links Blue
final static String BODY = "<BODY LINK=\"#0000FF\" VLINK=\"#FF00FF\" BGCOLOR=\"#FFFFFF\">";
final static String _BODY = "</BODY>";
final static String BASE = "<BASE TARGET=\"frame0\">";
// html files and directories
public final static String htmlext = ".html"; // html file extension
static File htmldir = new File("html/"); // dir for html files
static File htmlgendir; // dir for java html files
static File gen; // gendir formatted for our purposes
private static File indexfile = new File("index" + htmlext);
private static File referfile = new File("referfile" + htmlext);
private static Vector file_exts = new Vector(4); // holds filename extensions
private static Vector files = new Vector(4); // 2D Vector of filenames
private static Vector inputfiles = new Vector(); // *.input files
private static Vector origbehfiles = new Vector(); // *.beh files
private static Program cdprog;
// tables
private static Hashtable htmlclassnames = new Hashtable();
// visitor to create cd class table
private static HtmlClassNameVisitor cdvis = new HtmlClassNameVisitor();
private static HtmlClassNameVisitor behvis = new HtmlClassNameVisitor();
// html frames
public final static int cdframeoffset = 1; // frame number for cd files
// flexibility option to allow frame format to be specified on command line
// for 2nd column such as *,2*,2*,* or 15%,35%,35%,15%
private static String frame_fmt;
// methods
/** Get the reference filename */
public static File getReferFile() { return referfile; }
/** Get the 2D array of filenames */
public static Vector getFiles() { return files; }
/** Get the filename extensions */
public static Vector getFileExts() { return file_exts; }
/** Get the list of java files */
public static Vector getJavaFiles() { return javaFiles; }
/** Get the table of cd class names */
public static Hashtable getHtmlCdClassNames() { return cdvis.getTable(); }
/** Get the table of beh class names */
public static Hashtable getHtmlBehClassNames() { return behvis.getTable(); }
/** Get the table of class names */
public static Hashtable getHtmlClassNames() { return htmlclassnames; }
public static void putHtmlClassNames(Object k, Object e) { htmlclassnames.put(k, e); }
/** return the index for a file extension */
public static int findExtIndex(String s) { return file_exts.indexOf(s); }
/** Generate the HTML files */
private static void generateHtml() throws ParseError, IOException {
if(html) {
// HTML generation is desired
InputStream in;
log.println("javaFiles = "+javaFiles.toString());
// format and ensure html directory
String dir = htmldir.toString();
if(!dir.endsWith("/"))
dir += "/";
htmldir = new File(dir);
ensureDirectory(htmldir);
// format and ensure html java directory
dir = gendir.toString();
if(dir.startsWith("./"))
dir = dir.substring(2);
if(!dir.endsWith("/"))
dir += "/";
gen = new File(dir);
htmlgendir = new File(htmldir.toString() + dir);
ensureDirectory(htmlgendir);
// get filename lists
// NOTE: not handling multiple cd files due to beh being parsed
// and written first and assuming already know which cdfile to
// cross-reference
// get cdfile list
addFiles(".cd", cdfile);
// get behfile list
for (Enumeration e = origbehfiles.elements(); e.hasMoreElements();) {
File efile = (File)e.nextElement();
addFiles(efile.toString().substring(efile.toString().lastIndexOf(".")), efile);
}
// add java file extension
file_exts.addElement(".java");
files.addElement(new Vector());
// get inputfile list
for (Enumeration e = inputfiles.elements(); e.hasMoreElements();) {
File efile = (File)e.nextElement();
addFiles(efile.toString().substring(efile.toString().lastIndexOf(".")), efile);
}
// parse cd file
in = makeInputStream(cdfile);
cdprog = parse(in);
cdprog.toAll(cdvis); // create hashtable of classes in cd
// parse beh files
int index;
if((index = file_exts.indexOf(".beh")) >= 0) {
for (Enumeration e = ((Vector)(files.elementAt(index))).elements(); e.hasMoreElements();) {
File behfile = (File)e.nextElement();
in = makeInputStream(behfile);
ProgramBehavior beh = ProgramBehavior.parse(in);
beh.toAll(behvis);
writeHtmlBehaviorFile(behfile, beh);
}
}
// now java files know which cd and beh files to reference
// generate all the java html files and get list of java files
prog.generateCode(false, true);
// now know which beh files to reference.
writeHtmlClassDictionary();
// add any java-only classes to hash table
prog.addHtmlJavaClasses();
// generate frame index and reference file
writeHtmlFrameIndex();
writeHtmlReferFile();
// generate input file
writeHtmlInputFile();
}
}
/** Generate HTML behavior file */
private static void writeHtmlBehaviorFile(File behfile, ProgramBehavior pb)
throws ParseError, IOException {
File behfilehtml = new File(htmldir.toString(),
behfile.getName() + htmlext);
log.println("Creating " + behfilehtml.toString() + "...");
openOutputFile(behfilehtml);
htmlHeader(out, behfilehtml.getName());
out.println(BODY);
out.println("<H2>" + behfilehtml.getName() + "</H2>");
out.println(BASE);
out.println(PRE);
pb.toAll(new HtmlVisitor(out, behfile, htmlclassnames));
out.println(_PRE);
out.println(_BODY);
htmlFooter(out);
}
/** Generate HTML Class Dictionary */
private static void writeHtmlClassDictionary() throws IOException {
int index; // file extension index
// Check if class dictionary exists
if((index = file_exts.indexOf(".cd")) >= 0) {
int i = 0;
// future: allowing for multiple cd files
for (Enumeration e = ((Vector)(files.elementAt(index))).elements(); e.hasMoreElements(); i++) {
File cdfile = (File)e.nextElement();
File cdfilehtml = new File(htmldir, cdfile.getName() + htmlext);
log.println("Creating " + cdfilehtml.toString() + "...");
openOutputFile(cdfilehtml);
htmlHeader(out, cdfilehtml.getName());
out.println(BODY);
out.println("<H2>" + cdfilehtml.getName() + "</H2>");
out.println(BASE);
out.println(PRE);
cdprog.toAll(new HtmlVisitor(out, cdfile, htmlclassnames));
out.println(_PRE);
out.println(_BODY);
htmlFooter(out);
}
}
else {
System.err.println("No cd file specified!");
}
}
/** Write an index.html file that sets up the frames */
private static void writeHtmlFrameIndex()
throws IOException {
int i;
File f = new File(htmldir.toString(), indexfile.toString());
log.println("Creating " + f.toString() + "...");
openOutputFile(f);
htmlHeader(out, "Demeter/Java Hypertext Documentation Tool");
// we want the left column frame to contain the reference file
out.println("<FRAMESET COLS=\"*,5*\">");
out.println(" <FRAME SRC=\"" + referfile + "\" NAME=frame0>");
if(!file_exts.isEmpty()) {
String rows = " <FRAMESET ROWS=\"";
if(frame_fmt != null)
rows += frame_fmt; // specified on command line
else {
i = 0;
// 2nd column frame gets a row for every file type
for (Enumeration e = file_exts.elements(); e.hasMoreElements();) {
String curext = (String)e.nextElement();
if(i++ != 0) rows += ","; // prepend comma only after first
// give procedural files more space
if (curext.equals(".cd") || curext.equals(".input")) {
rows += "*"; // less space (class dict and input files)
}
else {
rows += "2*"; // more space
}
}
}
out.println(rows + "\">");
i = cdframeoffset;
// initially point to the first file in each list
for (Enumeration e = files.elements(); e.hasMoreElements();) {
Vector curext = (Vector)e.nextElement();
out.println(" <FRAME SRC=\"" + curext.firstElement()
+ htmlext + "\" NAME=frame" + i++ + ">");
}
out.println(" </FRAMESET>");
}
out.println("</FRAMESET>");
out.println("<NOFRAMES>");
out.println("You must use a browser that can display frames " +
"to see this page.");
out.println("</NOFRAMES>");
htmlFooter(out);
}
/** Generate a reference file that contains a list of files
relevant to the program and a class list that
lists all references for a particular class
*/
private static void writeHtmlReferFile()
throws IOException {
int i, j;
File f = new File(htmldir.toString(),referfile.toString());
log.println("Creating " + f.toString() + "...");
openOutputFile(f);
htmlHeader(out, "Reference File");
out.println(BODY);
out.println("<NOBR><H2>Reference File</H2></NOBR>");
// create list of files
out.println("<NOBR><H3>File List</H3></NOBR>");
i = cdframeoffset;
for (Enumeration e = files.elements(); e.hasMoreElements();) {
Vector ext = (Vector)e.nextElement();
for (Enumeration el = ext.elements(); el.hasMoreElements();) {
File ff = (File)el.nextElement();
out.println("<A HREF=\"" + ff
+ htmlext + "\" TARGET=\"frame" + i + "\">" + ff + "</A><BR>");
}
++i;
}
// write list of class references
out.println("<NOBR><H3>Class List</H3></NOBR>");
out.println("<NOBR>c prefix = .cd file reference</NOBR><BR>");
out.println("<NOBR>b prefix = .beh file reference</NOBR><BR>");
out.println("<NOBR>j prefix = .java file reference</NOBR><BR><BR>");
Enumeration e, k, ev;
String file = "";
int cindex = Program.findExtIndex(".cd");
int bindex = Program.findExtIndex(".beh");
int jindex = Program.findExtIndex(".java");
// sort the classes
Collator col = Collator.getInstance();
CollationKey[] keys = new CollationKey[htmlclassnames.size()];
for (k = htmlclassnames.keys(), i = 0; k.hasMoreElements(); i++) {
keys[i] = col.getCollationKey((String)k.nextElement());
}
sort(keys);
// iterate through all classnames
for (j = 0; j < keys.length; j++) {
String key = keys[j].getSourceString(); // classname
HtmlClassIndex hci = (HtmlClassIndex)htmlclassnames.get(key);
// place a name tag for other files to reference & classname
out.print("<NOBR><A NAME=\"" + key + "\"><B>" + key + "</B> "); // class name tag
// list cd file references
int frame = cindex + cdframeoffset;
for (ev = hci.getCd().elements(), i = 0; ev.hasMoreElements(); i++) {
file = (String)ev.nextElement();
out.print("c<A HREF=\"" + file + htmlext + "#" + key + i +
"\" TARGET=\"frame" + frame + "\">" + i + "</A>");
}
// list beh file references
frame = bindex + cdframeoffset;
for (ev = hci.getBeh().elements(), i = 0; ev.hasMoreElements(); i++) {
file = (String)ev.nextElement();
out.print("b<A HREF=\"" + file + htmlext + "#" + key + i +
"\" TARGET=\"frame" + frame + "\">" + i + "</A>");
}
// list java file references
File javfile = new File(gen + key + ".java");
if(((Vector)(files.elementAt(jindex))).contains(javfile)) {
// this file was generated in HTML
frame = jindex + cdframeoffset;
out.print("j<A HREF=\"" + javfile.toString() + htmlext + "#" + key +
0 + "\" TARGET=\"frame" + frame + "\">" + 0 + "</A>");
}
out.println("</NOBR><BR>");
}
out.println(_BODY);
htmlFooter(out);
}
/** Write out the input files in HTML */
private static void writeHtmlInputFile() throws IOException {
int index;
if((index = file_exts.indexOf(".input")) >= 0) {
int i = 0;
for (Enumeration e = ((Vector)(files.elementAt(index))).elements(); e.hasMoreElements(); i++) {
File inputfile = (File)e.nextElement();
File inputfilehtml = new File(htmldir, inputfile.getName() + htmlext);
log.println("Creating " + inputfilehtml.toString() + "...");
openOutputFile(inputfilehtml);
htmlHeader(out, inputfilehtml.getName());
out.println(BODY);
out.println("<H2>" + inputfilehtml.getName() + "</H2>");
// for now, just copy the text.
out.println(PRE);
InputStream in = makeInputStream(inputfile);
copy(in, out);
out.println(_PRE);
out.println(_BODY);
htmlFooter(out);
}
}
}
/** store filename by extension */
public static void addFiles(String ext, File file) {
int index;
if((index = file_exts.indexOf(ext)) < 0) {
// need to add filetype first
file_exts.addElement(ext);
files.addElement(new Vector());
index = files.size() - 1;
}
// make sure path starts as expected (no ./)
if(file.toString().startsWith("./"))
file = new File(file.toString().substring(2));
// Add pathname to end of appropriate list
((Vector)(files.elementAt(index))).addElement(file);
}
/** Make sure the directory exists and is writable. */
private static void ensureDirectory(File dir) throws IOException {
if (!dir.exists()) {
log.println("Directory " + dir.toString() +
" does not exist, will create.");
if (!dir.mkdirs()) {
System.err.println("Error: could not create output directory.");
throw new IOException();
}
}
if (dir.exists()) {
if (!dir.isDirectory()) {
System.err.println("Error: " + dir +
" exists but is not a directory.");
} else if (!dir.canWrite()) {
System.err.println("Error: " + dir +
" exists but is not writable.");
} else return;
throw new IOException();
}
}
/** Every HTML file has this header */
public static void htmlHeader(PrintWriter out, String title) {
out.println(HTML);
out.println(HEAD);
out.println(TITLE + title + _TITLE);
out.println("<!-- Automatically generated by Demeter/Java " +
"Hypertext Documentation Tool -->");
out.println(_HEAD);
}
/** Every HTML file has this footer */
public static void htmlFooter(PrintWriter out) {
out.println(_HTML);
closeOutputFile();
}
/** copy from in to out */
private static void copy(InputStream in, PrintWriter out)
throws IOException {
int ch;
while((ch = in.read()) >= 0)
out.write(ch);
}
/** bubble sort the keys */
private static void sort(CollationKey[] keys) {
// for each location in the array
for(int i = 0; i < keys.length - 1; i++) {
for(int j = 0; j < keys.length - i - 1; j++) {
// for the rest of the array compare the keys
if( keys[j].compareTo( keys[j+1] ) > 0 ) {
// swap keys[i] and keys[j]
CollationKey temp = keys[j + 1];
keys[j + 1] = keys[j];
keys[j] = temp;
}
}
}
}
@)
private void addHtmlJavaClasses()=allClassDefs{
before ClassDef (@
String c = host.get_classname().toString();
if(!Program.getHtmlClassNames().containsKey(c))
Program.putHtmlClassNames(c, new HtmlClassIndex());
@)
}
}
ProgramBehavior{
traversal toAll(UniversalVisitor v) {
bypassing{ Hashtable }to*;
}
}
HtmlClassNameVisitor{
(@ private Hashtable hash; @)
init (@ hash = new Hashtable(); @)
before-> ClassName, name, Name (@
hash.put(source.get_name().toString(), source.get_name().toString());
@)
Hashtable getTable()(@
return (hash);
@)
}
HtmlClassIndex{
(@ private Vector cd = new Vector();
private Vector beh = new Vector();
public void addCd(String s) { cd.addElement(s); }
public void addBeh(String s) { beh.addElement(s); }
public Vector getCd() { return cd; }
public Vector getBeh() { return beh; }
@)
}