phpdiff.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php if (!defined('PmWiki')) exit();
  2. /*
  3. Copyright 2003,2004 Nils Knappmeier (nk@knappi.org)
  4. Copyright 2004-2005 Patrick R. Michaud (pmichaud@pobox.com)
  5. This file is part of PmWiki; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published
  7. by the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version. See pmwiki.php for full details.
  9. This file implements a diff function in native PHP. It is based
  10. upon the PHPDiffEngine code written by Nils Knappmeier, who in turn
  11. had used Daniel Unterberger's diff
  12. (http://www.holomind.de/phpnet/diff.php) as the basis for his code.
  13. Pm's revision of Nils' code simply attempts to streamline it
  14. for speed (eliminate function calls and unnecessary string ops)
  15. and place everything into a single file.
  16. */
  17. ## PHPDiff returns the differences between $old and $new, formatted
  18. ## in the standard diff(1) output format.
  19. function PHPDiff($old,$new)
  20. {
  21. # split the source text into arrays of lines
  22. $t1 = explode("\n",$old);
  23. $x=array_pop($t1);
  24. if ($x>'') $t1[]="$x\n\\ No newline at end of file";
  25. $t2 = explode("\n",$new);
  26. $x=array_pop($t2);
  27. if ($x>'') $t2[]="$x\n\\ No newline at end of file";
  28. # build a reverse-index array using the line as key and line number as value
  29. # don't store blank lines, so they won't be targets of the shortest distance
  30. # search
  31. foreach($t1 as $i=>$x) if ($x>'') $r1[$x][]=$i;
  32. foreach($t2 as $i=>$x) if ($x>'') $r2[$x][]=$i;
  33. $a1=0; $a2=0; # start at beginning of each list
  34. $actions=array();
  35. # walk this loop until we reach the end of one of the lists
  36. while ($a1<count($t1) && $a2<count($t2)) {
  37. # if we have a common element, save it and go to the next
  38. if ($t1[$a1]==$t2[$a2]) { $actions[]=4; $a1++; $a2++; continue; }
  39. # otherwise, find the shortest move (Manhattan-distance) from the
  40. # current location
  41. $best1=count($t1); $best2=count($t2);
  42. $s1=$a1; $s2=$a2;
  43. while(($s1+$s2-$a1-$a2) < ($best1+$best2-$a1-$a2)) {
  44. $d=-1;
  45. foreach((array)@$r1[$t2[$s2]] as $n)
  46. if ($n>=$s1) { $d=$n; break; }
  47. if ($d>=$s1 && ($d+$s2-$a1-$a2)<($best1+$best2-$a1-$a2))
  48. { $best1=$d; $best2=$s2; }
  49. $d=-1;
  50. foreach((array)@$r2[$t1[$s1]] as $n)
  51. if ($n>=$s2) { $d=$n; break; }
  52. if ($d>=$s2 && ($s1+$d-$a1-$a2)<($best1+$best2-$a1-$a2))
  53. { $best1=$s1; $best2=$d; }
  54. $s1++; $s2++;
  55. }
  56. while ($a1<$best1) { $actions[]=1; $a1++; } # deleted elements
  57. while ($a2<$best2) { $actions[]=2; $a2++; } # added elements
  58. }
  59. # we've reached the end of one list, now walk to the end of the other
  60. while($a1<count($t1)) { $actions[]=1; $a1++; } # deleted elements
  61. while($a2<count($t2)) { $actions[]=2; $a2++; } # added elements
  62. # and this marks our ending point
  63. $actions[]=8;
  64. # now, let's follow the path we just took and report the added/deleted
  65. # elements into $out.
  66. $op = 0;
  67. $x0=$x1=0; $y0=$y1=0;
  68. $out = array();
  69. foreach($actions as $act) {
  70. if ($act==1) { $op|=$act; $x1++; continue; }
  71. if ($act==2) { $op|=$act; $y1++; continue; }
  72. if ($op>0) {
  73. $xstr = ($x1==($x0+1)) ? $x1 : ($x0+1).",$x1";
  74. $ystr = ($y1==($y0+1)) ? $y1 : ($y0+1).",$y1";
  75. if ($op==1) $out[] = "{$xstr}d{$y1}";
  76. elseif ($op==3) $out[] = "{$xstr}c{$ystr}";
  77. while ($x0<$x1) { $out[] = '< '.$t1[$x0]; $x0++; } # deleted elems
  78. if ($op==2) $out[] = "{$x1}a{$ystr}";
  79. elseif ($op==3) $out[] = '---';
  80. while ($y0<$y1) { $out[] = '> '.$t2[$y0]; $y0++; } # added elems
  81. }
  82. $x1++; $x0=$x1;
  83. $y1++; $y0=$y1;
  84. $op=0;
  85. }
  86. $out[] = '';
  87. return join("\n",$out);
  88. }
  89. $DiffFunction = 'PHPDiff';