1 40 41 package org.snipsnap.versioning.cookbook; 42 43 import org.snipsnap.versioning.ChangeInfo; 44 45 import java.util.ArrayList ; 46 import java.util.List ; 47 import java.util.StringTokenizer ; 48 49 58 59 public class CookbookDiff { 60 private ChangeInfo last; 61 private List lines = new ArrayList (); 62 63 64 private final int UNREAL = Integer.MAX_VALUE; 65 66 67 private SourceInfo oldInfo, newInfo; 68 69 79 private int blocklen[]; 80 81 82 public List diff(String oldText, String newText) { 83 oldInfo = new SourceInfo(); 84 newInfo = new SourceInfo(); 85 86 87 inputScan(oldText, oldInfo); 88 inputScan(newText, newInfo); 89 90 92 oldInfo.alloc(); 93 newInfo.alloc(); 94 95 blocklen = new int[(oldInfo.maxLine > newInfo.maxLine ? 96 oldInfo.maxLine : newInfo.maxLine) + 2]; 97 98 99 transform(); 100 return printOut(); 101 } 102 103 108 void inputScan(String input, SourceInfo pinfo) { 109 pinfo.maxLine = 0; 110 StringTokenizer tokenizer = new StringTokenizer (input, "\n\r"); 111 while (tokenizer.hasMoreTokens()) { 112 String line = tokenizer.nextToken(); 113 storeLine(line, pinfo); 114 } 115 } 116 117 123 void storeLine(String linebuffer, SourceInfo pinfo) { 124 int linenum = ++pinfo.maxLine; 125 if (linenum > SourceInfo.MAXLINECOUNT) { 126 System.err.println("MAXLINECOUNT exceeded, must stop."); 127 } 128 pinfo.symbol[linenum] = 129 Node.addSymbol(linebuffer, pinfo == oldInfo, linenum); 130 } 131 132 139 void transform() { 140 141 int oldline, newline; 142 int oldmax = oldInfo.maxLine + 2; 143 int newmax = newInfo.maxLine + 2; 144 145 for (oldline = 0; oldline < oldmax; oldline++) 146 oldInfo.other[oldline] = -1; 147 for (newline = 0; newline < newmax; newline++) 148 newInfo.other[newline] = -1; 149 150 scanUnique(); 151 scanAfter(); 152 scanBefore(); 153 scanBlocks(); 154 } 155 156 164 void scanUnique() { 165 int oldline, newline; 166 Node psymbol; 167 168 for (newline = 1; newline <= newInfo.maxLine; newline++) { 169 psymbol = newInfo.symbol[newline]; 170 if (psymbol.symbolIsUnique()) { oldline = psymbol.linenum; 172 newInfo.other[newline] = oldline; oldInfo.other[oldline] = newline; 174 } 175 } 176 newInfo.other[0] = 0; 177 oldInfo.other[0] = 0; 178 newInfo.other[newInfo.maxLine + 1] = oldInfo.maxLine + 1; 179 oldInfo.other[oldInfo.maxLine + 1] = newInfo.maxLine + 1; 180 } 181 182 192 void scanAfter() { 193 int oldline, newline; 194 195 for (newline = 0; newline <= newInfo.maxLine; newline++) { 196 oldline = newInfo.other[newline]; 197 if (oldline >= 0) { 198 for (; ;) { 199 if (++oldline > oldInfo.maxLine) break; 200 if (oldInfo.other[oldline] >= 0) break; 201 if (++newline > newInfo.maxLine) break; 202 if (newInfo.other[newline] >= 0) break; 203 204 206 207 if (newInfo.symbol[newline] != 208 oldInfo.symbol[oldline]) 209 break; 211 newInfo.other[newline] = oldline; oldInfo.other[oldline] = newline; 213 } 214 } 215 } 216 } 217 218 223 void scanBefore() { 224 int oldline, newline; 225 226 for (newline = newInfo.maxLine + 1; newline > 0; newline--) { 227 oldline = newInfo.other[newline]; 228 if (oldline >= 0) { 229 for (; ;) { 230 if (--oldline <= 0) break; 231 if (oldInfo.other[oldline] >= 0) break; 232 if (--newline <= 0) break; 233 if (newInfo.other[newline] >= 0) break; 234 235 237 238 if (newInfo.symbol[newline] != 239 oldInfo.symbol[oldline]) 240 break; 242 newInfo.other[newline] = oldline; oldInfo.other[oldline] = newline; 244 } 245 } 246 } 247 } 248 249 254 void scanBlocks() { 255 int oldline, newline; 256 int oldfront = 0; int newlast = -1; 259 for (oldline = 1; oldline <= oldInfo.maxLine; oldline++) 260 blocklen[oldline] = 0; 261 blocklen[oldInfo.maxLine + 1] = UNREAL; 263 for (oldline = 1; oldline <= oldInfo.maxLine; oldline++) { 264 newline = oldInfo.other[oldline]; 265 if (newline < 0) 266 oldfront = 0; 267 else { 268 if (oldfront == 0) oldfront = oldline; 269 if (newline != (newlast + 1)) oldfront = oldline; 270 ++blocklen[oldfront]; 271 } 272 newlast = newline; 273 } 274 } 275 276 277 public static final int 280 idle = 0, delete = 1, insert = 2, movenew = 3, moveold = 4, 281 same = 5, change = 6; 282 int printstatus; 283 boolean anyprinted; 284 int printoldline, printnewline; 286 290 private List printOut() { 291 List result = new ArrayList (); 292 293 printstatus = idle; 294 anyprinted = false; 295 for (printoldline = printnewline = 1; ;) { 296 if (printoldline > oldInfo.maxLine) { 297 newConsume(result); 298 break; 299 } 300 if (printnewline > newInfo.maxLine) { 301 oldConsume(result); 302 break; 303 } 304 if (newInfo.other[printnewline] < 0) { 305 if (oldInfo.other[printoldline] < 0) 306 showChange(result); 307 else 308 showInsert(result); 309 } else if (oldInfo.other[printoldline] < 0) 310 showDelete(result); 311 else if (blocklen[printoldline] < 0) 312 skipOld(); 313 else if (oldInfo.other[printoldline] == printnewline) 314 showSame(result); 315 else 316 showMove(result); 317 } 318 setLast(result); 319 return result; 320 } 321 322 323 private void setLast(ChangeInfo info, List result) { 327 setLast(result); 328 last = info; 329 } 330 331 private void setLast(List result) { 332 if (null != last) { 333 last.setLines((String []) lines.toArray(new String [0])); 334 result.add(last); 335 } 336 lines = new ArrayList (); 337 } 338 339 343 private void newConsume(List result) { 344 for (; ;) { 345 if (printnewline > newInfo.maxLine) 346 break; 347 if (newInfo.other[printnewline] < 0) 348 showInsert(result); 349 else 350 showMove(result); 351 } 352 } 353 354 359 private void oldConsume(List result) { 360 for (; ;) { 361 if (printoldline > oldInfo.maxLine) 362 break; 363 printnewline = oldInfo.other[printoldline]; 364 if (printnewline < 0) 365 showDelete(result); 366 else if (blocklen[printoldline] < 0) 367 skipOld(); 368 else 369 showMove(result); 370 } 371 } 372 373 377 private void showDelete(List result) { 378 if (printstatus != delete) { 379 ChangeInfo info = new ChangeInfo(ChangeInfo.DELETE, printoldline, printoldline); 380 setLast(info, result); 381 } 382 printstatus = delete; 383 lines.add(oldInfo.symbol[printoldline].getSymbol()); 384 anyprinted = true; 385 printoldline++; 386 } 387 388 392 private void showInsert(List result) { 393 if (printstatus == change) { 394 } else if (printstatus != insert) { 396 ChangeInfo info = new ChangeInfo(ChangeInfo.INSERT, printoldline, printoldline); 397 setLast(info, result); 398 } 399 printstatus = insert; 400 lines.add(newInfo.symbol[printnewline].getSymbol()); 401 anyprinted = true; 402 printnewline++; 403 } 404 405 410 private void showChange(List result) { 411 if (printstatus != change) { 412 ChangeInfo info = new ChangeInfo(ChangeInfo.CHANGE, printoldline, printoldline); 413 setLast(info, result); 414 } 415 printstatus = change; 416 lines.add(oldInfo.symbol[printoldline].getSymbol()); 417 anyprinted = true; 418 printoldline++; 419 } 420 421 427 private void skipOld() { 428 printstatus = idle; 429 for (; ;) { 430 if (++printoldline > oldInfo.maxLine) 431 break; 432 if (oldInfo.other[printoldline] < 0) 433 break; 434 if (blocklen[printoldline] != 0) 435 break; 436 } 437 } 438 439 445 private void skipNew() { 446 int oldline; 447 printstatus = idle; 448 for (; ;) { 449 if (++printnewline > newInfo.maxLine) 450 break; 451 oldline = newInfo.other[printnewline]; 452 if (oldline < 0) 453 break; 454 if (blocklen[oldline] != 0) 455 break; 456 } 457 } 458 459 464 private void showSame(List result) { 465 int count; 466 printstatus = idle; 467 if (newInfo.other[printnewline] != printoldline) { 468 System.err.println("BUG IN LINE REFERENCING"); 469 } 470 count = blocklen[printoldline]; 471 printoldline += count; 472 printnewline += count; 473 } 474 475 480 private void showMove(List result) { 481 int oldblock = blocklen[printoldline]; 482 int newother = newInfo.other[printnewline]; 483 int newblock = blocklen[newother]; 484 485 if (newblock < 0) 486 skipNew(); else if (oldblock >= newblock) { blocklen[newother] = -1; ChangeInfo info = new ChangeInfo(ChangeInfo.MOVE, newother, printoldline); 490 setLast(info, result); 491 for (; newblock > 0; newblock--, printnewline++) 492 lines.add(newInfo.symbol[printnewline].getSymbol()); 493 anyprinted = true; 494 printstatus = idle; 495 496 } else 497 skipOld(); 498 } 499 } 500 501 ; 502 503 508 class Node { 509 Node pleft, pright; 510 int linenum; 511 512 static final int freshnode = 0, 513 oldonce = 1, newonce = 2, bothonce = 3, other = 4; 514 515 int linestate; 516 String line; 517 518 static Node panchor = null; 519 520 Node(String pline) { 521 pleft = pright = null; 522 linestate = freshnode; 523 524 line = pline; 525 } 526 527 531 static Node matchsymbol(String pline) { 532 int comparison; 533 Node pnode = panchor; 534 if (panchor == null) return panchor = new Node(pline); 535 for (; ;) { 536 comparison = pnode.line.compareTo(pline); 537 if (comparison == 0) return pnode; 538 539 if (comparison < 0) { 540 if (pnode.pleft == null) { 541 pnode.pleft = new Node(pline); 542 return pnode.pleft; 543 } 544 pnode = pnode.pleft; 545 } 546 if (comparison > 0) { 547 if (pnode.pright == null) { 548 pnode.pright = new Node(pline); 549 return pnode.pright; 550 } 551 pnode = pnode.pright; 552 } 553 } 554 555 } 556 557 562 static Node addSymbol(String pline, boolean inoldfile, int linenum) { 563 Node pnode; 564 pnode = matchsymbol(pline); 565 if (pnode.linestate == freshnode) { 566 pnode.linestate = inoldfile ? oldonce : newonce; 567 } else { 568 if ((pnode.linestate == oldonce && !inoldfile) || 569 (pnode.linestate == newonce && inoldfile)) 570 pnode.linestate = bothonce; 571 else 572 pnode.linestate = other; 573 } 574 if (inoldfile) pnode.linenum = linenum; 575 return pnode; 576 } 577 578 584 public boolean symbolIsUnique() { 585 return (linestate == bothonce); 586 } 587 588 591 public String getSymbol() { 592 return line; 593 } 594 } 595 596 597 class SourceInfo { 598 static final int MAXLINECOUNT = 20000; 599 600 public int maxLine; 601 Node symbol[]; 602 int other[]; 603 604 605 606 609 SourceInfo() { 610 symbol = new Node[MAXLINECOUNT + 2]; 611 other = null; } 613 614 void alloc() { 616 other = new int[symbol.length + 2]; 617 } 618 } 619 620 ; | Popular Tags |