Pretty.java

Pretty is an application that formats the java source code in order to make it more readable, with the possibility to remove comments from the source code. It is also possible to convert the java source code in colorized HTML. Download pretty.jar


As an example, here is the output of Pretty applied to itself:

/* Program pretty: used to reformat a java program in order to look better
05-11-2005	Version 0.1: initial release
05-11-2006	Version 0.2: minor changes
10-11-2007	Version 0.3: conversion to html now supported

Usage: java Pretty [-notabs] [-nocomment] [-strings] [-html] [-help] <filename> [<outfile>]

-notabs     use blanks instead of tabs
-nocomment  remove every comment
-strings    print-out strings
-html       convert java source to html, colorize java source
-help       print this help message

Requires Java 1.5

javalc6
*/
import java.io.*;
import parser.*;
import java.util.ArrayList;

enum State { SOURCE, STRING, COMMENT, SHORT_COMMENT, CHAR }

interface callback {
    void print(String s, State state);
    void println(String s, State state);
}

public class Pretty {
    boolean notabs, nocomment, strings, html;
    PrintWriter out = null;
    boolean newline;
    int column;
    final String blanks = new blanks().generate(1000);
    String color; // used only for html


    final boolean testmode = false; // testmode, normally false


    private class blanks {
        String generate(int num) {
            String result ="";
            for (int i = 0; i < num; i++) result += " ";
            return (result);
        }
    };

    private class HandleSource implements callback {
        public void print(String s, State state) { 
            StringBuffer str = new StringBuffer();
            if (s.length() == 0) return;
            if ((state == State.SOURCE) && newline) {  
                // source in newline
                String ss = removeLeadingChars(s);
                
                if ((ss.length() > 0) && (ss.charAt(0) == '}')) column--;

                if (notabs) str.append(blanks.substring(0,column*4));
                else for (int i =0; i < column; i++)
                { str.append("\t"); }
                str.append(ss);

                for (int i = 0; i < ss.length(); i++) {   
                    if (ss.charAt(i) == '{') column++;
                    if ((i > 0)&&(ss.charAt(i) == '}')) column--;
                }
            }
            else { 
                if (!nocomment) str.append(s);
                else if (state != State.COMMENT) // comment
                str.append(s);

                if (state == State.SOURCE) // source
                for (int i = 0; i < s.length(); i++) {   
                    if (s.charAt(i) == '{') column++;
                    if (s.charAt(i) == '}') column--;
                }
            }
            if (html)	printHTML(str, state);
            else out.print(str);
            newline = false;
        }
        public void println(String s, State state) { 
            print(s, state);
            out.println();
            newline = true;
        }
    }


    Pretty (String [] files, boolean notabs, boolean nocomment, boolean strings, boolean html) {
        this.notabs = notabs;
        this.nocomment = nocomment;
        this.strings = strings;
        this.html = html;

        java.util.Arrays.sort(Java.keywords);
        newline = true;
        column = 0;
        try	{
            String result;
            if (files.length == 2)	result = files[1];
            else	if (html) result = files[0]+".html";
            else result = files[0]+".new";
            LineNumberReader in = new LineNumberReader(new FileReader(files[0]));
            long zz = System.currentTimeMillis();
            out = open(result, files[0]);
            syntax(in, new HandleSource());
            close(out);
            if (testmode) {	
                System.out.println("Result: "+lazyCompare(new File(files[0]), new File(result))+"       Elapsed time (ms): "+(System.currentTimeMillis() - zz));
            }
            else System.out.println("Elapsed time (ms): "+(System.currentTimeMillis() - zz));
        }
        catch (IOException ex)	{  
            System.err.println(ex.toString());
            if (out != null)
            out.close();
        }
    }
    
