Java2Html.java
import java.io.*;
import java.util.*;

public class Java2Html 
{
    static public String destination;
    static Vector packages = new Vector();
    static long lines = 0;
    
    public static void ReadDir(Package parent, String name, String srcdir) {
        Package P = new Package(parent, name, srcdir);
        packages.addElement(P);
        
        File F = new File(srcdir);
        String file[] = F.list();
        for(int i = 0; i < file.length; i++) {
            String f = file[i];
            if (f.endsWith(".java")) 
                P.AddFile(f);
            else {
                String dirname = srcdir + "/" + f;
                File D = new File(dirname);
                if (D.isDirectory()) {
                    if (name.equals(""))
                        ReadDir(P, f, dirname);
                    else
                        ReadDir(P, name + "." + f, dirname);
                }
            }
        }
    }
    
    public static void WritePackageList() {
        String fname = Java2Html.destination + "/packages.html";
            
        try {
            PrintWriter W = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fname))));
            W.println("<html><head><title>All packages</title></head><body bgcolor=ffffdd>");
            W.println("<b>All packages</b><hr>");
                    
            Enumeration e = packages.elements();
            while(e.hasMoreElements()) {
                Package p = (Package)e.nextElement();
                File F = new File(Java2Html.destination + "/" + p.IndexName());
                if (F.exists()) {
                    if (p.name.equals("")) 
                        W.println("<a href=" + p.IndexName() + "><b>default package</b></A></BR>");
                    else
                        W.println("<a href=" + p.IndexName() + "><b>" + p.name + "</b></A></BR>");
                }
            }    
            W.println("</body></html>");
            W.close();
        } catch (IOException e) {
        }
    }
    
    public static void main(String[] args) {
        destination = args[1];
        ReadDir(null, "", args[0]);
        
        VectorSorter.Sort(packages);
        
        WritePackageList();
        Enumeration e = packages.elements();
        while(e.hasMoreElements()) {
            Package P = (Package)e.nextElement();
            P.Convert2Html();
        }
        System.out.println("Lines of code: " + lines);
    }
}

class Package {
    String sourcedir;
    String name;
    Package parent;
    
    Vector files = new Vector();
    Vector subpackages = new Vector();
    
    public Package(Package parent, String name, String sourcedir) {
        this.name = name;
        this.sourcedir = sourcedir;
        this.parent = parent;
        if (parent != null)
            parent.subpackages.addElement(this);
    }
    
    public void AddFile(String name) {
        files.addElement(new JFile(name, this));
    }
    
    public String FullClassName(JFile f) {
        if (name.equals(""))
            return f.name;
        else
            return name + "." + f.name;
    }

    public String SourceFilename(JFile f) {
        return sourcedir + "/" + f.name;
    }
    
    public String IndexName() {
        if (name.equals(""))
            return "default-package-idx.html";
        else
            return name + "-idx.html";
    }
        
    public void Convert2Html() {
        if (files.size() > 0) {
            VectorSorter.Sort(files);
            
            // convert all the files of this package
            Enumeration e = files.elements();
            while(e.hasMoreElements()) {
                JFile f = (JFile)e.nextElement();
                f.Convert2Html();
            }
                    
            // write an index for this package
            String indexname = Java2Html.destination + "/" + IndexName();
            try {
                PrintWriter W = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexname))));
                    
                if (name.equals("")) {
                    W.println("<html><head><title>default package</title></head><body>");
                    W.println("<b>default package</b><hr>");
                } else {
                    W.println("<html><head><title>package " + name + "</title></head><body bgcolor=ffffdd>");
                    W.println("<b>package " + name + "</b><hr>");
                }
                
                e = files.elements();
                while(e.hasMoreElements()) {
                    JFile f = (JFile)e.nextElement();
                    W.println("<a href=" + f.FullClassName() + ".html>" + f.name + "</A></BR>");
                }
                
                W.println("</body></html>");
                W.close();
            } catch (IOException ex) {
            }
    }
    }    

}

class JFile {
    Package pack;
    String name;            // filename
    
    public JFile(String name, Package pack) {
        this.name = name;
        this.pack = pack;
    }
    
    public String SourceFilename() {
        return pack.SourceFilename(this);
    }
    
    public String FullClassName() {
        return pack.FullClassName(this);
    }
    
    char[] buf = new char[1024];
    int pos = 0;
    
    final void Flush(PrintWriter W) {
        if (pos > 0) {
            String word = new String(buf, 0, pos);
            boolean key = keywords.get(word) != null;
            
            if (key) W.print("<font color=0000aa><b>");
            W.print(word);
            if (key) W.print("</b></font>");
            pos = 0;
        }
    }
    
