home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Text / Diff / ThreeWay.php < prev   
Encoding:
PHP Script  |  2008-07-02  |  7.1 KB  |  277 lines

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