Text_Diff
[ class tree: Text_Diff ] [ index: Text_Diff ] [ all elements ]

Source for file Diff3.php

Documentation is available at Diff3.php

  1. <?php
  2.  
  3. require_once 'Text/Diff.php';
  4.  
  5. /**
  6.  * A class for computing three way diffs.
  7.  *
  8.  * $Horde: framework/Text_Diff/Diff3.php,v 1.3 2005/06/23 19:40:18 selsky Exp $
  9.  *
  10.  * @package Text_Diff
  11.  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
  12.  */
  13. class Text_Diff3 extends Text_Diff {
  14.  
  15.     /**
  16.      * Conflict counter.
  17.      *
  18.      * @var integer 
  19.      */
  20.     var $_conflictingBlocks = 0;
  21.  
  22.     /**
  23.      * Computes diff between 3 sequences of strings.
  24.      *
  25.      * @param array $orig    The original lines to use.
  26.      * @param array $final1  The first version to compare to.
  27.      * @param array $final2  The second version to compare to.
  28.      */
  29.     function Text_Diff3($orig, $final1, $final2)
  30.     {
  31.         if (extension_loaded('xdiff')) {
  32.             $engine = &new Text_Diff_Engine_xdiff();
  33.         } else {
  34.             $engine = &new Text_Diff_Engine_native();
  35.         }
  36.  
  37.         $this->_edits = $this->_diff3($engine->diff($orig, $final1),
  38.                                       $engine->diff($orig, $final2));
  39.     }
  40.  
  41.     function mergedOutput($label1 = false, $label2 = false)
  42.     {
  43.         $lines = array();
  44.         foreach ($this->_edits as $edit) {
  45.             if ($edit->isConflict()) {
  46.                 /* FIXME: this should probably be moved somewhere else. */
  47.                 $lines = array_merge($lines,
  48.                                      array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
  49.                                      $edit->final1,
  50.                                      array("======="),
  51.                                      $edit->final2,
  52.                                      array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
  53.                 $this->_conflictingBlocks++;
  54.             } else {
  55.                 $lines = array_merge($lines, $edit->merged());
  56.             }
  57.         }
  58.  
  59.         return $lines;
  60.     }
  61.  
  62.     /**
  63.      * @access private
  64.      */
  65.     function _diff3($edits1, $edits2)
  66.     {
  67.         $edits = array();
  68.         $bb = &new Text_Diff3_BlockBuilder();
  69.  
  70.         $e1 = current($edits1);
  71.         $e2 = current($edits2);
  72.         while ($e1 || $e2) {
  73.             if ($e1 && $e2 && is_a($e1, 'Text_Diff_Op_copy') && is_a($e2, 'Text_Diff_Op_copy')) {
  74.                 /* We have copy blocks from both diffs. This is the (only)
  75.                  * time we want to emit a diff3 copy block.  Flush current
  76.                  * diff3 diff block, if any. */
  77.                 if ($edit = $bb->finish()) {
  78.                     $edits[] = $edit;
  79.                 }
  80.  
  81.                 $ncopy = min($e1->norig(), $e2->norig());
  82.                 assert($ncopy > 0);
  83.                 $edits[] = &new Text_Diff3_Op_copy(array_slice($e1->orig, 0, $ncopy));
  84.  
  85.                 if ($e1->norig() > $ncopy) {
  86.                     array_splice($e1->orig, 0, $ncopy);
  87.                     array_splice($e1->final, 0, $ncopy);
  88.                 } else {
  89.                     $e1 = next($edits1);
  90.                 }
  91.  
  92.                 if ($e2->norig() > $ncopy) {
  93.                     array_splice($e2->orig, 0, $ncopy);
  94.                     array_splice($e2->final, 0, $ncopy);
  95.                 } else {
  96.                     $e2 = next($edits2);
  97.                 }
  98.             } else {
  99.                 if ($e1 && $e2) {
  100.                     if ($e1->orig && $e2->orig) {
  101.                         $norig = min($e1->norig(), $e2->norig());
  102.                         $orig = array_splice($e1->orig, 0, $norig);
  103.                         array_splice($e2->orig, 0, $norig);
  104.                         $bb->input($orig);
  105.                     }
  106.  
  107.                     if (is_a($e1, 'Text_Diff_Op_copy')) {
  108.                         $bb->out1(array_splice($e1->final, 0, $norig));
  109.                     }
  110.  
  111.                     if (is_a($e2, 'Text_Diff_Op_copy')) {
  112.                         $bb->out2(array_splice($e2->final, 0, $norig));
  113.                     }
  114.                 }
  115.  
  116.                 if ($e1 && ! $e1->orig) {
  117.                     $bb->out1($e1->final);
  118.                     $e1 = next($edits1);
  119.                 }
  120.                 if ($e2 && ! $e2->orig) {
  121.                     $bb->out2($e2->final);
  122.                     $e2 = next($edits2);
  123.                 }
  124.             }
  125.         }
  126.  
  127.         if ($edit = $bb->finish()) {
  128.             $edits[] = $edit;
  129.         }
  130.  
  131.         return $edits;
  132.     }
  133.  
  134. }
  135.  
  136. /**
  137.  * @package Text_Diff
  138.  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
  139.  *
  140.  * @access private
  141.  */
  142. class Text_Diff3_Op {
  143.  
  144.     function Text_Diff3_Op($orig = false, $final1 = false, $final2 = false)
  145.     {
  146.         $this->orig = $orig ? $orig : array();
  147.         $this->final1 = $final1 ? $final1 : array();
  148.         $this->final2 = $final2 ? $final2 : array();
  149.     }
  150.  
  151.     function merged()
  152.     {
  153.         if (!isset($this->_merged)) {
  154.             if ($this->final1 === $this->final2) {
  155.                 $this->_merged = &$this->final1;
  156.             } elseif ($this->final1 === $this->orig) {
  157.                 $this->_merged = &$this->final2;
  158.             } elseif ($this->final2 === $this->orig) {
  159.                 $this->_merged = &$this->final1;
  160.             } else {
  161.                 $this->_merged = false;
  162.             }
  163.         }
  164.  
  165.         return $this->_merged;
  166.     }
  167.  
  168.     function isConflict()
  169.     {
  170.         return $this->merged() === false;
  171.     }
  172.  
  173. }
  174.  
  175. /**
  176.  * @package Text_Diff
  177.  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
  178.  *
  179.  * @access private
  180.  */
  181. class Text_Diff3_Op_copy extends Text_Diff3_Op {
  182.  
  183.     function Text_Diff3_Op_Copy($lines = false)
  184.     {
  185.         $this->orig = $lines ? $lines : array();
  186.         $this->final1 = &$this->orig;
  187.         $this->final2 = &$this->orig;
  188.     }
  189.  
  190.     function merged()
  191.     {
  192.         return $this->orig;
  193.     }
  194.  
  195.     function isConflict()
  196.     {
  197.         return false;
  198.     }
  199.  
  200. }
  201.  
  202. /**
  203.  * @package Text_Diff
  204.  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
  205.  *
  206.  * @access private
  207.  */
  208. class Text_Diff3_BlockBuilder {
  209.  
  210.     function Text_Diff3_BlockBuilder()
  211.     {
  212.         $this->_init();
  213.     }
  214.  
  215.     function input($lines)
  216.     {
  217.         if ($lines) {
  218.             $this->_append($this->orig, $lines);
  219.         }
  220.     }
  221.  
  222.     function out1($lines)
  223.     {
  224.         if ($lines) {
  225.             $this->_append($this->final1, $lines);
  226.         }
  227.     }
  228.  
  229.     function out2($lines)
  230.     {
  231.         if ($lines) {
  232.             $this->_append($this->final2, $lines);
  233.         }
  234.     }
  235.  
  236.     function isEmpty()
  237.     {
  238.         return !$this->orig && !$this->final1 && !$this->final2;
  239.     }
  240.  
  241.     function finish()
  242.     {
  243.         if ($this->isEmpty()) {
  244.             return false;
  245.         } else {
  246.             $edit = &new Text_Diff3_Op($this->orig, $this->final1, $this->final2);
  247.             $this->_init();
  248.             return $edit;
  249.         }
  250.     }
  251.  
  252.     function _init()
  253.     {
  254.         $this->orig = $this->final1 = $this->final2 = array();
  255.     }
  256.  
  257.     function _append(&$array, $lines)
  258.     {
  259.         array_splice($array, sizeof($array), 0, $lines);
  260.     }
  261.  
  262. }

Documentation generated on Mon, 11 Mar 2019 14:16:38 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.