// 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("&");
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(""");
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(""");
bufl++;
buf.append("</font>");
state = s_normal;
}
//otherwise output the quote char in a normal way
else
{
buf.append("""); 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("<");
bufl++;
break;
case '>': //greater-than handled special in HTML
buf.append(">");
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