    void syntax (LineNumberReader in, callback cb) throws IOException {
        String s;
        State state = State.SOURCE;
        while ((s = in.readLine()) != null) {
            int marker = 0;

            main: // for each char in string
            for (int i = 0; i < s.length(); i++)
            {
                switch (state)
                {   
                    case SOURCE : // source 
                    if (s.startsWith("//", i))
                    {	cb.print(s.substring(marker, i), state);  // source
                        marker = i;
                        state = State.SHORT_COMMENT; // short_comment
                        break main;
                    }
                    if (s.startsWith("/*", i))
                    {	cb.print(s.substring(marker, i), state);  // source
                        marker = i;
                        state = State.COMMENT; // comment
                        break;
                    }
                    if (s.charAt(i) == '\"')
                    {	cb.print(s.substring(marker, i), state);  // source
                        marker = i;
                        state = State.STRING; // string
                        break;
                    }
                    if (s.charAt(i) == '\'')
                    {	cb.print(s.substring(marker, i), state);  // source
                        marker = i;
                        state = State.CHAR; // char
                        break;
                    }
                    break;
                    case STRING: // string
                    if (s.charAt(i) == '\"')
                    {	cb.print(s.substring(marker, i), state);  // string
                        if (strings) System.out.println(s.substring(marker, i+1));
                        marker = i;
                        state = State.SOURCE; // source
                    }
                    if (s.charAt(i) == '\\') i++; // escape, skip
                    break;
                    case COMMENT: // comment
                    if (s.startsWith("*/", i))
                    {	cb.print(s.substring(marker, i+2), state);  // comment
                        marker = i+2;
                        state = State.SOURCE; // source
                    } // else if (s.indexOf("*/", i) == -1) break main;
                    break;
                    case SHORT_COMMENT: // short_comment
                    throw new RuntimeException("Assert failed");
                    case CHAR: // char
                    if (s.charAt(i) == '\'')
                    {	cb.print(s.substring(marker, i), State.STRING);  // string ???
                        marker = i;
                        state = State.SOURCE; // source
                    }
                    if (s.charAt(i) == '\\') i++; // escape, skip
                    break;
                }
            }
// all chars in the current line were analysed
            switch (state)
            {   
                case SOURCE : // source 
                cb.println(s.substring(marker), state);  // source
                break;
                case STRING: // string
                throw new IOException("Wrong syntax: string not terminated correctly at line "+in.getLineNumber());
                case COMMENT: // comment
                cb.println(s.substring(marker), state);  // comment
                break;
                case SHORT_COMMENT: // short_comment
                cb.println(s.substring(marker), State.COMMENT);  // comment (even if it is short...)
                state = State.SOURCE; // source
                break;
                case CHAR: // char
                throw new IOException("Wrong syntax: char not terminated correctly at line "+in.getLineNumber());
            }


// main while
        }
        in.close();	
    }
    
    String removeLeadingChars(String line) {
        int i=0;
        while ((i < line.length())&&((line.charAt(i) == ' ')||(line.charAt(i) == '\t'))) i++;
        return (line.substring(i));
        
    }


