// J2H.java
// Application converts Java source into displayable HTML
// J. W. Rider, 21 July 2000

import java.io.*;
import java.util.*;                     // Vector

public class J2H
{
    // All standard Java identifiers will be displayed
    // in a special way.

    final static String identifiers[] =
    {
"abstract", "default",  "if",           "private",      "throw",
"boolean",  "do",       "implements",   "protected",    "throws",
"break",    "double",   "import",       "public",       "transient",
"byte",     "else",     "instanceof",   "return",       "true",
"case",     "extends",  "int",          "short",        "try",
"catch",    "false",    "interface",    "static",       "void",
"char",     "final",    "long",         "strictfp",     "volatile",
"class",    "finally",  "native",       "super",        "while",
"const",    "float",    "new",          "switch",
"continue", "for",      "null",         "synchronized",
            "goto",     "package",      "this"
    };

    static Vector keyw = new Vector(identifiers.length);

    static
    {
      for (int i = 0; i < identifiers.length; i++)
          keyw.addElement(identifiers[i]);
    }

    // Default color definitions
    static int tabsize = 1;
    static String bgcolor = "";
    static String txcolor = "";
    static String kwcolor = "0000F0";
    static String cmcolor = "A00000";
    static String stcolor = "00A000";

    // invariant HTML strings
    final static String BEGINHTML = "<html>\r\n<head>\r\n<title>";
    final static String BEGINBODY = "</title>\r\n</head>\r\n<body ";
    final static String FONTCOLOR = "<font color= \"";
    final static String ENDFONT   = "</font>";
    final static String ENDTAG    = "\">";
    final static String BOLD      = "<B>";
    final static String ENDBOLD   = "</B>";
    final static String ITAL      = "<EM>";
    final static String ENDITAL   = "</EM>";

    // color-dependent HTML strings
    static String BEGINKEYW = ((kwcolor.length()>0)
                                 ?FONTCOLOR+kwcolor+ENDTAG
                                 :"")+BOLD;

    static String ENDOFKEYW = ENDBOLD+((kwcolor.length()>0)
                                 ?ENDFONT:"");

    static String BEGINCOMMENT = ((cmcolor.length()>0)
                                 ?FONTCOLOR+cmcolor+ENDTAG
                                 :"")+ITAL;

    static String ENDOFCOMMENT = "</em>"+((cmcolor.length()>0)
                                 ?ENDFONT:"");

    static void resetColors()
    {
      BEGINKEYW = ((kwcolor.length()>0)
                   ?FONTCOLOR+kwcolor+ENDTAG
                   :"")+BOLD;

      ENDOFKEYW = "</b>"+((kwcolor.length()>0)
                          ?"</font>":"");

      BEGINCOMMENT = ((cmcolor.length()>0)
                      ?"<font color= \""+cmcolor+"\">"
                      :"")+"<em>";

      ENDOFCOMMENT = "</em>"+((cmcolor.length()>0)
                              ?"</font>":"");
    }

