1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13: class Horde_Text_Diff_ThreeWay
14: {
15: 16: 17: 18: 19:
20: protected $_edits;
21:
22: 23: 24: 25: 26:
27: protected $_conflictingBlocks = 0;
28:
29: 30: 31: 32: 33: 34: 35:
36: public function __construct($orig, $final1, $final2)
37: {
38: if (extension_loaded('xdiff')) {
39: $engine = new Horde_Text_Diff_Engine_Xdiff();
40: } else {
41: $engine = new Horde_Text_Diff_Engine_Native();
42: }
43:
44: $this->_edits = $this->_diff3($engine->diff($orig, $final1),
45: $engine->diff($orig, $final2));
46: }
47:
48: 49:
50: public function mergedOutput($label1 = false, $label2 = false)
51: {
52: $lines = array();
53: foreach ($this->_edits as $edit) {
54: if ($edit->isConflict()) {
55:
56: $lines = array_merge($lines,
57: array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
58: $edit->final1,
59: array("======="),
60: $edit->final2,
61: array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
62: $this->_conflictingBlocks++;
63: } else {
64: $lines = array_merge($lines, $edit->merged());
65: }
66: }
67:
68: return $lines;
69: }
70:
71: 72:
73: protected function _diff3($edits1, $edits2)
74: {
75: $edits = array();
76: $bb = new Horde_Text_Diff_ThreeWay_BlockBuilder();
77:
78: $e1 = current($edits1);
79: $e2 = current($edits2);
80: while ($e1 || $e2) {
81: if ($e1 && $e2 &&
82: $e1 instanceof Horde_Text_Diff_Op_Copy &&
83: $e2 instanceof Horde_Text_Diff_Op_Copy) {
84: 85: 86:
87: if ($edit = $bb->finish()) {
88: $edits[] = $edit;
89: }
90:
91: $ncopy = min($e1->norig(), $e2->norig());
92: assert($ncopy > 0);
93: $edits[] = new Horde_Text_Diff_ThreeWay_Op_Copy(array_slice($e1->orig, 0, $ncopy));
94:
95: if ($e1->norig() > $ncopy) {
96: array_splice($e1->orig, 0, $ncopy);
97: array_splice($e1->final, 0, $ncopy);
98: } else {
99: $e1 = next($edits1);
100: }
101:
102: if ($e2->norig() > $ncopy) {
103: array_splice($e2->orig, 0, $ncopy);
104: array_splice($e2->final, 0, $ncopy);
105: } else {
106: $e2 = next($edits2);
107: }
108: } else {
109: if ($e1 && $e2) {
110: if ($e1->orig && $e2->orig) {
111: $norig = min($e1->norig(), $e2->norig());
112: $orig = array_splice($e1->orig, 0, $norig);
113: array_splice($e2->orig, 0, $norig);
114: $bb->input($orig);
115: }
116:
117: if ($e1 instanceof Horde_Text_Diff_Op_Copy) {
118: $bb->out1(array_splice($e1->final, 0, $norig));
119: }
120:
121: if ($e2 instanceof Horde_Text_Diff_Op_Copy) {
122: $bb->out2(array_splice($e2->final, 0, $norig));
123: }
124: }
125:
126: if ($e1 && ! $e1->orig) {
127: $bb->out1($e1->final);
128: $e1 = next($edits1);
129: }
130: if ($e2 && ! $e2->orig) {
131: $bb->out2($e2->final);
132: $e2 = next($edits2);
133: }
134: }
135: }
136:
137: if ($edit = $bb->finish()) {
138: $edits[] = $edit;
139: }
140:
141: return $edits;
142: }
143: }
144: