/* * 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 * * 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(" " ); System.out.println(" \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(""+a_dir+" "+j_files+""+k_files+""+i_lines+""+j_lines+"+"+change+""); }else{ percent = ( ((float)change*-1.0)/(float)j_lines ) * 100.0 ; color = "red"; pprint(""+a_dir+" "+j_files+""+k_files+""+i_lines+""+j_lines+""+change+""); } pprint_graph( percent , color ); pprint(""); close_page(); } private void init_para() { pprint(""); pprint("

"); pprint("
"); pprint("|MAIN |"); pprint("
"); pprint("

"); pprint(""); } private void end_para() { pprint("
dirfiles(-)files(+)lines(old)lines(new)lines(change)lines %


"); pprint("
"); pprint("|MAIN |"); pprint("
"); pprint("

"); pprint(""); } 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("

"); fprint("
"); fprint("KOMPARE SOURCE DIFF"); fprint("
"); fprint("

"); fprint("Source location:"); fprint(""); fprint(""); fprint(""); fprint("
"); fprint("OLD"); fprint(""); fprint(""+a_start+"
"); fprint("
"); fprint("NEW"); fprint(""); fprint(""+b_start+"
"); fprint("
"); fprint("

"); fprint("Diff Summary"); fprint(""); fprint(""); fprint(""); fprint(""); fprint(""); fprint("
"); fprint("total files ( old - new )"); fprint(""); fprint(""+ a_total +"-"+ b_total +"
"); fprint("
"); fprint("removed files"); fprint(""); fprint(""+j_total+"
"); fprint("
"); fprint("added files"); fprint(""); fprint(""+k_total+"
"); fprint("
"); fprint("total source lines ( old - new = changed )"); fprint(""); fprint(""+i_tot_lines+"-"+j_tot_lines+"="+line_change+"
"); fprint("
"); fprint("
"); fprint("Diff Details"); fprint("
"); fprint("NAVIGATE SOURCE TREE"); fprint("
"); fprint("

"); fprint("Quick View"); fprint("
"); fprint("DIRECTORY ONLY LISTING"); fprint("
"); fprint("

"); int g_files = a_total + b_total; int g_lines = i_tot_lines + j_tot_lines; fprint("Parse Info"); fprint(""); fprint(""); fprint(""); 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(""); fprint("
"); fprint("total files"); fprint(""); fprint(""+g_files +"
"); fprint("
"); fprint("total source lines"); fprint(""); fprint(""+g_lines +"
"); fprint("
"); fprint("elapsed time"); fprint(""); fprint(""+ela+" "+legend+"
"); fprint("
"); fprint("

"); fprint("Source file types
"); for( int i = 0 ; i < source_types.length ; i++ ){ fprint(source_types[i] +", "); } fprint("

"); fprint("
"); fprint(""); fprint("GENEARTED USING KOMPARE ON "); fprint(format.format( new Date())); fprint(""); fprint("
"); fprint("
"); 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("diff"); fprint(""); String last = a_dir.substring( 0, a_dir.lastIndexOf("/") ); if( once ){ last = "index.html" ; once = false; }else{ last = makeFilename( last ); } fprint("
"); fprint("| BACK | MAIN |"); fprint("
"); fprint("

"); fprint(""); fprint(""); fprint(""); fprint("
"); fprint("OLD"); fprint(""); fprint(""+a_dir+"
"); fprint("
"); fprint("NEW"); fprint(""); fprint(""+b_dir+"
"); fprint("
"); fprint("
"); fprint(""); fprint(""); fprint(""); fprint(""); } 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("
#OLDNEWlines%
"); fprint("

"); fprint(""); fprint(""); fprint(""); fprint(""); fprint(""); fprint("
"); fprint("total files ( old - new )"); fprint(""); //fprint(""+ a_total +"-"+ b_total +"="+file_change+"
"); fprint(""+ a_total +"-"+ b_total +"
"); fprint("
"); fprint("files removed"); fprint(""); fprint(""+j_files+"
"); fprint("
"); fprint("files added"); fprint(""); fprint(""+k_files+"
"); fprint("
"); fprint("source lines ( old - new = changed )"); fprint(""); fprint(""+i_lines+"-"+j_lines+"="+line_change+"
"); fprint("
"); fprint("

"); fprint("
"); fprint("| BACK | MAIN |"); fprint("
"); fprint(""); fprint(""); } 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 = ""+one+""; if( one != null ) one = ""+one+""; }else{ if(a_directory){ //a_dirlist.addElement( a_file ); dir_parse( a_file , 1); one = ""+one+" ("+a_dir_files+"/"+a_dir_lines+")"; } if( one != null ){ if( is_source( a_file ) ){ one = ""+one+" ("+get_lines(a_file)+")"; }else{ one = ""+one+""; } } } b_directory = is_directory(b_file); if( b_directory && matching ){ b_dirlist.addElement( b_file ); two = ""+two+""; if( two != null ) two = ""+two+""; }else{ if( b_directory ){ //b_dirlist.addElement( b_file ); dir_parse( b_file , 2); //two = ""+two+""; two = ""+two+" ("+b_dir_files+"/"+b_dir_lines+")"; } if( two != null ) { if( is_source( b_file ) ){ two = ""+two+" ("+get_lines(b_file)+")"; }else{ two = ""+two+""; } } } if( i >= a_match && one != null) a_color = red; if( i >= b_match && two != null) b_color = green; fprint(""); if ( one == null ){ fprint( ""+i+" "+two+""); }else if ( two == null ){ fprint( ""+i+""+ one +" " ); }else{ fprint( ""+i+""+ one +""+two+ "" ); } /******* 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( "+"+change+"" ); else if(change < 0 ) fprint( ""+change+"" ); else fprint( " " ); }else{ fprint( " " ); } ********/ 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( "+"+change+"" ); double percent = ((float)change/(float)b_lines ) * 100.0; print_graph( percent , "green" ); }else if(change < 0 ){ fprint( ""+change+"" ); double percent = ( ((float)change*-1.0)/(float)a_lines ) * 100.0; print_graph( percent ,"red" ); }else{ fprint( " " ); fprint( " " ); } }else{ fprint( " " ); if( one != null && !a_directory ) i_lines += get_lines(a_file) ; if( two != null && !b_directory ) j_lines += get_lines(b_file) ; fprint( " " ); } fprint(""); } private void print_graph( double x , String color ) { //x = 100.0 - x ; fprint2( "" ); if( x > 1.0 ){ fprint2( "
" ); fprint2( "  
" ); } else { fprint2( " " ); } fprint2( "" ); } private void pprint_graph( double x , String color ) { //x = 100.0 - x ; pprint( "" ); if( x > 1.0 ){ pprint( "
" ); pprint( "  
" ); } else { pprint( " " ); } pprint( "" ); } 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 void parse_additions() { for( int i = 0 ; i < _b.length ; i++ ){ if( _b[i] == 0 ){ //print ( "->"+ i +" "+ _b.length +" "+ b_count ); b_column[ b_count ] = b_files[i] ; b_count++; }else{ //print ( "**"+ i +" "+ _b.length +" "+ b_count ); } } } private void parse_matching() { for ( int i=0; i < a_files.length; i++) { int match = loop_matching(i); if ( match >= 0 ){ //print ( "->"+ i +" "+ a_files.length +" "+ a_count +" "+ b_count ); a_column[ a_count ] = a_files[i] ; a_count++; b_column[ b_count ] = b_files[match] ; b_count++; }else{ //print ( "**"+ i +" "+ a_files.length +" "+ a_count +" "+ b_count ); } } a_match = a_count ; b_match = b_count ; } private int loop_matching( int i ) { for ( int j =0; j < b_files.length; j++) { if ( a_files[i].equals( b_files[j]) ){ _a[i] = 1; _b[j] = 1; return j; } } return -1 ; } private void print( String s) { System.out.println( s ); } private void fprint( String s) { if ( out != null ){ try{ out.writeBytes( s+"\n"); }catch( IOException e ){ } } } private void pprint( String s) { if ( para != null ){ try{ para.writeBytes( s+"\n"); }catch( IOException e ){ } } } private void fprint2( String s) { if ( out != null ){ try{ out.writeBytes(s); }catch( IOException e ){ } } } static class MyFilenameFilter implements FilenameFilter { private String extension; public MyFilenameFilter(String extension) { this.extension = extension; } public boolean accept(File dir, String name) { if ( name.endsWith(extension) ) return true; return false; } } }