/*
* Kompare - Visual Navigation of Source Tree diff using HTML
*
* Released under GPL http://www.gnu.org/copyleft/gpl.html
*
* Usage:
*
* javac Kompare.java
* java Komapre <path to source tree 1> <path to source tree 2>
*
* All HTML files will be generated in the same directory
* from where Kompare is ran from, Open the generated
* "index.html" to start navigating the source diff.
*
* kishan@hackorama.com www.hackorama.com 2001 APRIL
*
*/
import java.io.*;
import java.util.*;
import java.text.*;
public class Kompare
{
public static void main( String args[] )
{
if( args.length < 2 ){
System.out.print("\n Usage: java Kompare " );
System.out.print(" <path to source directory 1>" );
System.out.println(" <path to source directory 2>\n" );
}else{
String one = args[0];
String two = args[1];
Kompare kompare = new Kompare( one, two );
}
}
// modify these to list different source file types , file types not listed
// here will be ignored while parsing
String[] source_types = { ".c" , ".h" , ".cc", ".cpp" , ".C", ".H", ".CC", ".CPP" };
// if there is any folder in a source tree which need not be parsed list
// it here and it will not be parsed
String[] ignore_folders = { " " };
private Vector a_dirlist = new Vector();
private Vector b_dirlist = new Vector();
private String a_dir;
private String b_dir;
private String a_base;
private String b_base;
private int[] _a;
private int[] _b;
private String[] a_files;
private String[] b_files;
private int a_len = 0;
private int b_len = 0;
private int a_count = 0;
private int b_count = 0;
private int a_match = 0;
private int b_match = 0;
private String[] a_column;
private String[] b_column;
private String firstpage;
private int page_count = 0 ;
private static DataOutputStream out = null;
private static DataOutputStream para = null;
private static boolean first_time = true;
String style = "style=\"text-decoration:none\"";
private int i_files = 0;
private int j_files = 0;
private int k_files = 0;
private int i_lines = 0;
private int j_lines = 0;
private int i_bytes = 0;
private int j_bytes = 0;
private int i_total = 0;
private int j_total = 0;
private int k_total = 0;
private int i_tot_lines = 0;
private int j_tot_lines = 0;
private int i_tot_bytes = 0;
private int j_tot_bytes = 0;
private String green = "#DDFFDD";
private String red = "#FFDDDD";
private String bg_one = "#EEEEEE";
private String a_start;
private String b_start;
private int a_dir_lines = 0;
private int b_dir_lines = 0;
private int a_dir_files = 0;
private int b_dir_files = 0;
private long elapsed = 0 ;
public Kompare( String one , String two )
{
while ( one.endsWith( "/" ) || one.endsWith( "\" ) ){
one = one.substring( 0 , one.length() - 1 );
}
while ( two.endsWith( "/" ) || two.endsWith( "\" ) ){
two = two.substring( 0 , two.length() - 1 );
}
a_dirlist.addElement( one );
b_dirlist.addElement( two );
a_base = one.substring( 0, one.lastIndexOf("/") );
b_base = two.substring( 0, two.lastIndexOf("/") );
firstpage = makeFilename( one );
a_start = one;
b_start = two;
open_para( "complete.html" );
init_para();
long startTime = java.lang.System.currentTimeMillis();
ignite();
elapsed = java.lang.System.currentTimeMillis() - startTime;
final_report();
end_para();
close_para();
}
private String makeFilename( String str)
{
str = str.replace('/', '_')+".html";
str = str.replace('\\', '_');
if( str.startsWith( ".." ) )
str = str.substring( 2 );
if( str.startsWith( "." ) )
str = str.substring( 1 );
return str ;
}
public void ignite()
{
for( int i = 0 ; i < a_dirlist.size() ; i++ ){
int match = dir_matching(i);
if( match >= 0 ){
String a = (String) a_dirlist.elementAt(i);
String b = (String) b_dirlist.elementAt(match);
a_dirlist.removeElementAt(i);
b_dirlist.removeElementAt(match);
step( a , b );
}else{
//a_dirlist.removeElementAt(i);
}
}
//b_dirlist.removeAllElements();
}
private Vector x_list = new Vector();
public void dir_parse( String dir , int option )
{
print( "dir parsing "+ dir +" ("+ option +")");
File x = new File( dir );
String[] x_files = x.list();
for ( int i=0; i < x_files.length; i++) {
String the_file = dir+"/"+x_files[i];
if( is_directory(the_file) ){
x_list.addElement(the_file );
}else{
int lines = get_lines(the_file);
if(option == 1){
i_lines+=lines;
a_dir_lines+=lines;
}else if (option == 2 ){
j_lines+=lines;
b_dir_lines+=lines;
}
}
if(option == 1) {
j_files++;
a_dir_files++;
}else if (option == 2 ) {
k_files++;
b_dir_files++;
}
}
//recurse subdirectories
for ( int i=0; i < x_list.size() ; i++) {
String the_file = (String) x_list.elementAt(i);
x_list.removeElementAt(i);
dir_parse( the_file , option );
}
}
private int dir_matching( int i )
{
if( first_time ){
first_time = false ;
return 0;
}
for( int j = 0 ; j < b_dirlist.size() ; j++ ){
String one = (String) a_dirlist.elementAt(i);
String two = (String) b_dirlist.elementAt(j);
one = one.substring( one.lastIndexOf("/") );
two = two.substring( two.lastIndexOf("/") );
if( one.equals(two) )
return j;
}
return -1 ;
}
public void step( String _a_dir , String _b_dir )
{
print( "working "+_a_dir +" : " + _b_dir );
a_len = 0;
b_len = 0;
a_count = 0;
b_count = 0;
a_dir = _a_dir;
b_dir = _b_dir;
File a = new File( a_dir );
File b = new File( b_dir );
a_files = a.list();
b_files = b.list();
a_len = a_files.length;
b_len = b_files.length;
_a = new int[ a_len ] ;
_b = new int[ b_len ] ;
a_column = new String[ a_len ];
b_column = new String[ b_len ];
for( int i = 0 ; i < _a.length ; i++ )
_a[i] = 0;
for( int i = 0 ; i < _b.length ; i++ )
_b[i] = 0;
parse();
//recurse through the directories
ignite();
}
public void parse()
{
parse_matching();
parse_missing();
parse_additions();
report();
}
private void report()
{
String thispage = makeFilename( a_dir );
open_page(thispage); page_count++;
i_files = 0;
j_files = 0;
k_files = 0;
i_lines = 0;
j_lines = 0;
i_bytes = 0;
j_bytes = 0;
init_page();
for( int i = 0 ; i < a_column.length ; i ++ ){
if( i < b_column.length ){
print_elem( i , a_column[i] , b_column[i] );
if( i >= a_match ) {
j_files++;
k_files++;
}else{
i_files++;
}
}else{
print_elem( i , a_column[i] , null );
j_files++;
}
}
if( b_column.length > a_column.length ){
for( int i = a_column.length ; i < b_column.length ; i++ ){
print_elem( i , null , b_column[i] );
k_files++;
}
}
i_total+=i_files;
j_total+=j_files;
k_total+=k_files;
i_tot_lines+=i_lines;
j_tot_lines+=j_lines;
i_tot_bytes+=i_bytes;
j_tot_bytes+=j_bytes;
end_page();
int change = i_lines-j_lines;
double percent = 0.0 ;
String color = "white" ;
if( change > 0 ){
percent = ( (float)change/(float)i_lines ) * 100.0 ;
color = "green";
pprint("<tr><td><a href="+thispage+">"+a_dir+"</a> </td><td>"+j_files+"</td><td>"+k_files+"</td><td>"+i_lines+"</td><td>"+j_lines+"</td><td>+"+change+"</td>");
}else{
percent = ( ((float)change*-1.0)/(float)j_lines ) * 100.0 ;
color = "red";
pprint("<tr><td><a href="+thispage+">"+a_dir+"</a> </td><td>"+j_files+"</td><td>"+k_files+"</td><td>"+i_lines+"</td><td>"+j_lines+"</td><td>"+change+"</td>");
}
pprint_graph( percent , color );
pprint("</tr>");
close_page();
}
private void init_para()
{
pprint("<html><body bgcolor=white link=black vlink=black>");
pprint("<br><br>");
pprint("<table border=0><tr><td bgcolor="+bg_one+">");
pprint("<b>|<a "+style+" href=index.html>MAIN |</a></b>");
pprint("</td></tr><tr><td>");
pprint("<br><br><table border=1>");
pprint("<tr><td>dir</td><td>files(-)</td><td>files(+)</td><td>lines(old)</td><td>lines(new)</td><td>lines(change)</td><td>lines %</td></tr>");
}
private void end_para()
{
pprint("</table><br><br>");
pprint("</td></tr><tr><td bgcolor="+bg_one+">");
pprint("<b>|<a "+style+" href=index.html>MAIN |</a></b>");
pprint("</td></tr></table>");
pprint("<br><br>");
pprint("</body></html>");
}
private void clean_leftout()
{
for( int i = 0 ; i < a_dirlist.size() ; i++ ){
print("removed:" +a_dirlist.elementAt(i) );
}
for( int i = 0 ; i < b_dirlist.size() ; i++ ){
print("added:" +b_dirlist.elementAt(i) );
}
}
private void final_report()
{
int a_total = i_total + j_total;
int b_total = i_total + k_total;
//int line_change = i_tot_lines - j_tot_lines ;
int line_change = j_tot_lines - i_tot_lines ;
SimpleDateFormat format = new SimpleDateFormat( "MM/dd/yyyy" );
open_page("index.html");
fprint("<html><body bgcolor=white link=black vlink=black alink=red><br><br>");
fprint("<table border=0><tr><td bgcolor="+bg_one+">");
fprint("<b>KOMPARE SOURCE DIFF</b>");
fprint("</td></tr><tr><td>");
fprint("<br><br>");
fprint("Source location:");
fprint("<table border=1 width=100%>");
fprint("<tr><td>");
fprint("OLD");
fprint("</td><td>");
fprint("<b>"+a_start+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td>");
fprint("NEW");
fprint("</td><td>");
fprint("<b>"+b_start+"</b><br>");
fprint("</td></tr>");
fprint("</table>");
fprint("<br><br>");
fprint("Diff Summary");
fprint("<table border=1 width=100%>");
fprint("<tr><td>");
fprint("total files ( old - new )");
fprint("</td><td>");
fprint("<b>"+ a_total +"-"+ b_total +"</b><br>");
fprint("</td></tr>");
fprint("<tr><td bgcolor="+red+">");
fprint("removed files");
fprint("</td><td>");
fprint("<b>"+j_total+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td bgcolor="+green+">");
fprint("added files");
fprint("</td><td>");
fprint("<b>"+k_total+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td>");
fprint("total source lines ( old - new = changed )");
fprint("</td><td>");
fprint("<b>"+i_tot_lines+"-"+j_tot_lines+"="+line_change+"</b><br>");
fprint("</td></tr>");
fprint("</table>");
fprint("<br>");
fprint("Diff Details");
fprint("</td></tr><tr><td bgcolor="+bg_one+">");
fprint("<a href="+firstpage+">NAVIGATE SOURCE TREE</a>");
fprint("</td></tr><tr><td>");
fprint("<br><br>");
fprint("Quick View");
fprint("</td></tr><tr><td bgcolor="+bg_one+">");
fprint("<a href=complete.html>DIRECTORY ONLY LISTING</a>");
fprint("</td></tr><tr><td>");
fprint("<br><br>");
int g_files = a_total + b_total;
int g_lines = i_tot_lines + j_tot_lines;
fprint("Parse Info");
fprint("<table border=1 width=100%>");
fprint("<tr><td>");
fprint("total files");
fprint("</td><td>");
fprint("<b>"+g_files +"</b><br>");
fprint("</td></tr>");
fprint("<tr><td>");
fprint("total source lines");
fprint("</td><td>");
fprint("<b>"+g_lines +"</b><br>");
fprint("</td></tr>");
String legend = "milliseconds" ;
double ela = 0.0 ;
if( elapsed > 1000 ){
ela = (double)elapsed /1000.0;
legend = "seconds" ;
if( ela > 60.0 ){
ela = ela / 60.0 ;
legend = "minutes" ;
}
}
fprint("<tr><td>");
fprint("elapsed time");
fprint("</td><td>");
fprint("<b>"+ela+" "+legend+"</b><br>");
fprint("</td></tr>");
fprint("</table>");
fprint("<br><br>");
fprint("Source file types<br>");
for( int i = 0 ; i < source_types.length ; i++ ){
fprint(source_types[i] +", ");
}
fprint("<br><br>");
fprint("</td></tr><tr><td align=right bGcolor="+bg_one+">");
fprint("<font size=-2>");
fprint("GENEARTED USING <a href=http://www.hackorama.com/kompare>KOMPARE</a> ON ");
fprint(format.format( new Date()));
fprint("</font>");
fprint("</td></tr></table>");
fprint("<br></body></html>");
close_page();
}
private boolean is_directory( String filename)
{
for( int i = 0 ; i < ignore_folders.length ; i++ ){
if( filename.endsWith("/"+ignore_folders[i]) ) return false;
}
File temp = new File(filename);
return temp.isDirectory();
}
private int get_size( String filename)
{
int size = 0;
File temp = new File(filename);
try{
FileInputStream in = new FileInputStream( temp );
size = in.available();
in.close();
}catch( IOException e ){ }
return size;
}
private int get_lines( String filename)
{
if( is_source(filename)){
int count = 0;
File temp = new File(filename);
try{
FileReader in = new FileReader( temp );
LineNumberReader lines = new LineNumberReader( in );
while( lines.readLine() != null )
count = lines.getLineNumber();
in.close();
}catch( IOException e ){ }
return count;
}else{
return 0 ;
}
}
private boolean is_source( String filename )
{
for( int i = 0 ; i < source_types.length ; i++ ){
if( filename.endsWith(source_types[i])) return true;
}
return false;
}
static boolean once = true;
private void init_page()
{
fprint("<html><head><title>diff</title></head>");
fprint("<body bgcolor=white text=black link=black vlink=black alink=orange>");
String last = a_dir.substring( 0, a_dir.lastIndexOf("/") );
if( once ){
last = "index.html" ;
once = false;
}else{
last = makeFilename( last );
}
fprint("<table border=0><tr><td bgcolor="+bg_one+">");
fprint("<b><a "+style+" href="+last+">| BACK</a> | <a "+style+" href=index.html>MAIN |</a></b>");
fprint("</td></tr><tr><td>");
fprint("<br><br>");
fprint("<table border=1 width=100%>");
fprint("<tr><td>");
fprint("OLD");
fprint("</td><td>");
fprint("<b>"+a_dir+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td>");
fprint("NEW");
fprint("</td><td>");
fprint("<b>"+b_dir+"</b><br>");
fprint("</td></tr>");
fprint("</table>");
fprint("<br>");
fprint("<table border=1>");
fprint("<tr>");
fprint("<td>#</td><td>OLD</td><td>NEW</td><td>lines</td><td>%</td>");
fprint("</tr>");
}
static boolean b_once = true;
private void end_page()
{
int a_total = i_files + j_files ;
int b_total = i_files + k_files ;
//int file_change = a_total - b_total ;
//int line_change = i_lines - j_lines ;
int file_change = b_total - a_total ;
int line_change = j_lines - i_lines ;
String last = a_dir.substring( 0, a_dir.lastIndexOf("/") );
if( b_once ){
last = "index.html" ;
b_once = false;
}else{
last = makeFilename( last );
}
fprint("</table>");
fprint("<br><br>");
fprint("<table border=1 width=100%>");
fprint("<tr><td>");
fprint("total files ( old - new )");
fprint("</td><td>");
//fprint("<b>"+ a_total +"-"+ b_total +"="+file_change+"</b><br>");
fprint("<b>"+ a_total +"-"+ b_total +"</b><br>");
fprint("</td></tr>");
fprint("<tr><td bgcolor="+red+">");
fprint("files removed");
fprint("</td><td>");
fprint("<b>"+j_files+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td bgcolor="+green+">");
fprint("files added");
fprint("</td><td>");
fprint("<b>"+k_files+"</b><br>");
fprint("</td></tr>");
fprint("<tr><td>");
fprint("source lines ( old - new = changed )");
fprint("</td><td>");
fprint("<b>"+i_lines+"-"+j_lines+"="+line_change+"</b><br>");
fprint("</td></tr>");
fprint("</table>");
fprint("<br><br>");
fprint("</td></tr><tr><td bgcolor="+bg_one+">");
fprint("<b><a "+style+" href="+last+">| BACK</a> | <a "+style+" href=index.html>MAIN |</a></b>");
fprint("</td></tr></table>");
fprint("</body>");
fprint("</html>");
}
private void open_page( String pagename )
{
try {
out = new DataOutputStream( new FileOutputStream(new File(pagename)));
}catch( IOException e ){ }
}
private void open_para( String pagename )
{
try {
para = new DataOutputStream( new FileOutputStream(new File(pagename)));
}catch( IOException e ){ }
}
private void close_page()
{
if ( out != null ) try { out.close(); } catch ( IOException e) { }
}
private void close_para()
{
if ( para != null ) try { para.close(); } catch ( IOException e) { }
}
private void print_elem( int i , String one , String two )
{
a_dir_lines = 0;
b_dir_lines = 0;
a_dir_files = 0;
b_dir_files = 0;
boolean matching = false;
boolean a_directory = false;
boolean b_directory = false;
String a_color = "white";
String b_color = "white";
String a_file = a_dir+"/"+one;
String b_file = b_dir+"/"+two;
if( one != null && two!= null ){
if( one.equals(two) ) matching = true ;
}
a_directory = is_directory(a_file);
String next = makeFilename( a_file );
if( a_directory && matching ){
a_dirlist.addElement( a_file );
one = "<b>"+one+"</b>";
if( one != null ) one = "<a "+style+" href="+next+">"+one+"</a>";
}else{
if(a_directory){
//a_dirlist.addElement( a_file );
dir_parse( a_file , 1);
one = "<b>"+one+"</b> ("+a_dir_files+"/"+a_dir_lines+")";
}
if( one != null ){
if( is_source( a_file ) ){
one = "<a href="+a_file+">"+one+"</a> ("+get_lines(a_file)+")";
}else{
one = "<a "+style+" href="+a_file+">"+one+"</a>";
}
}
}
b_directory = is_directory(b_file);
if( b_directory && matching ){
b_dirlist.addElement( b_file );
two = "<b>"+two+"</b>";
if( two != null ) two = "<a "+style+" href="+next+">"+two+"</a>";
}else{
if( b_directory ){
//b_dirlist.addElement( b_file );
dir_parse( b_file , 2);
//two = "<b>"+two+"</b>";
two = "<b>"+two+"</b> ("+b_dir_files+"/"+b_dir_lines+")";
}
if( two != null ) {
if( is_source( b_file ) ){
two = "<a href="+b_file+">"+two+"</a> ("+get_lines(b_file)+")";
}else{
two = "<a "+style+" href="+b_file+">"+two+"</a>";
}
}
}
if( i >= a_match && one != null) a_color = red;
if( i >= b_match && two != null) b_color = green;
fprint("<tr>");
if ( one == null ){
fprint( "<td>"+i+"</td><td> </td><td bgcolor="+b_color+">"+two+"</td>");
}else if ( two == null ){
fprint( "<td>"+i+"</td><td bgcolor="+a_color+">"+ one +"</td><td> </td>" );
}else{
fprint( "<td>"+i+"</td><td bgcolor="+a_color+">"+ one +"</td><td bgcolor="+b_color+">"+two+ "</td>" );
}
/*******
if( !a_directory && !b_directory && matching ){
//int change = get_size(a_file) - get_size(b_file);
int change = get_size(b_file) - get_size(a_file);
if(change > 0 )
fprint( "<td bgcolor="+green+">+"+change+"</td>" );
else if(change < 0 )
fprint( "<td bgcolor="+red+">"+change+"</td>" );
else
fprint( "<td> </td>" );
}else{
fprint( "<td> </td>" );
}
********/
if( !a_directory && !b_directory && matching ){
int a_lines = get_lines(a_file) ;
int b_lines = get_lines(b_file) ;
i_lines += a_lines ;
j_lines += b_lines ;
//int change = a_lines - b_lines ;
int change = b_lines - a_lines ;
if(change > 0 ){
fprint( "<td bgcolor="+green+">+"+change+"</td>" );
double percent = ((float)change/(float)b_lines ) * 100.0;
print_graph( percent , "green" );
}else if(change < 0 ){
fprint( "<td bgcolor="+red+">"+change+"</td>" );
double percent = ( ((float)change*-1.0)/(float)a_lines ) * 100.0;
print_graph( percent ,"red" );
}else{
fprint( "<td> </td>" );
fprint( "<td> </td>" );
}
}else{
fprint( "<td> </td>" );
if( one != null && !a_directory ) i_lines += get_lines(a_file) ;
if( two != null && !b_directory ) j_lines += get_lines(b_file) ;
fprint( "<td> </td>" );
}
fprint("</tr>");
}
private void print_graph( double x , String color )
{
//x = 100.0 - x ;
fprint2( "<td width=100>" );
if( x > 1.0 ){
fprint2( "<table border=0 width=100 cellpadding=0 cellspacing=0><tr><td bgcolor="+color+" width="+x+"%>" );
fprint2( " </td><td> </td></tr></table>" );
} else {
fprint2( " " );
}
fprint2( "</td>" );
}
private void pprint_graph( double x , String color )
{
//x = 100.0 - x ;
pprint( "<td width=100>" );
if( x > 1.0 ){
pprint( "<table border=0 width=100 cellpadding=0 cellspacing=0><tr><td bgcolor="+color+" width="+x+"%>" );
pprint( " </td><td> </td></tr></table>" );
} else {
pprint( " " );
}
pprint( "</td>" );
}
private void parse_missing()
{
for( int i = 0 ; i < _a.length ; i++ ){
if( _a[i] == 0 ){
a_column[ a_count ] = a_files[i] ; a_count++;
}else {
//print ( "**"+ i +" "+ _a.length +" "+ a_count );
}
}
}
private