mirror of
https://github.com/UnickSoft/graphonline.git
synced 2025-07-01 15:26:12 +00:00
118 lines
4.4 KiB
PHP
Executable File
118 lines
4.4 KiB
PHP
Executable File
<?php if (!defined('PmWiki')) exit();
|
|
/*
|
|
Copyright 2003,2004 Nils Knappmeier (nk@knappi.org)
|
|
Copyright 2004-2010 Patrick R. Michaud (pmichaud@pobox.com)
|
|
|
|
This file is part of PmWiki; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published
|
|
by the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version. See pmwiki.php for full details.
|
|
|
|
This file implements a diff function in native PHP. It is based
|
|
upon the PHPDiffEngine code written by Nils Knappmeier, who in turn
|
|
had used Daniel Unterberger's diff
|
|
(http://www.holomind.de/phpnet/diff.php) as the basis for his code.
|
|
|
|
Pm's revision of Nils' code simply attempts to streamline it
|
|
for speed (eliminate function calls and unnecessary string ops)
|
|
and place everything into a single file.
|
|
|
|
*/
|
|
|
|
## PHPDiff returns the differences between $old and $new, formatted
|
|
## in the standard diff(1) output format.
|
|
function PHPDiff($old, $new)
|
|
{
|
|
StopWatch("PHPDiff: begin");
|
|
# split the source text into arrays of lines
|
|
$t1 = explode("\n", $old);
|
|
$x = array_pop($t1);
|
|
if ($x > '') $t1[] = "$x\n\\ No newline at end of file";
|
|
$t2 = explode("\n", $new);
|
|
$x = array_pop($t2);
|
|
if ($x > '') $t2[] = "$x\n\\ No newline at end of file";
|
|
|
|
$t1_start = 0; $t1_end = count($t1);
|
|
$t2_start = 0; $t2_end = count($t2);
|
|
|
|
# stop with a common ending
|
|
while ($t1_start < $t1_end && $t2_start < $t2_end
|
|
&& $t1[$t1_end-1] == $t2[$t2_end-1]) { $t1_end--; $t2_end--; }
|
|
|
|
# skip over any common beginning
|
|
while ($t1_start < $t1_end && $t2_start < $t2_end
|
|
&& $t1[$t1_start] == $t2[$t2_start]) { $t1_start++; $t2_start++; }
|
|
|
|
# build a reverse-index array using the line as key and line number as value
|
|
# don't store blank lines, so they won't be targets of the shortest distance
|
|
# search
|
|
for($i = $t1_start; $i < $t1_end; $i++) if ($t1[$i]>'') $r1[$t1[$i]][] = $i;
|
|
for($i = $t2_start; $i < $t2_end; $i++) if ($t2[$i]>'') $r2[$t2[$i]][] = $i;
|
|
|
|
$a1 = $t1_start; $a2 = $t2_start; # start at beginning of each list
|
|
$actions = array();
|
|
|
|
# walk this loop until we reach the end of one of the lists
|
|
while ($a1 < $t1_end && $a2 < $t2_end) {
|
|
# if we have a common element, save it and go to the next
|
|
if ($t1[$a1] == $t2[$a2]) { $actions[] = 4; $a1++; $a2++; continue; }
|
|
|
|
# otherwise, find the shortest move (Manhattan-distance) from the
|
|
# current location
|
|
$best1 = $t1_end; $best2 = $t2_end;
|
|
$s1 = $a1; $s2 = $a2;
|
|
while(($s1 + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2)) {
|
|
$d = -1;
|
|
foreach((array)@$r1[$t2[$s2]] as $n)
|
|
if ($n >= $s1) { $d = $n; break; }
|
|
if ($d >= $s1 && ($d + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2))
|
|
{ $best1 = $d; $best2 = $s2; }
|
|
$d = -1;
|
|
foreach((array)@$r2[$t1[$s1]] as $n)
|
|
if ($n >= $s2) { $d = $n; break; }
|
|
if ($d >= $s2 && ($s1 + $d - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2))
|
|
{ $best1 = $s1; $best2 = $d; }
|
|
$s1++; $s2++;
|
|
}
|
|
while ($a1 < $best1) { $actions[] = 1; $a1++; } # deleted elements
|
|
while ($a2 < $best2) { $actions[] = 2; $a2++; } # added elements
|
|
}
|
|
|
|
# we've reached the end of one list, now walk to the end of the other
|
|
while($a1 < $t1_end) { $actions[] = 1; $a1++; } # deleted elements
|
|
while($a2 < $t2_end) { $actions[] = 2; $a2++; } # added elements
|
|
|
|
# and this marks our ending point
|
|
$actions[] = 8;
|
|
|
|
# now, let's follow the path we just took and report the added/deleted
|
|
# elements into $out.
|
|
$op = 0;
|
|
$x0 = $x1 = $t1_start; $y0 = $y1 = $t2_start;
|
|
$out = array();
|
|
foreach($actions as $act) {
|
|
if ($act == 1) { $op |= $act; $x1++; continue; }
|
|
if ($act == 2) { $op |= $act; $y1++; continue; }
|
|
if ($op > 0) {
|
|
$xstr = ($x1 == ($x0+1)) ? $x1 : ($x0+1) . ",$x1";
|
|
$ystr = ($y1 == ($y0+1)) ? $y1 : ($y0+1) . ",$y1";
|
|
if ($op == 1) $out[] = "{$xstr}d{$y1}";
|
|
elseif ($op == 3) $out[] = "{$xstr}c{$ystr}";
|
|
while ($x0 < $x1) { $out[] = '< ' . $t1[$x0]; $x0++; } # deleted elems
|
|
if ($op == 2) $out[] = "{$x1}a{$ystr}";
|
|
elseif ($op == 3) $out[] = '---';
|
|
while ($y0 < $y1) { $out[] = '> '.$t2[$y0]; $y0++; } # added elems
|
|
}
|
|
$x1++; $x0 = $x1;
|
|
$y1++; $y0 = $y1;
|
|
$op = 0;
|
|
}
|
|
$out[] = '';
|
|
StopWatch("PHPDiff: end");
|
|
return join("\n",$out);
|
|
}
|
|
|
|
if (!function_exists(@$DiffFunction))
|
|
$DiffFunction = 'PHPDiff';
|
|
|