    // convert(String) is the primary procedure
    static void convert(String source) throws IOException
    {
      // output file is source file plus extension ".html"
      String newSource;
      int lastdot=source.lastIndexOf(".");
      newSource=source.substring(0,lastdot)+"_"
               +source.substring(lastdot+1,source.length());
      String dest = newSource + ".html";

      // Display the name of the file being processed
      System.out.println(dest);
      FileReader in = new FileReader(source);
      FileWriter out = new FileWriter(dest);

      out.write(BEGINHTML);
      out.write(source);              // title is name of file
      out.write(BEGINBODY);

      if ( bgcolor.length()>0 )
        out.write("bgcolor=\"" + bgcolor +"\" ");

      if (txcolor.length()>0)
        out.write("text=\"" + txcolor +"\" ");

      out.write(">\r\n<pre>\r\n");    // "pre" is fixed width font

      StringBuffer buf = new StringBuffer(2048);

      int c = 0, kwl = 0, bufl = 0;
      char ch = ' ', lastch;
      int s_normal  = 0;
      int s_string  = 1;
      int s_char    = 2;
      int s_comline = 3;
      int s_comment = 4;
      int state = s_normal;

      while (c != -1)
      {
        c = in.read();
        lastch = ch;
        ch = c >= 0 ? (char) c : 0;
        if (state == s_normal)
          if ((kwl == 0
             && Character.isJavaIdentifierStart(ch)
             && !Character.isJavaIdentifierPart(lastch))
          || (kwl > 0
             && Character.isJavaIdentifierPart(ch)))
          {
             buf.append(ch);
             bufl++;
             kwl++;
             continue;
          }
          else if (kwl > 0)
          {
            String kw =
              buf.toString().substring(buf.length() - kwl);
            if (keyw.contains(kw))
            {
              buf.insert(buf.length() - kwl,BEGINKEYW);
              buf.append(ENDOFKEYW);
            }
            kwl = 0;
          }
       switch (ch)
       {
            case '&':  // ampersands treated special in HTML
              buf.append("&amp;");
              bufl++;
              break;

            case '\"': // double quote treated special in HTML

              // if the quote is the beginning of the string
              // change to string color and start underlining
              // after the quote character
              if (state == s_normal)
              {
                buf.append("<font color=\""+stcolor+"\">");
                buf.append("&quot;");
                bufl++;
                buf.append("<u>");
                state = s_string;
              }

              //if the quote is the end of a string
              // stop underlining and restore normal color
              else if (state == s_string && lastch != '\\')
              {
                buf.append("</u>");
                buf.append("&quot;");
                bufl++;
                buf.append("</font>");
                state = s_normal;
              }

              //otherwise output the quote char in a normal way
              else
              {
                buf.append("&quot;"); bufl++;
              }
              break;

            case '\'': //single quote
              buf.append("\'");
              bufl++;
              if (state == s_normal)
                state = s_char;
              else if (state == s_char && lastch != '\\')
                state = s_normal;
              break;

            case '\\':                // backslash
              buf.append("\\");
              bufl++;
              // however if the preceding character were also
              // a backslash, we want to consider this backslash
              // as having been processed so that "\\" and '\\'
              // will not be interpreted as double or single
              // quote.
              if (lastch == '\\'
              && (state == s_string || state == s_char))
                ch = 0;
              break;

            case '/': //slash
              buf.append("/");
              bufl++;
              // star-slash used to end a comment
              if (state == s_comment && lastch == '*')
              {
                buf.append(ENDOFCOMMENT);
                state = s_normal;
              }
              // slash-slash used to start a comment
              else if (state == s_normal && lastch == '/')
              {
                buf.insert(buf.length() - 2,
                           "<font color=\"" + cmcolor + "\"><em>");
                state = s_comline;
              }
              break;

            case '*': //asterisk
              buf.append("*");
              bufl++;
              // slash-star used to start a comment
              if (state == s_normal && lastch == '/')
              {
                buf.insert(buf.length() - 2,
                           "<font color=\"" + cmcolor + "\"><em>");
                state = s_comment;
              }
              break;

            case '<': //less-than handled special in HTML
              buf.append("&lt;");
              bufl++;
              break;

            case '>': //greater-than handled special in HTML
              buf.append("&gt;");
              bufl++;
              break;

            case '\t': //embedded tab used for formatting lines
              int n = bufl / tabsize * tabsize + tabsize;
              while (bufl < n)
              {
                buf.append(' ');
                bufl++;
              }
              break;

            case '\r':
            case '\n':
              if (state == s_comline)
              {
                buf.append(ENDOFCOMMENT);
                state = s_normal;
              }
              buf.append(ch);
              if (buf.length() >= 1024)
              {
                out.write(buf.toString());
                buf.setLength(0);
              }
              bufl = 0;
              if (kwl != 0)
                kwl = 0; // This should never execute
              if (state != s_normal && state != s_comment)
                state = s_normal; // Syntax Error
              break;

             case 0:                    // end of input file
              if (c < 0)
              {
                if (state == s_comline)
                {
                  buf.append(ENDOFCOMMENT);
                  state = s_normal;
                }
                out.write(buf.toString());
                buf.setLength(0);
                bufl = 0;
                if (state == s_comment)
                {
                  // Syntax Error
                  buf.append(ENDOFCOMMENT);
                  state = s_normal;
                }
                break;
              }

             default:
                bufl++;
                buf.append(ch);
         } //end of switch(ch)
      }
      out.write("</pre>\r\n</body>\r\n</html>");
      in.close();
      out.close();
    }