    PrintWriter open(String filename, String source) throws IOException {
        PrintWriter out = new PrintWriter(new FileWriter(new File(filename)));
        if (html) {
            out.println();
            out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
            out.println("<html>");
            out.println("<head>");
            out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">");
            out.println("<meta name=\"description\" content=\"Programmi Java\">");
            out.println("<title>"+encodeHTML(new StringBuffer(source))+"</title>");
            out.println("</head>");
            out.println("<body><pre><font color=\"#000000\">");
            color = "#000000"; // used only for html
        }
        return out;
    }

    void close(PrintWriter out) {
        if (html) {
            out.println("</font></pre></body>");
            out.println("</html>");
        }
        out.close();
    }

    boolean testAlfa(char ch) {
        return ((ch >= 'a')&&(ch <= 'z'))||((ch >= 'A')&&(ch <= 'Z'));
    }

    boolean testDigit(char ch) {
        return ((ch >= '0')&&(ch <= '9'));
    }

    void printHTML(StringBuffer str, State state) {
        String oldcolor = color;
        switch (state)	{   
            case SOURCE : color = "#000000";
            break;
            case COMMENT : color = "#339966";
            break;
            default: color = "#0033CC";
        }
        if (!color.equals(oldcolor)) {
            out.print("</font><font color=\""+color+"\">");
        }
        if (state == State.SOURCE) {
            int i = 0;
            while (i < str.length())	{
// skips blank and tabs
                char ch = str.charAt(i);
                if (testAlfa(ch)||(ch == '_')||(ch == '$'))	{
                    StringBuffer id = new StringBuffer();
                    do {
                        id.append(ch);
                        i++;
                        if (i >= str.length()) break;
                        ch = str.charAt(i);
                    }
                    while (testAlfa(ch)||(ch == '_')||(ch == '$') || testDigit(ch));
                    if (java.util.Arrays.binarySearch(Java.keywords, id.toString()) >= 0)
                    out.print("<b>"+encodeHTML(id)+"</b>");
                    else out.print(encodeHTML(id));
                }
                if (i >= str.length()) break;
                out.print(encodeHTML(new StringBuffer(str.substring(i,i+1))));
                i++;
            }
        } else	out.print(encodeHTML(str));
    }

    public StringBuffer encodeHTML(StringBuffer s)	{
        StringBuffer out = new StringBuffer();
        for(int i=0; i<s.length(); i++)
        {
            char c = s.charAt(i);
            if(c > 127 || c=='"' || c=='<' || c=='>') {
                out.append("&#"+(int)c+";");
            }
            else if (c=='"') out.append("&quot;");
            else if (c=='<') out.append("&lt;");
            else if (c=='>') out.append("&gt;");
            else if (c=='&') out.append("&amp;");
            else {
                out.append(c);
            }
        }
        return out;
    }

    public static boolean lazyCompare(File file1, File file2) throws IOException {
        InputStream bufferedInput1 = new BufferedInputStream(new java.io.FileInputStream(file1));
        InputStream bufferedInput2 = new BufferedInputStream(new java.io.FileInputStream(file2));
        int ch = bufferedInput1.read();
        int ch2 = bufferedInput2.read();
        while(true)	{
            while ((-1 != ch)&&(" \t\n\r".indexOf(ch) != -1)) {
                ch = bufferedInput1.read();
            }
            while ((-1 != ch2)&&(" \t\n\r".indexOf(ch2) != -1)) {
                ch2 = bufferedInput2.read();
            }
            if (ch == -1) return -1 == ch2;
//			System.err.println(ch+"<->"+ch2);
            if( ch != ch2 ) return false;
            ch = bufferedInput1.read();
            ch2 = bufferedInput2.read();
        }
    }

//main	
    public static void main(String[] args) throws ParserException
    {
        Parser cli = new Parser();
        Option notabs = cli.addOption("-notabs", false, null,"use blanks instead of tabs");
        Option nocomment = cli.addOption("-nocomment", false, null,"remove every comment");
        Option strings = cli.addOption("-strings", false, null,"print-out strings");
        Option html = cli.addOption("-html", false, null,"convert java to html");
        cli.addOption("-help", false, null,"print this help message");
        String [] result = cli.parse(args);
        if ((result.length > 0)&&(result.length < 3)) {
            if (new File(result[0]).isDirectory()) System.err.println("Error: "+result[0]+" is a directory!");
            else new Pretty(result, cli.hasOption(notabs), cli.hasOption(nocomment), cli.hasOption(strings), cli.hasOption(html));
        }
        else System.err.println("Usage: java Pretty"+cli.getUsage("<filename> [<outfile>]"));
    }
}


Share Share on Facebook Share on Twitter Bookmark on Reddit Share via mail
Privacy Policy Creative Commons Attribution-Share Alike Trovami