| /* |
| |
| Derby - Class org.apache.derbyTesting.functionTests.harness.SimpleDiff |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| |
| //SimpleDiff.java |
| package org.apache.derbyTesting.functionTests.harness; |
| |
| import java.io.IOException; |
| import java.io.BufferedInputStream; |
| import java.util.Vector; |
| import java.io.File; |
| import java.io.PrintWriter; |
| import java.io.BufferedReader; |
| import java.io.FileReader; |
| |
| public class SimpleDiff |
| { |
| |
| PrintWriter pw; |
| |
| boolean debugOn = Boolean.getBoolean("simplediff.debug"); |
| int debugLevel = 1; |
| |
| boolean diffsFound = true; |
| |
| int lookAhead = 20; |
| |
| public void debug(int level, String msg) |
| { |
| if (debugLevel >= level) |
| { |
| debug(msg); |
| } |
| } |
| public void debug(String msg) |
| { |
| if (debugOn) |
| { |
| System.out.println("DEBUG: " + msg); |
| } |
| } |
| |
| int lineCount(String file) throws IOException |
| { |
| BufferedReader input = new BufferedReader(new FileReader(file)); |
| int count = 0; |
| String aLine = input.readLine(); |
| while (aLine != null) |
| { |
| count++; |
| aLine = input.readLine(); |
| } |
| input.close(); |
| return count; |
| } |
| |
| |
| public String[] readFile(BufferedReader input) throws IOException |
| { |
| |
| Vector<String> vec = new Vector<String>(); |
| |
| String aLine = ""; |
| //int count = 0; |
| aLine = input.readLine(); |
| while (aLine != null) |
| { |
| vec.addElement(aLine); |
| //count++; |
| aLine = input.readLine(); |
| } |
| input.close(); |
| |
| String rV[] = new String[vec.size()]; |
| //debug(2, ""+count + " lines in " + filename); |
| debug(2, ""+vec.size() + " lines in input"); |
| vec.copyInto(rV); |
| |
| return rV; |
| } |
| |
| public void printFile(String file[]) |
| { |
| for (int i = 0; i < file.length; i++) |
| { |
| pw.println(i + ": " + file[i]); |
| System.out.println(i + ": " + file[i]); |
| } |
| } |
| |
| public static String usage = "java SimpleDiff <file1> <file2>"; |
| |
| /** |
| @param file1 Name of first file to be read |
| @param file2 Name of file with which to compare |
| @return String array of file contents |
| @exception IOException thrown by underlying calls |
| to the file system |
| */ |
| |
| public String[] diffFiles( DiffBuffer file1, |
| DiffBuffer file2) |
| throws IOException |
| { |
| |
| int currentLine1 = 0; |
| int currentLine2 = 0; |
| Vector<String> returnVec = new Vector<String>(); |
| |
| while ( file1.isValidOffset(currentLine1) && |
| file2.isValidOffset(currentLine2)) |
| { |
| String f1 = file1.lineAt(currentLine1); |
| String f2 = file2.lineAt(currentLine2); |
| |
| if (f1.equals(f2)) |
| { |
| debug(1, currentLine1 + ": match"); |
| currentLine1++; |
| currentLine2++; |
| file1.setLowWater(currentLine1); |
| file2.setLowWater(currentLine2); |
| } |
| else |
| { |
| boolean foundMatch = false; |
| int checkLine2 = currentLine2; |
| int checkCount = 1; |
| // while ( (currentLine2 + checkCount) < (file2Length - 1) && |
| while ( file2.isValidOffset(currentLine2 + checkCount) && |
| checkCount < lookAhead) |
| { |
| debug(1, "currentLine1 " + currentLine1 + " currentLine2 " + (currentLine2 +checkCount)); |
| debug(1, "about to reference file2[" + (currentLine2 + checkCount) + "]"); |
| f2 = file2.lineAt(currentLine2 + checkCount); |
| debug(2, "did"); |
| if (f1.equals(f2)) |
| { |
| foundMatch = true; |
| if (checkCount > 1) |
| { |
| returnVec.addElement(currentLine1 + "a" + (currentLine2 + 1) + "," + (currentLine2 + checkCount)); |
| } |
| else |
| { |
| returnVec.addElement(currentLine1 + "a" + (currentLine2 + 1)); |
| } |
| |
| for (int j = 0; j < checkCount; j++) |
| { |
| returnVec.addElement("> " + |
| file2.lineAt(currentLine2 + j) ); |
| } |
| currentLine2 = currentLine2 + checkCount; |
| checkCount = 0; |
| |
| // This break statement was commented out, which |
| // caused problems in the diff output. I don't |
| // know why it was commented out, and uncommenting |
| // it fixed the problem. |
| // |
| // - Jeff Lichtman |
| // March 24, 1999 |
| break; |
| } |
| checkCount ++; |
| } |
| if (!foundMatch && file2.isValidOffset(currentLine2)) |
| { |
| int checkLine1 = currentLine1; |
| checkCount = 1; |
| f2 = file2.lineAt(currentLine2); |
| while ( file1.isValidOffset(currentLine1 + checkCount) && |
| checkCount < lookAhead) |
| { |
| debug(1, "currentLine2 " + currentLine2 + " currentLine1 " + (currentLine1 + checkCount)); |
| f1 = file1.lineAt(currentLine1 + checkCount); |
| if ( f2.equals(f1)) |
| { |
| foundMatch = true; |
| if (checkCount > 1) |
| { |
| returnVec.addElement((currentLine1 + 1) + "," + (currentLine1 + checkCount) + "d" + currentLine2); |
| } |
| else |
| { |
| returnVec.addElement((currentLine1 + 1) + "d" + currentLine2); |
| } |
| |
| for (int j = 0; j < checkCount; j++) |
| { |
| returnVec.addElement("< " + |
| file1.lineAt(currentLine1 + j) ); |
| |
| } |
| currentLine1 = currentLine1 + checkCount; |
| checkCount = 0; |
| debug(1, "continuing"); |
| break; |
| } |
| checkCount ++; |
| } |
| |
| } |
| if (!foundMatch) |
| { |
| debug(1, currentLine1 + ": NOMATCH"); |
| returnVec.addElement((currentLine1 + 1) +" del");// + (currentLine2 + 1)); |
| returnVec.addElement("< " + file1.lineAt(currentLine1)); |
| currentLine1++; |
| } |
| else |
| { |
| currentLine1++; |
| currentLine2++; |
| file1.setLowWater(currentLine1); |
| file2.setLowWater(currentLine2); |
| } |
| } |
| } |
| |
| if (file1.isValidOffset(currentLine1)) |
| { |
| returnVec.addElement((currentLine2) + " del"); |
| for (int i = currentLine1; file1.isValidOffset(i); i++) |
| { |
| returnVec.addElement("< " + file1.lineAt(i)); |
| } |
| } |
| if (file2.isValidOffset(currentLine2)) |
| { |
| returnVec.addElement((currentLine1) + " add"); |
| for (int i = currentLine2; file2.isValidOffset(i); i++) |
| { |
| returnVec.addElement("> " + file2.lineAt(i)); |
| } |
| } |
| |
| file1.close(); |
| file2.close(); |
| |
| if (returnVec.isEmpty()) |
| { |
| return null; |
| } |
| |
| |
| String [] returnArray = new String[returnVec.size()]; |
| returnVec.copyInto(returnArray); |
| return returnArray; |
| |
| |
| } |
| |
| private void reportMemory() |
| { |
| reportMemory(null); |
| } |
| |
| private void reportMemory(String header) |
| { |
| if (header != null) |
| { |
| System.out.println(header); |
| } |
| long free = Runtime.getRuntime().freeMemory(); |
| long total = Runtime.getRuntime().totalMemory(); |
| |
| System.out.println("total: " + total ); |
| System.out.println("free: " + free ); |
| System.out.println("used: " + (total - free)); |
| System.gc(); |
| System.out.println("used: <postgc> " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); |
| System.out.println(" "); |
| } |
| |
| public boolean doWork(BufferedReader in1, BufferedReader in2, PrintWriter localPW) throws IOException |
| { |
| this.pw=(localPW==null?new PrintWriter(System.out):localPW); |
| try |
| { |
| DiffBuffer db1 = new DiffBuffer(in1, "1"); |
| DiffBuffer db2 = new DiffBuffer(in2, "2"); |
| |
| String diffs[] = diffFiles(db1, db2); |
| |
| if (diffs == null) |
| { |
| debug(1, "no diff"); |
| return false; |
| } |
| else |
| { |
| for (int i = 0; i < diffs.length; i++) |
| { |
| this.pw.println(diffs[i]); |
| System.out.println(diffs[i]); |
| } |
| } |
| |
| } |
| catch (IOException ioe) |
| { |
| System.err.println("IOException comparing <" + in1 + |
| "> and <" + in2 + ">"); |
| System.err.println(ioe); |
| |
| this.pw.println("IOException comparing <" + in1 + |
| "> and <" + in2 + ">"); |
| this.pw.println(ioe); |
| } |
| return true; |
| } |
| public static void main(String args[]) throws IOException |
| { |
| |
| if (args.length < 2) |
| { |
| System.err.println("Invalid number of arguments"); |
| System.err.println("Usage: " + usage); |
| System.exit(1); |
| } |
| |
| SimpleDiff me = new SimpleDiff(); |
| |
| try |
| { |
| BufferedReader br1 = new BufferedReader(new FileReader(args[0])); |
| BufferedReader br2 = new BufferedReader(new FileReader(args[1])); |
| me.doWork(br1, br2, null); |
| } |
| catch (IOException ioe) |
| { |
| System.out.println("IOExeption: " + ioe); |
| } |
| } |
| |
| public void pause() |
| { |
| BufferedInputStream bis = new BufferedInputStream(System.in); |
| try |
| { |
| bis.read(); |
| } |
| catch (IOException ioe) |
| { |
| pw.println("Error trying to pause..."); |
| System.out.println("Error trying to pause..."); |
| } |
| } |
| |
| class DiffBuffer extends Vector<String> |
| { |
| |
| |
| public boolean atEOF() |
| { |
| return atEnd; |
| } |
| |
| public DiffBuffer(BufferedReader rb) |
| { |
| this(rb, ""); |
| } |
| |
| public DiffBuffer(BufferedReader rb, String name) |
| { |
| this (rb, name, 1024); |
| } |
| |
| public DiffBuffer(BufferedReader rb, String name, int size) |
| { |
| super(size); |
| readBuffer = rb; |
| currentLowWater = 0; |
| currentHighWater = -1; |
| oldLow = 0; |
| myName = name; |
| atEnd = false; |
| } |
| |
| public boolean isValidOffset(int lineNumber) throws IOException |
| { |
| if (atEnd) |
| { |
| return lineNumber <= actualEndOfFile; |
| } |
| |
| if (lineAt(lineNumber) == null) |
| { |
| return false; |
| } |
| return true; |
| } |
| |
| public String lineAt(int offset) throws IOException |
| { |
| /* |
| System.out.println("offset: " + offset); |
| System.out.println("currentHighWater: " + currentHighWater); |
| System.out.println(""); |
| */ |
| if (offset > currentHighWater) |
| { |
| for (int i = 0; i < offset - currentHighWater; i++) |
| { |
| String aLine = readBuffer.readLine(); |
| addElement(aLine); |
| /* |
| System.out.println("aLine: " + aLine); |
| */ |
| if (aLine == null) |
| { |
| if (!atEnd) |
| { |
| //first time we've tried to read past the EOF |
| actualEndOfFile = currentHighWater + i; |
| //System.out.println(myName + ": length " + actualEndOfFile); |
| atEnd = true; |
| } |
| } |
| } |
| currentHighWater = offset; |
| } |
| return (String) elementAt(offset); |
| } |
| |
| |
| public final String EMPTY = null; |
| protected BufferedReader readBuffer; |
| protected int currentLowWater; |
| protected int currentHighWater; |
| private int oldLow; |
| protected String myName; |
| protected boolean atEnd; |
| protected int actualEndOfFile; |
| /** |
| Useful to keep memory requirements low |
| */ |
| public void setLowWater(int newLow) |
| { |
| |
| for (int i = oldLow; i < newLow; i++) |
| { |
| setElementAt(EMPTY, i); |
| } |
| currentLowWater = newLow; |
| oldLow = newLow -1; |
| } |
| |
| |
| public void iterate(boolean verbose) |
| { |
| int nulls = 0; |
| int nonnulls = 0; |
| |
| |
| for (int i = 0; i < this.size(); i++) |
| { |
| if (elementAt(i) == null) |
| { |
| if (verbose) |
| { |
| System.out.print("[" + i + "] "); |
| System.out.println("null"); |
| } |
| nulls++; |
| |
| } |
| else |
| { |
| if (verbose) |
| { |
| System.out.print("[" + i + "] "); |
| System.out.println("NotNULL"); |
| } |
| nonnulls++; |
| } |
| } |
| System.out.println("nulls: " + nulls + " nonNull: " + nonnulls); |
| } |
| |
| public void close() throws IOException |
| { |
| // System.out.println("Closing BufferedReader"); |
| readBuffer.close(); |
| readBuffer = null; |
| } |
| } |
| |
| } |