    public static void main(String args[])
    {
      if (args.length < 1 || args.length > 2)
      {
        System.out.println(
          "j2h converter + syntax coloring + tabs2spaces");

        System.out.println("");

        System.out.println(
          "java  [java_opt]  j2h  [properties_file]  source");

        System.out.println("");

        System.out.println(
          "  - java is the name of the Java interpreter");

        System.out.println(
          "  - java_opt are the options of the Java interpreter");

        System.out.println(
          "  - j2h is the name of this application");

        System.out.println(
          "  - properties_file (optional) is the path ");

        System.out.println(
          "    of a file which has a structure like this:");

        System.out.println(
"        tabsize=number  (default value is 1)");

        System.out.println(
"        bgcolor=RRGGBB   - background");

        System.out.println(
"        txcolor=RRGGBB   - source code");

        System.out.println(
"        kwcolor=RRGGBB  (default value is 0000F0) - keywords");

        System.out.println(
"        cmcolor=RRGGBB  (default value is A00000) - comments");

        System.out.println(
"        stcolor=RRGGBB  (default value is 00A000) - strings");

        System.out.println(
"  - source is a file or the directory to the Java source file(s)");

        System.out.println("");
        System.out.println("Examples:");
        System.out.println("    java  j2h  j2h.java");
        System.out.println("    java  j2h  C:\\TEMP");
        System.out.println(
                         "    java  j2h  j2h.properties  C:\\TEMP");
        System.exit(1);
      }
      String source, propfile;
      if (args.length == 2)
      {
        propfile = args[0];
        source = args[1];
      }
      else
      {
        propfile = "j2h.properties";
        source = args[0];
      }

      try
      {
        InputStream in = new FileInputStream(propfile);
        Properties prop = new Properties();
        prop.load(in);
        in.close();
        tabsize = Integer.parseInt(prop.getProperty("tabsize",
                                                    "1"));
        bgcolor = "#" + prop.getProperty("bgcolor", bgcolor);
        txcolor = "#" + prop.getProperty("txcolor", txcolor);
        kwcolor = "#" + prop.getProperty("kwcolor", kwcolor);
        cmcolor = "#" + prop.getProperty("cmcolor", cmcolor);
        stcolor = "#" + prop.getProperty("stcolor", stcolor);
        resetColors();
      }
      catch (FileNotFoundException e)
      {
      }
      catch (IOException e)
      {
        System.out.println(e);
      }
      catch (NumberFormatException e)
      {
        System.out.println(e);
      }

      File f = new File(source);
      if (f.isFile())
      {
        try
        {
          convert(f.getPath());
        }
        catch (IOException e)
        {
          System.out.println(e);
        }
      }
      else if (f.isDirectory())
      {
        try
        {
          String src[] = f.list();
          for (int i = 0; i < src.length; i++)
            if (src[i].endsWith(".java"))
              convert(new File(f, src[i]).getPath());
        }
        catch (IOException e)
        {
          System.out.println(e);
        }
      }
      else
      {
          System.out.println(
      "The source parameter must be an existent file or directory");
          System.out.println("Run j2h without parameters for help");
      }
    } //end of main()
}//end of class J2H

 
 
1