2 //rcs_id('$Id: diff3.php,v 1.2 2002-02-14 23:12:31 lakka Exp $');
5 // A class for computing three way diffs
7 // Copyright (C) 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
8 // You may copy this code freely under the conditions of the GPL.
11 require_once('lib/difflib.php');
16 function _Diff3_Block ($orig = false, $final1 = false, $final2 = false) {
17 $this->orig = $orig ? $orig : array();
18 $this->final1 = $final1 ? $final1 : array();
19 $this->final2 = $final2 ? $final2 : array();
23 if (!isset($this->_merged)) {
24 if ($this->final1 === $this->final2)
25 $this->_merged = &$this->final1;
26 elseif ($this->final1 === $this->orig)
27 $this->_merged = &$this->final2;
28 elseif ($this->final2 === $this->orig)
29 $this->_merged = &$this->final1;
31 $this->_merged = false;
33 return $this->_merged;
36 function is_conflict () {
37 return $this->merged() === false;
42 class _Diff3_CopyBlock extends _Diff3_Block {
45 function _Diff3_CopyBlock ($lines = false) {
46 $this->orig = $lines ? $lines : array();
47 $this->final1 = &$this->orig;
48 $this->final2 = &$this->orig;
55 function is_conflict () {
60 class _Diff3_BlockBuilder {
61 function _Diff3_BlockBuilder () {
66 $this->orig = $this->final1 = $this->final2 = array();
70 function _append (&$array, $lines) {
71 array_splice($array, sizeof($array), 0, $lines);
74 function input($lines) {
76 $this->_append($this->orig, $lines);
79 function out1($lines) {
81 $this->_append($this->final1, $lines);
84 function out2($lines) {
86 $this->_append($this->final2, $lines);
90 return !$this->orig && !$this->final1 && !$this->final2;
94 if ($this->is_empty())
97 $block = new _Diff3_Block($this->orig, $this->final1, $this->final2);
106 function Diff3 ($orig, $final1, $final2) {
107 $eng = new _DiffEngine;
109 $this->blocks = $this->__diff3($eng->diff($orig, $final1),
110 $eng->diff($orig, $final2));
113 function __diff3($edits1, $edits2) {
115 $bb = new _Diff3_BlockBuilder;
117 $e1 = current($edits1);
118 $e2 = current($edits2);
125 if ($e1 && $e2 && $e1->type == 'copy' && $e2->type == 'copy') {
126 // We have copy blocks from both diffs. This is the (only)
127 // time we want to emit a diff3 copy block.
128 // Flush current diff3 diff block, if any
129 if ($block = $bb->finish())
132 $ncopy = min($e1->norig(), $e2->norig());
134 $blocks[] = new _Diff3_CopyBlock(array_slice($e1->orig, 0, $ncopy));
136 if ($e1->norig() > $ncopy) {
137 array_splice($e1->orig, 0, $ncopy);
138 array_splice($e1->final, 0, $ncopy);
143 if ($e2->norig() > $ncopy) {
144 array_splice($e2->orig, 0, $ncopy);
145 array_splice($e2->final, 0, $ncopy);
152 $norig = min($e1->norig(), $e2->norig());
153 $orig = array_splice($e1->orig, 0, $norig);
154 array_splice($e2->orig, 0, $norig);
157 if ($e1->type == 'copy')
158 $bb->out1(array_splice($e1->final, 0, $norig));
160 if ($e2->type == 'copy')
161 $bb->out2(array_splice($e2->final, 0, $norig));
163 if ($e1 && ! $e1->orig) {
164 $bb->out1($e1->final);
167 if ($e2 && ! $e2->orig) {
168 $bb->out2($e2->final);
174 if ($block = $bb->finish())
181 function merged_output($label1 = false, $label2 = false) {
183 foreach ($this->blocks as $block) {
184 if ($block->is_conflict()) {
185 // FIXME: this should probably be moved somewhere else...
186 $lines = array_merge($lines,
187 array("<<<<<<<" . ($label1 ? " $label1" : '')),
191 array(">>>>>>>" . ($label2 ? " $label2" : '')));
194 $lines = array_merge($lines, $block->merged());
205 // c-hanging-comment-ender-p: nil
206 // indent-tabs-mode: nil