xoops_trust_path/libs/altsys/include/Text_Diff.php
<?php
/**
* @brief XCL/PHP7 @gigamaster replace 'each' (deprecated) with foreach
*
* Text_Diff
*
* General API for generating and formatting diffs - the differences between
* two sequences of strings.
*
* The PHP diff code used in this package was originally written by Geoffrey
* T. Dairiki and is used with his permission.
*
* $Horde: framework/Text_Diff/Diff.php,v 1.13 2005/05/26 20:26:06 selsky Exp $
*
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*/
class Text_Diff {
/**
* Array of changes.
*
* @var array
*/
public $_edits;
/**
* Computes diffs between sequences of strings.
*
* @param array $from_lines An array of strings. Typically these are
* lines from a file.
* @param array $to_lines An array of strings.
*/
//HACK by domifara
// function Text_Diff($from_lines, $to_lines)
public function __construct( $from_lines, $to_lines ) {
array_walk( $from_lines, [ $this, '_trimNewlines' ] );
array_walk( $to_lines, [ $this, '_trimNewlines' ] );
if ( extension_loaded( 'xdiff' ) ) {
$engine = new Text_Diff_Engine_xdiff();
} else {
$engine = new Text_Diff_Engine_native();
}
$this->_edits = $engine->diff( $from_lines, $to_lines );
}
/**
* Returns the array of differences.
*/
public function getDiff() {
return $this->_edits;
}
/**
* Computes a reversed diff.
*
* Example:
* <code>
* $diff = new Text_Diff($lines1, $lines2);
* $rev = $diff->reverse();
* </code>
*
* @return Text_Diff A Diff object representing the inverse of the
* original diff. Note that we purposely don't return a
* reference here, since this essentially is a clone()
* method.
*/
public function reverse() {
if ( version_compare( zend_version(), '2', '>' ) ) {
$rev = clone( $obj );
} else {
$rev = $this;
}
$rev->_edits = [];
foreach ( $this->_edits as $edit ) {
$rev->_edits[] = $edit->reverse();
}
return $rev;
}
/**
* Checks for an empty diff.
*
* @return bool True if two sequences were identical.
*/
public function isEmpty() {
foreach ( $this->_edits as $edit ) {
if ( ! is_a( $edit, 'Text_Diff_Op_copy' ) ) {
return false;
}
}
return true;
}
/**
* Computes the length of the Longest Common Subsequence (LCS).
*
* This is mostly for diagnostic purposes.
*
* @return int The length of the LCS.
*/
public function lcs() {
$lcs = 0;
foreach ( $this->_edits as $edit ) {
if ( is_a( $edit, 'Text_Diff_Op_copy' ) ) {
$lcs += count( $edit->orig );
}
}
return $lcs;
}
/**
* Gets the original set of lines.
*
* This reconstructs the $from_lines parameter passed to the constructor.
*
* @return array The original sequence of strings.
*/
public function getOriginal() {
$lines = [];
foreach ( $this->_edits as $edit ) {
if ( $edit->orig ) {
array_splice( $lines, count( $lines ), 0, $edit->orig );
}
}
return $lines;
}
/**
* Gets the final set of lines.
*
* This reconstructs the $to_lines parameter passed to the constructor.
*
* @return array The sequence of strings.
*/
public function getFinal() {
$lines = [];
foreach ( $this->_edits as $edit ) {
if ( $edit->final ) {
array_splice( $lines, count( $lines ), 0, $edit->final );
}
}
return $lines;
}
/**
* Removes trailing newlines from a line of text. This is meant to be used
* with array_walk().
*
* @param string $line The line to trim.
* @param int $key The index of the line in the array. Not used.
*/
public function _trimNewlines( &$line, $key ) {
$line = str_replace( [ "\n", "\r" ], '', $line );
}
/**
* Checks a diff for validity.
*
* This is here only for debugging purposes.
*
* @param $from_lines
* @param $to_lines
*
* @return bool
*/
public function _check( $from_lines, $to_lines ) {
if ( serialize( $from_lines ) != serialize( $this->getOriginal() ) ) {
trigger_error( "Reconstructed original doesn't match", E_USER_ERROR );
}
if ( serialize( $to_lines ) != serialize( $this->getFinal() ) ) {
trigger_error( "Reconstructed final doesn't match", E_USER_ERROR );
}
$rev = $this->reverse();
if ( serialize( $to_lines ) != serialize( $rev->getOriginal() ) ) {
trigger_error( "Reversed original doesn't match", E_USER_ERROR );
}
if ( serialize( $from_lines ) != serialize( $rev->getFinal() ) ) {
trigger_error( "Reversed final doesn't match", E_USER_ERROR );
}
$prevtype = null;
foreach ( $this->_edits as $edit ) {
if ( $prevtype == get_class( $edit ) ) {
trigger_error( 'Edit sequence is non-optimal', E_USER_ERROR );
}
$prevtype = get_class( $edit );
}
return true;
}
}
/**
* $Horde: framework/Text_Diff/Diff.php,v 1.13 2005/05/26 20:26:06 selsky Exp $
*
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*/
class Text_MappedDiff extends Text_Diff {
/**
* Computes a diff between sequences of strings.
*
* This can be used to compute things like case-insensitve diffs, or diffs
* which ignore changes in white-space.
*
* @param array $from_lines An array of strings.
* @param array $to_lines An array of strings.
* @param array $mapped_from_lines This array should have the same size
* number of elements as $from_lines. The
* elements in $mapped_from_lines and
* $mapped_to_lines are what is actually
* compared when computing the diff.
* @param array $mapped_to_lines This array should have the same number
* of elements as $to_lines.
*/
public function __construct(
$from_lines,
$to_lines,
$mapped_from_lines,
$mapped_to_lines
) {
assert( count( $from_lines ) == count( $mapped_from_lines ) );
assert( count( $to_lines ) == count( $mapped_to_lines ) );
parent::Text_Diff( $mapped_from_lines, $mapped_to_lines );
$xi = $yi = 0;
for ( $i = 0; $i < count( $this->_edits ); $i ++ ) {
$orig = &$this->_edits[ $i ]->orig;
if ( is_array( $orig ) ) {
$orig = array_slice( $from_lines, $xi, count( $orig ) );
$xi += count( $orig );
}
$final = &$this->_edits[ $i ]->final;
if ( is_array( $final ) ) {
$final = array_slice( $to_lines, $yi, count( $final ) );
$yi += count( $final );
}
}
}
}
/**
* Class used internally by Diff to actually compute the diffs. This class
* uses the xdiff PECL package (https://pecl.php.net/package/xdiff) to compute
* the differences between the two input arrays.
*
* @author Jon Parise <jon@horde.org>
* @package Text_Diff
*
* @access private
*/
class Text_Diff_Engine_xdiff {
/**
* @param $from_lines
* @param $to_lines
*
* @return array
*/
public function diff( $from_lines, $to_lines ) {
/* Convert the two input arrays into strings for xdiff processing. */
$from_string = implode( "\n", $from_lines );
$to_string = implode( "\n", $to_lines );
/* Diff the two strings and convert the result to an array. */
$diff = xdiff_string_diff( $from_string, $to_string, count( $to_lines ) );
$diff = explode( "\n", $diff );
/* Walk through the diff one line at a time. We build the $edits
* array of diff operations by reading the first character of the
* xdiff output (which is in the "unified diff" format).
*
* Note that we don't have enough information to detect "changed"
* lines using this approach, so we can't add Text_Diff_Op_changed
* instances to the $edits array. The result is still perfectly
* valid, albeit a little less descriptive and efficient. */
$edits = [];
foreach ( $diff as $line ) {
switch ( $line[0] ) {
case ' ':
$edits[] = new Text_Diff_Op_copy( [ mb_substr( $line, 1 ) ] );
break;
case '+':
$edits[] = new Text_Diff_Op_add( [ mb_substr( $line, 1 ) ] );
break;
case '-':
$edits[] = new Text_Diff_Op_delete( [ mb_substr( $line, 1 ) ] );
break;
}
}
return $edits;
}
}
/**
* Class used internally by Diff to actually compute the diffs. This class is
* implemented using native PHP code.
*
* The algorithm used here is mostly lifted from the perl module
* Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
* https://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
*
* More ideas are taken from:
* https://www.ics.uci.edu/~eppstein/161/960229.html
*
* Some ideas (and a bit of code) are taken from analyze.c, of GNU
* diffutils-2.7, which can be found at:
* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
*
* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
* code was written by him, and is used/adapted with his permission.
*
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
* @package Text_Diff
*
* @access private
*/
class Text_Diff_Engine_native {
/**
* @param $from_lines
* @param $to_lines
*
* @return array
*/
public function diff( $from_lines, $to_lines ) {
$n_from = count( $from_lines );
$n_to = count( $to_lines );
$this->xchanged = $this->ychanged = [];
$this->xv = $this->yv = [];
$this->xind = $this->yind = [];
unset( $this->seq, $this->in_seq, $this->lcs );
// Skip leading common lines.
for ( $skip = 0; $skip < $n_from && $skip < $n_to; $skip ++ ) {
if ( $from_lines[ $skip ] != $to_lines[ $skip ] ) {
break;
}
$this->xchanged[ $skip ] = $this->ychanged[ $skip ] = false;
}
// Skip trailing common lines.
$xi = $n_from;
$yi = $n_to;
for ( $endskip = 0; -- $xi > $skip && -- $yi > $skip; $endskip ++ ) {
if ( $from_lines[ $xi ] != $to_lines[ $yi ] ) {
break;
}
$this->xchanged[ $xi ] = $this->ychanged[ $yi ] = false;
}
// Ignore lines which do not exist in both files.
for ( $xi = $skip; $xi < $n_from - $endskip; $xi ++ ) {
$xhash[ $from_lines[ $xi ] ] = 1;
}
for ( $yi = $skip; $yi < $n_to - $endskip; $yi ++ ) {
$line = $to_lines[ $yi ];
if ( ( $this->ychanged[ $yi ] = empty( $xhash[ $line ] ) ) ) {
continue;
}
$yhash[ $line ] = 1;
$this->yv[] = $line;
$this->yind[] = $yi;
}
for ( $xi = $skip; $xi < $n_from - $endskip; $xi ++ ) {
$line = $from_lines[ $xi ];
if ( ( $this->xchanged[ $xi ] = empty( $yhash[ $line ] ) ) ) {
continue;
}
$this->xv[] = $line;
$this->xind[] = $xi;
}
// Find the LCS.
$this->_compareseq( 0, count( $this->xv ), 0, count( $this->yv ) );
// Merge edits when possible.
$this->_shiftBoundaries( $from_lines, $this->xchanged, $this->ychanged );
$this->_shiftBoundaries( $to_lines, $this->ychanged, $this->xchanged );
// Compute the edit operations.
$edits = [];
$xi = $yi = 0;
while ( $xi < $n_from || $yi < $n_to ) {
assert( $yi < $n_to || $this->xchanged[ $xi ] );
assert( $xi < $n_from || $this->ychanged[ $yi ] );
// Skip matching "snake".
$copy = [];
while ( $xi < $n_from && $yi < $n_to
&& ! $this->xchanged[ $xi ]
&& ! $this->ychanged[ $yi ] ) {
$copy[] = $from_lines[ $xi ++ ];
++ $yi;
}
if ( $copy ) {
$edits[] = new Text_Diff_Op_copy( $copy );
}
// Find deletes & adds.
$delete = [];
while ( $xi < $n_from && $this->xchanged[ $xi ] ) {
$delete[] = $from_lines[ $xi ++ ];
}
$add = [];
while ( $yi < $n_to && $this->ychanged[ $yi ] ) {
$add[] = $to_lines[ $yi ++ ];
}
if ( $delete && $add ) {
$edits[] = new Text_Diff_Op_change( $delete, $add );
} elseif ( $delete ) {
$edits[] = new Text_Diff_Op_delete( $delete );
} elseif ( $add ) {
$edits[] = new Text_Diff_Op_add( $add );
}
}
return $edits;
}
/**
* Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
* XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
* segments.
*
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
* NCHUNKS+1 (X, Y) indexes giving the diving points between sub
* sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
* the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
* (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
*
* This function assumes that the first lines of the specified portions of
* the two files do not match, and likewise that the last lines do not
* match. The caller must trim matching lines from the beginning and end
* of the portions it is going to specify.
*
* @param $xoff
* @param $xlim
* @param $yoff
* @param $ylim
* @param $nchunks
*
* @return array
*/
public function _diag( $xoff, $xlim, $yoff, $ylim, $nchunks ) {
$flip = false;
if ( $xlim - $xoff > $ylim - $yoff ) {
/* Things seems faster (I'm not sure I understand why) when the
* shortest sequence is in X. */
$flip = true;
list( $xoff, $xlim, $yoff, $ylim ) = [ $yoff, $ylim, $xoff, $xlim ];
}
if ( $flip ) {
for ( $i = $ylim - 1; $i >= $yoff; $i -- ) {
$ymatches[ $this->xv[ $i ] ][] = $i;
}
} else {
for ( $i = $ylim - 1; $i >= $yoff; $i -- ) {
$ymatches[ $this->yv[ $i ] ][] = $i;
}
}
$this->lcs = 0;
$this->seq[0] = $yoff - 1;
$this->in_seq = [];
$ymids[0] = [];
$numer = $xlim - $xoff + $nchunks - 1;
$x = $xoff;
for ( $chunk = 0; $chunk < $nchunks; $chunk ++ ) {
if ( $chunk > 0 ) {
for ( $i = 0; $i <= $this->lcs; ++ $i ) {
$ymids[ $i ][ $chunk - 1 ] = $this->seq[ $i ];
}
}
$x1 = $xoff + (int) ( ( $numer + ( $xlim - $xoff ) * $chunk ) / $nchunks );
for ( ; $x < $x1; $x ++ ) {
$line = $flip ? $this->yv[ $x ] : $this->xv[ $x ];
if ( empty( $ymatches[ $line ] ) ) {
continue;
}
$matches = $ymatches[ $line ];
foreach ( $matches as $y ) {
if ( empty( $this->in_seq[ $y ] ) ) {
$k = $this->_lcsPos( $y );
assert( $k > 0 );
$ymids[ $k ] = $ymids[ $k - 1 ];
break;
}
}
// TODO @gigamaster replace each (deprecated) with foreach
// while ( list( $junk, $y ) = each( $matches ) ) {
foreach($matches as $junk => $y) {
if ( $y > $this->seq[ $k - 1 ] ) {
// assert($y < $this->seq[$k]); // GIJ Patched
/* Optimization: this is a common case: next match is
* just replacing previous match. */
$this->in_seq[ $this->seq[ $k ] ] = false;
$this->seq[ $k ] = $y;
$this->in_seq[ $y ] = 1;
} elseif ( empty( $this->in_seq[ $y ] ) ) {
$k = $this->_lcsPos( $y );
assert( $k > 0 );
$ymids[ $k ] = $ymids[ $k - 1 ];
}
}
}
}
$seps[] = $flip ? [ $yoff, $xoff ] : [ $xoff, $yoff ];
$ymid = $ymids[ $this->lcs ];
for ( $n = 0; $n < $nchunks - 1; $n ++ ) {
$x1 = $xoff + (int) ( ( $numer + ( $xlim - $xoff ) * $n ) / $nchunks );
$y1 = $ymid[ $n ] + 1;
$seps[] = $flip ? [ $y1, $x1 ] : [ $x1, $y1 ];
}
$seps[] = $flip ? [ $ylim, $xlim ] : [ $xlim, $ylim ];
return [ $this->lcs, $seps ];
}
/**
* @param $ypos
*
* @return int
*/
public function _lcsPos( $ypos ) {
$end = $this->lcs;
if ( 0 == $end || $ypos > $this->seq[ $end ] ) {
$this->seq[ ++ $this->lcs ] = $ypos;
$this->in_seq[ $ypos ] = 1;
return $this->lcs;
}
$beg = 1;
while ( $beg < $end ) {
$mid = (int) ( ( $beg + $end ) / 2 );
if ( $ypos > $this->seq[ $mid ] ) {
$beg = $mid + 1;
} else {
$end = $mid;
}
}
assert( $ypos != $this->seq[ $end ] );
$this->in_seq[ $this->seq[ $end ] ] = false;
$this->seq[ $end ] = $ypos;
$this->in_seq[ $ypos ] = 1;
return $end;
}
/**
* Finds LCS of two sequences.
*
* The results are recorded in the vectors $this->{x,y}changed[], by
* storing a 1 in the element for each line that is an insertion or
* deletion (ie. is not in the LCS).
*
* The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
*
* Note that XLIM, YLIM are exclusive bounds. All line numbers are
* origin-0 and discarded lines are not counted.
*
* @param $xoff
* @param $xlim
* @param $yoff
* @param $ylim
*/
public function _compareseq( $xoff, $xlim, $yoff, $ylim ) {
/* Slide down the bottom initial diagonal. */
while ( $xoff < $xlim && $yoff < $ylim
&& $this->xv[ $xoff ] == $this->yv[ $yoff ] ) {
++ $xoff;
++ $yoff;
}
/* Slide up the top initial diagonal. */
while ( $xlim > $xoff && $ylim > $yoff
&& $this->xv[ $xlim - 1 ] == $this->yv[ $ylim - 1 ] ) {
-- $xlim;
-- $ylim;
}
if ( $xoff == $xlim || $yoff == $ylim ) {
$lcs = 0;
} else {
/* This is ad hoc but seems to work well. $nchunks =
* sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
* max(2,min(8,(int)$nchunks)); */
$nchunks = min( 7, $xlim - $xoff, $ylim - $yoff ) + 1;
list( $lcs, $seps ) = $this->_diag( $xoff, $xlim, $yoff, $ylim, $nchunks );
}
if ( 0 == $lcs ) {
/* X and Y sequences have no common subsequence: mark all
* changed. */
while ( $yoff < $ylim ) {
$this->ychanged[ $this->yind[ $yoff ++ ] ] = 1;
}
while ( $xoff < $xlim ) {
$this->xchanged[ $this->xind[ $xoff ++ ] ] = 1;
}
} else {
/* Use the partitions to split this problem into subproblems. */
reset( $seps );
$pt1 = $seps[0];
while ( $pt2 = next( $seps ) ) {
$this->_compareseq( $pt1[0], $pt2[0], $pt1[1], $pt2[1] );
$pt1 = $pt2;
}
}
}
/**
* Adjusts inserts/deletes of identical lines to join changes as much as
* possible.
*
* We do something when a run of changed lines include a line at one end
* and has an excluded, identical line at the other. We are free to
* choose which identical line is included. `compareseq' usually chooses
* the one at the beginning, but usually it is cleaner to consider the
* following identical line to be the "change".
*
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
*
* @param $lines
* @param $changed
* @param $other_changed
*/
public function _shiftBoundaries( $lines, &$changed, $other_changed ) {
$i = 0;
$j = 0;
assert( count( $lines ) == count( $changed ) );
$len = count( $lines );
$other_len = count( $other_changed );
while ( 1 ) {
/* Scan forward to find the beginning of another run of
* changes. Also keep track of the corresponding point in the
* other file.
*
* Throughout this code, $i and $j are adjusted together so that
* the first $i elements of $changed and the first $j elements of
* $other_changed both contain the same number of zeros (unchanged
* lines).
*
* Furthermore, $j is always kept so that $j == $other_len or
* $other_changed[$j] == false. */
while ( $j < $other_len && $other_changed[ $j ] ) {
$j ++;
}
while ( $i < $len && ! $changed[ $i ] ) {
assert( $j < $other_len && ! $other_changed[ $j ] );
$i ++;
$j ++;
while ( $j < $other_len && $other_changed[ $j ] ) {
$j ++;
}
}
if ( $i == $len ) {
break;
}
$start = $i;
/* Find the end of this run of changes. */
while ( ++ $i < $len && $changed[ $i ] ) {
continue;
}
do {
/* Record the length of this run of changes, so that we can
* later determine whether the run has grown. */
$runlength = $i - $start;
/* Move the changed region back, so long as the previous
* unchanged line matches the last changed one. This merges
* with previous changed regions. */
while ( $start > 0 && $lines[ $start - 1 ] == $lines[ $i - 1 ] ) {
$changed[ -- $start ] = 1;
$changed[ -- $i ] = false;
while ( $start > 0 && $changed[ $start - 1 ] ) {
$start --;
}
assert( $j > 0 );
while ( $other_changed[ -- $j ] ) {
continue;
}
assert( $j >= 0 && !$other_changed[$j] );
}
/* Set CORRESPONDING to the end of the changed run, at the
* last point where it corresponds to a changed run in the
* other file. CORRESPONDING == LEN means no such point has
* been found. */
$corresponding = $j < $other_len ? $i : $len;
/* Move the changed region forward, so long as the first
* changed line matches the following unchanged one. This
* merges with following changed regions. Do this second, so
* that if there are no merges, the changed region is moved
* forward as far as possible. */
while ( $i < $len && $lines[ $start ] == $lines[ $i ] ) {
$changed[ $start ++ ] = false;
$changed[ $i ++ ] = 1;
while ( $i < $len && $changed[ $i ] ) {
$i ++;
}
assert( $j < $other_len && ! $other_changed[$j] );
$j ++;
if ( $j < $other_len && $other_changed[ $j ] ) {
$corresponding = $i;
while ( $j < $other_len && $other_changed[ $j ] ) {
$j ++;
}
}
}
} while ( $runlength != $i - $start );
/* If possible, move the fully-merged run of changes back to a
* corresponding run in the other file. */
while ( $corresponding < $i ) {
$changed[ -- $start ] = 1;
$changed[ -- $i ] = 0;
assert( $j > 0 );
while ( $other_changed[ -- $j ] ) {
continue;
}
assert( $j >= 0 && !$other_changed[$j] );
}
}
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op {
public $orig;
public $final;
public function reverse() {
trigger_error( 'Abstract method', E_USER_ERROR );
}
/**
* @return int|void
*/
public function norig() {
return $this->orig ? count( $this->orig ) : 0;
}
/**
* @return int|void
*/
public function nfinal() {
return $this->final ? count( $this->final ) : 0;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_copy extends Text_Diff_Op {
/**
* Text_Diff_Op_copy constructor.
*
* @param $orig
* @param bool $final
*/
public function __construct( $orig, $final = false ) {
if ( ! is_array( $final ) ) {
$final = $orig;
}
$this->orig = $orig;
$this->final = $final;
}
/**
* @return \Text_Diff_Op_copy
*/
public function &reverse() {
return $reverse = new self( $this->final, $this->orig );
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_delete extends Text_Diff_Op {
/**
* Text_Diff_Op_delete constructor.
*
* @param $lines
*/
public function __construct( $lines ) {
$this->orig = $lines;
$this->final = false;
}
/**
* @return \Text_Diff_Op_add
*/
public function &reverse() {
return $reverse = new Text_Diff_Op_add( $this->orig );
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_add extends Text_Diff_Op {
/**
* Text_Diff_Op_add constructor.
*
* @param $lines
*/
public function __construct( $lines ) {
$this->final = $lines;
$this->orig = false;
}
/**
* @return \Text_Diff_Op_delete
*/
public function &reverse() {
return $reverse = new Text_Diff_Op_delete( $this->final );
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_change extends Text_Diff_Op {
/**
* Text_Diff_Op_change constructor.
*
* @param $orig
* @param $final
*/
public function __construct( $orig, $final ) {
$this->orig = $orig;
$this->final = $final;
}
/**
* @return \Text_Diff_Op_change
*/
public function &reverse() {
return $reverse = new self( $this->final, $this->orig );
}
}