    public void print(PrintWriter W, int ch) {
        if (ch == '<')
            W.print("&lt;");
        else if (ch == '>')
            W.print("&gt;");
        else if (ch == '&')
            W.print("&amp;");
        else if (ch == '\r') ;
        else
            W.print((char)ch);
    }
    
    public void Convert2Html() {
        try {
            System.out.println(FullClassName());
            String srcname = SourceFilename();
            String dstname = Java2Html.destination + "/" + FullClassName() + ".html";
            Reader R = new BufferedReader(new InputStreamReader(new FileInputStream(srcname)));
            PrintWriter W = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dstname))));
            
            W.println("<html><head><title>Source of " + FullClassName() + "</title></head><body bgcolor=ffffdd>");
            W.println("<b>" + FullClassName() + "</b>");
            W.println("<HR><pre>");
            int ch = R.read();
            while (ch != -1) {
                if (Alpha(ch)) {
                    buf[pos++] = (char)ch;
                } else {
                    Flush(W);
                    if (ch == '"' || ch == '\'') {     // skip strings
                        int fin = ch;
                        print(W, (char)ch);
                        ch = R.read();
                        while (ch != -1 && ch != fin) {
                            if (ch == '\\') {            // escape, takes care of \' and \"
                                print(W, (char)ch);
                                ch = R.read();
                            }
                            print(W, (char)ch);
                            ch = R.read();
                        }
                        print(W, (char)ch);
                    } else if (ch == '/') {
                        ch = R.read();
                        
                        if (ch == '/') {
                            W.print("<font color=00aa00>//");
                            ch = R.read();
                            while (ch != -1 && ch != '\n') {
                                print(W, (char)ch);
                                ch = R.read();
                            }
                            W.print("</font>");
                            W.print('\n');
                        } else if (ch == '*') {
                            W.print("<font color=00aa00>/*");
                            int cha = R.read();
                            int chb = R.read();
                            while (cha != -1) {
                                if (cha == '*' && chb == '/') {
                                    W.print("*/");
                                    break;
                                }
                                print(W, (char)cha);
                                cha = chb;
                                chb = R.read();
                            }
                            W.print("</font>");
                        } else {
                            W.print('/');
                            print(W, (char)ch);
                        }
                    } else {
                        if (ch == '\n') Java2Html.lines++;
                        print(W, (char)ch);
                    }
                }
                ch = R.read();
            }
            Flush(W);
            W.println("</pre></body></html>");
            W.close();
        } catch(IOException e) {
        }
    }
    
    boolean Alpha(int ch) {
        return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z';
    }
    
    static Hashtable keywords = new Hashtable();
    
    static {
        String kw = "boolean|char|byte|short|int|long|float|double|abstract|break|byvalue|case|cast|catch|"+
            "class|const|continue|default|do|else|extends|"+
            "false|final|finally|for|future|generic|goto|if|"+
            "implements|import|inner|instanceof|interface|"+
            "native|new|null|operator|outer|package|private|"+
            "protected|public|rest|return|static|super|switch|"+
            "synchronized|this|throw|throws|transient|true|try|"+
            "var|volatile|while|Boolean|Byte|Character|Class|ClassLoader|Cloneable|Compiler|"+
            "Double|Float|Integer|Long|Math|Number|Object|Process|"+
            "Runnable|Runtime|SecurityManager|Short|String|StringBuffer|"+
            "System|Thread|ThreadGroup|Void";
            
        Object x = new Object();
        StringTokenizer st = new StringTokenizer(kw, "|");
        while (st.hasMoreTokens()) {
            keywords.put(st.nextToken(), x);
        }
    }    
}

class VectorSorter {
    static private Vector dat;
    
    static public void Sort(Vector data) {
        dat = data;
        sort(0, dat.size() - 1);
    }
    
    static private final long compare(Object a, Object b) {
        if (a instanceof Package)
            return ((Package)a).name.compareTo(((Package)b).name);
        else
            return ((JFile)a).name.compareTo(((JFile)b).name);
    }
    
    static final void sort(int p, int r) {
        if (p < r) {
            int q = partition(p,r);
            if (q == r) 
                q--;
            sort(p,q);
            sort(q+1,r);
        }
    }

    static final int partition (int lo, int hi) {
        Object pivot = dat.elementAt(lo);
        while (true) {
            while (compare(dat.elementAt(hi), pivot) >= 0 && lo < hi) hi--;
            while (compare(dat.elementAt(lo), pivot) < 0 && lo < hi) lo++;
            if (lo < hi) {
                Object T = dat.elementAt(lo);
                dat.setElementAt(dat.elementAt(hi), lo);
                dat.setElementAt(T, hi);
            } else
                return hi;
        }
    }
}