phpBB
Statistics
| Revision:

root / trunk / phpBB / includes / diff / diff.php

History | View | Annotate | Download (23.7 kB)

1 6313 acydburn
<?php
2 8147 acydburn
/**
3 6313 acydburn
*
4 8034 acydburn
* @package diff
5 8147 acydburn
* @copyright (c) 2006 phpBB Group
6 11653 git-gate
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
7 6313 acydburn
*
8 6313 acydburn
*/
9 6313 acydburn
10 6313 acydburn
/**
11 8147 acydburn
* @ignore
12 6313 acydburn
*/
13 6313 acydburn
if (!defined('IN_PHPBB'))
14 6313 acydburn
{
15 6313 acydburn
        exit;
16 6313 acydburn
}
17 6313 acydburn
18 6313 acydburn
/**
19 9251 acydburn
* Code from pear.php.net, Text_Diff-1.1.0 package
20 6313 acydburn
* http://pear.php.net/package/Text_Diff/
21 6313 acydburn
*
22 6595 acydburn
* Modified by phpBB Group to meet our coding standards
23 6313 acydburn
* and being able to integrate into phpBB
24 6595 acydburn
*
25 6313 acydburn
* General API for generating and formatting diffs - the differences between
26 6313 acydburn
* two sequences of strings.
27 6313 acydburn
*
28 8692 acydburn
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
29 8692 acydburn
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
30 8692 acydburn
*
31 8034 acydburn
* @package diff
32 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
33 6313 acydburn
*/
34 6313 acydburn
class diff
35 6313 acydburn
{
36 6313 acydburn
        /**
37 6313 acydburn
        * Array of changes.
38 6313 acydburn
        * @var array
39 6313 acydburn
        */
40 6313 acydburn
        var $_edits;
41 6313 acydburn
42 6313 acydburn
        /**
43 6313 acydburn
        * Computes diffs between sequences of strings.
44 6313 acydburn
        *
45 6313 acydburn
        * @param array $from_lines  An array of strings. Typically these are lines from a file.
46 6313 acydburn
        * @param array $to_lines    An array of strings.
47 6313 acydburn
        */
48 6695 acydburn
        function diff(&$from_content, &$to_content, $preserve_cr = true)
49 6313 acydburn
        {
50 8692 acydburn
                $diff_engine = new diff_engine();
51 6695 acydburn
                $this->_edits = $diff_engine->diff($from_content, $to_content, $preserve_cr);
52 6313 acydburn
        }
53 6313 acydburn
54 6313 acydburn
        /**
55 6313 acydburn
        * Returns the array of differences.
56 6313 acydburn
        */
57 6313 acydburn
        function get_diff()
58 6313 acydburn
        {
59 6313 acydburn
                return $this->_edits;
60 6313 acydburn
        }
61 6313 acydburn
62 6313 acydburn
        /**
63 9251 acydburn
        * returns the number of new (added) lines in a given diff.
64 9251 acydburn
        *
65 9251 acydburn
        * @since Text_Diff 1.1.0
66 9251 acydburn
        *
67 9251 acydburn
        * @return integer The number of new lines
68 9251 acydburn
        */
69 9251 acydburn
        function count_added_lines()
70 9251 acydburn
        {
71 9251 acydburn
                $count = 0;
72 9251 acydburn
73 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
74 9251 acydburn
                {
75 10163 acydburn
                        $edit = $this->_edits[$i];
76 10163 acydburn
77 9251 acydburn
                        if (is_a($edit, 'diff_op_add') || is_a($edit, 'diff_op_change'))
78 9251 acydburn
                        {
79 9251 acydburn
                                $count += $edit->nfinal();
80 9251 acydburn
                        }
81 9251 acydburn
                }
82 9251 acydburn
                return $count;
83 9251 acydburn
        }
84 9251 acydburn
85 9251 acydburn
        /**
86 9251 acydburn
        * Returns the number of deleted (removed) lines in a given diff.
87 9251 acydburn
        *
88 9251 acydburn
        * @since Text_Diff 1.1.0
89 9251 acydburn
        *
90 9251 acydburn
        * @return integer The number of deleted lines
91 9251 acydburn
        */
92 9251 acydburn
        function count_deleted_lines()
93 9251 acydburn
        {
94 9251 acydburn
                $count = 0;
95 9251 acydburn
96 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
97 9251 acydburn
                {
98 10163 acydburn
                        $edit = $this->_edits[$i];
99 10163 acydburn
100 9251 acydburn
                        if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_change'))
101 9251 acydburn
                        {
102 9251 acydburn
                                $count += $edit->norig();
103 9251 acydburn
                        }
104 9251 acydburn
                }
105 9251 acydburn
                return $count;
106 9251 acydburn
        }
107 9251 acydburn
108 9251 acydburn
        /**
109 6313 acydburn
        * Computes a reversed diff.
110 6313 acydburn
        *
111 6313 acydburn
        * Example:
112 6313 acydburn
        * <code>
113 9254 acydburn
        * $diff = new diff($lines1, $lines2);
114 6313 acydburn
        * $rev = $diff->reverse();
115 6313 acydburn
        * </code>
116 6313 acydburn
        *
117 6313 acydburn
        * @return diff  A Diff object representing the inverse of the original diff.
118 8147 acydburn
        *               Note that we purposely don't return a reference here, since
119 6313 acydburn
        *               this essentially is a clone() method.
120 6313 acydburn
        */
121 6313 acydburn
        function reverse()
122 6313 acydburn
        {
123 6313 acydburn
                if (version_compare(zend_version(), '2', '>'))
124 6313 acydburn
                {
125 6313 acydburn
                        $rev = clone($this);
126 6313 acydburn
                }
127 6313 acydburn
                else
128 6313 acydburn
                {
129 6313 acydburn
                        $rev = $this;
130 6313 acydburn
                }
131 6313 acydburn
132 6313 acydburn
                $rev->_edits = array();
133 6313 acydburn
134 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
135 6313 acydburn
                {
136 10163 acydburn
                        $edit = $this->_edits[$i];
137 6313 acydburn
                        $rev->_edits[] = $edit->reverse();
138 6313 acydburn
                }
139 6313 acydburn
140 6313 acydburn
                return $rev;
141 6313 acydburn
        }
142 6313 acydburn
143 6313 acydburn
        /**
144 6313 acydburn
        * Checks for an empty diff.
145 6313 acydburn
        *
146 6313 acydburn
        * @return boolean  True if two sequences were identical.
147 6313 acydburn
        */
148 6313 acydburn
        function is_empty()
149 6313 acydburn
        {
150 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
151 6313 acydburn
                {
152 10163 acydburn
                        $edit = $this->_edits[$i];
153 10163 acydburn
154 10163 acydburn
                        // skip diff_op_copy
155 10163 acydburn
                        if (is_a($edit, 'diff_op_copy'))
156 6313 acydburn
                        {
157 10163 acydburn
                                continue;
158 10163 acydburn
                        }
159 10163 acydburn
160 10163 acydburn
                        if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_add'))
161 10163 acydburn
                        {
162 10163 acydburn
                                $orig = $edit->orig;
163 10163 acydburn
                                $final = $edit->final;
164 10163 acydburn
165 10163 acydburn
                                // We can simplify one case where the array is usually supposed to be empty...
166 10163 acydburn
                                if (sizeof($orig) == 1 && trim($orig[0]) === '') $orig = array();
167 10163 acydburn
                                if (sizeof($final) == 1 && trim($final[0]) === '') $final = array();
168 10163 acydburn
169 10163 acydburn
                                if (!$orig && !$final)
170 10163 acydburn
                                {
171 10163 acydburn
                                        continue;
172 10163 acydburn
                                }
173 10163 acydburn
174 6313 acydburn
                                return false;
175 6313 acydburn
                        }
176 10163 acydburn
177 10163 acydburn
                        return false;
178 6313 acydburn
                }
179 10163 acydburn
180 6313 acydburn
                return true;
181 6313 acydburn
        }
182 6313 acydburn
183 6313 acydburn
        /**
184 6313 acydburn
        * Computes the length of the Longest Common Subsequence (LCS).
185 6313 acydburn
        *
186 6313 acydburn
        * This is mostly for diagnostic purposes.
187 6313 acydburn
        *
188 6313 acydburn
        * @return integer  The length of the LCS.
189 6313 acydburn
        */
190 6313 acydburn
        function lcs()
191 6313 acydburn
        {
192 6313 acydburn
                $lcs = 0;
193 6313 acydburn
194 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
195 6313 acydburn
                {
196 10163 acydburn
                        $edit = $this->_edits[$i];
197 10163 acydburn
198 6313 acydburn
                        if (is_a($edit, 'diff_op_copy'))
199 6313 acydburn
                        {
200 6313 acydburn
                                $lcs += sizeof($edit->orig);
201 6313 acydburn
                        }
202 6313 acydburn
                }
203 6313 acydburn
                return $lcs;
204 6313 acydburn
        }
205 6313 acydburn
206 6313 acydburn
        /**
207 6313 acydburn
        * Gets the original set of lines.
208 6313 acydburn
        *
209 6313 acydburn
        * This reconstructs the $from_lines parameter passed to the constructor.
210 6313 acydburn
        *
211 6313 acydburn
        * @return array  The original sequence of strings.
212 6313 acydburn
        */
213 6313 acydburn
        function get_original()
214 6313 acydburn
        {
215 6313 acydburn
                $lines = array();
216 6313 acydburn
217 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
218 6313 acydburn
                {
219 10163 acydburn
                        $edit = $this->_edits[$i];
220 10163 acydburn
221 6313 acydburn
                        if ($edit->orig)
222 6313 acydburn
                        {
223 6313 acydburn
                                array_splice($lines, sizeof($lines), 0, $edit->orig);
224 6313 acydburn
                        }
225 6313 acydburn
                }
226 6313 acydburn
                return $lines;
227 6313 acydburn
        }
228 6313 acydburn
229 6313 acydburn
        /**
230 6313 acydburn
        * Gets the final set of lines.
231 6313 acydburn
        *
232 6313 acydburn
        * This reconstructs the $to_lines parameter passed to the constructor.
233 6313 acydburn
        *
234 6313 acydburn
        * @return array  The sequence of strings.
235 6313 acydburn
        */
236 6313 acydburn
        function get_final()
237 6313 acydburn
        {
238 6313 acydburn
                $lines = array();
239 6313 acydburn
240 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
241 6313 acydburn
                {
242 10163 acydburn
                        $edit = $this->_edits[$i];
243 10163 acydburn
244 6313 acydburn
                        if ($edit->final)
245 6313 acydburn
                        {
246 6313 acydburn
                                array_splice($lines, sizeof($lines), 0, $edit->final);
247 6313 acydburn
                        }
248 6313 acydburn
                }
249 6313 acydburn
                return $lines;
250 6313 acydburn
        }
251 6313 acydburn
252 6313 acydburn
        /**
253 6313 acydburn
        * Removes trailing newlines from a line of text. This is meant to be used with array_walk().
254 6313 acydburn
        *
255 6595 acydburn
        * @param string &$line  The line to trim.
256 6313 acydburn
        * @param integer $key  The index of the line in the array. Not used.
257 6313 acydburn
        */
258 6313 acydburn
        function trim_newlines(&$line, $key)
259 6313 acydburn
        {
260 6313 acydburn
                $line = str_replace(array("\n", "\r"), '', $line);
261 6313 acydburn
        }
262 6313 acydburn
263 6313 acydburn
        /**
264 6313 acydburn
        * Checks a diff for validity.
265 6313 acydburn
        *
266 6313 acydburn
        * This is here only for debugging purposes.
267 6313 acydburn
        */
268 6313 acydburn
        function _check($from_lines, $to_lines)
269 6313 acydburn
        {
270 6313 acydburn
                if (serialize($from_lines) != serialize($this->get_original()))
271 6313 acydburn
                {
272 6313 acydburn
                        trigger_error("[diff] Reconstructed original doesn't match", E_USER_ERROR);
273 6313 acydburn
                }
274 6313 acydburn
275 6313 acydburn
                if (serialize($to_lines) != serialize($this->get_final()))
276 6313 acydburn
                {
277 6313 acydburn
                        trigger_error("[diff] Reconstructed final doesn't match", E_USER_ERROR);
278 6313 acydburn
                }
279 6313 acydburn
280 6313 acydburn
                $rev = $this->reverse();
281 6313 acydburn
282 6313 acydburn
                if (serialize($to_lines) != serialize($rev->get_original()))
283 6313 acydburn
                {
284 6313 acydburn
                        trigger_error("[diff] Reversed original doesn't match", E_USER_ERROR);
285 6313 acydburn
                }
286 6313 acydburn
287 6313 acydburn
                if (serialize($from_lines) != serialize($rev->get_final()))
288 6313 acydburn
                {
289 6313 acydburn
                        trigger_error("[diff] Reversed final doesn't match", E_USER_ERROR);
290 6313 acydburn
                }
291 6313 acydburn
292 6313 acydburn
                $prevtype = null;
293 6313 acydburn
294 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
295 6313 acydburn
                {
296 10163 acydburn
                        $edit = $this->_edits[$i];
297 10163 acydburn
298 6313 acydburn
                        if ($prevtype == get_class($edit))
299 6313 acydburn
                        {
300 6313 acydburn
                                trigger_error("[diff] Edit sequence is non-optimal", E_USER_ERROR);
301 6313 acydburn
                        }
302 6313 acydburn
                        $prevtype = get_class($edit);
303 6313 acydburn
                }
304 6313 acydburn
305 6313 acydburn
                return true;
306 6313 acydburn
        }
307 6313 acydburn
}
308 6313 acydburn
309 6313 acydburn
/**
310 8034 acydburn
* @package diff
311 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
312 6313 acydburn
*/
313 6313 acydburn
class mapped_diff extends diff
314 6313 acydburn
{
315 6313 acydburn
        /**
316 6313 acydburn
        * Computes a diff between sequences of strings.
317 6313 acydburn
        *
318 6313 acydburn
        * This can be used to compute things like case-insensitve diffs, or diffs
319 6313 acydburn
        * which ignore changes in white-space.
320 6313 acydburn
        *
321 6313 acydburn
        * @param array $from_lines         An array of strings.
322 6313 acydburn
        * @param array $to_lines           An array of strings.
323 6313 acydburn
        * @param array $mapped_from_lines  This array should have the same size number of elements as $from_lines.
324 6313 acydburn
        *                                  The elements in $mapped_from_lines and $mapped_to_lines are what is actually
325 6313 acydburn
        *                                  compared when computing the diff.
326 6313 acydburn
        * @param array $mapped_to_lines    This array should have the same number of elements as $to_lines.
327 6313 acydburn
        */
328 6695 acydburn
        function mapped_diff(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
329 6313 acydburn
        {
330 6313 acydburn
                if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines))
331 6313 acydburn
                {
332 6313 acydburn
                        return false;
333 6313 acydburn
                }
334 6313 acydburn
335 6313 acydburn
                parent::diff($mapped_from_lines, $mapped_to_lines);
336 6313 acydburn
337 6313 acydburn
                $xi = $yi = 0;
338 6313 acydburn
                for ($i = 0; $i < sizeof($this->_edits); $i++)
339 6313 acydburn
                {
340 6313 acydburn
                        $orig = &$this->_edits[$i]->orig;
341 6313 acydburn
                        if (is_array($orig))
342 6313 acydburn
                        {
343 6313 acydburn
                                $orig = array_slice($from_lines, $xi, sizeof($orig));
344 6313 acydburn
                                $xi += sizeof($orig);
345 6313 acydburn
                        }
346 6313 acydburn
347 6313 acydburn
                        $final = &$this->_edits[$i]->final;
348 6313 acydburn
                        if (is_array($final))
349 6313 acydburn
                        {
350 6313 acydburn
                                $final = array_slice($to_lines, $yi, sizeof($final));
351 6313 acydburn
                                $yi += sizeof($final);
352 6313 acydburn
                        }
353 6313 acydburn
                }
354 6313 acydburn
        }
355 6313 acydburn
}
356 6313 acydburn
357 6313 acydburn
/**
358 8034 acydburn
* @package diff
359 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
360 6313 acydburn
*
361 6313 acydburn
* @access private
362 6313 acydburn
*/
363 6313 acydburn
class diff_op
364 6313 acydburn
{
365 6313 acydburn
        var $orig;
366 6313 acydburn
        var $final;
367 6313 acydburn
368 8692 acydburn
        function &reverse()
369 6313 acydburn
        {
370 6313 acydburn
                trigger_error('[diff] Abstract method', E_USER_ERROR);
371 6313 acydburn
        }
372 6313 acydburn
373 6313 acydburn
        function norig()
374 6313 acydburn
        {
375 6313 acydburn
                return ($this->orig) ? sizeof($this->orig) : 0;
376 6313 acydburn
        }
377 6313 acydburn
378 6313 acydburn
        function nfinal()
379 6313 acydburn
        {
380 6313 acydburn
                return ($this->final) ? sizeof($this->final) : 0;
381 6313 acydburn
        }
382 6313 acydburn
}
383 6313 acydburn
384 6313 acydburn
/**
385 8034 acydburn
* @package diff
386 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
387 6313 acydburn
*
388 6313 acydburn
* @access private
389 6313 acydburn
*/
390 6313 acydburn
class diff_op_copy extends diff_op
391 6313 acydburn
{
392 6313 acydburn
        function diff_op_copy($orig, $final = false)
393 6313 acydburn
        {
394 6313 acydburn
                if (!is_array($final))
395 6313 acydburn
                {
396 6313 acydburn
                        $final = $orig;
397 6313 acydburn
                }
398 6313 acydburn
                $this->orig = $orig;
399 6313 acydburn
                $this->final = $final;
400 6313 acydburn
        }
401 6313 acydburn
402 6313 acydburn
        function &reverse()
403 6313 acydburn
        {
404 8765 aptx
                $reverse = new diff_op_copy($this->final, $this->orig);
405 6313 acydburn
                return $reverse;
406 6313 acydburn
        }
407 6313 acydburn
}
408 6313 acydburn
409 6313 acydburn
/**
410 8034 acydburn
* @package diff
411 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
412 6313 acydburn
*
413 6313 acydburn
* @access private
414 6313 acydburn
*/
415 6313 acydburn
class diff_op_delete extends diff_op
416 6313 acydburn
{
417 6313 acydburn
        function diff_op_delete($lines)
418 6313 acydburn
        {
419 6313 acydburn
                $this->orig = $lines;
420 6313 acydburn
                $this->final = false;
421 6313 acydburn
        }
422 6313 acydburn
423 6313 acydburn
        function &reverse()
424 6313 acydburn
        {
425 8765 aptx
                $reverse = new diff_op_add($this->orig);
426 6313 acydburn
                return $reverse;
427 6313 acydburn
        }
428 6313 acydburn
}
429 6313 acydburn
430 6313 acydburn
/**
431 8034 acydburn
* @package diff
432 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
433 6313 acydburn
*
434 6313 acydburn
* @access private
435 6313 acydburn
*/
436 6313 acydburn
class diff_op_add extends diff_op
437 6313 acydburn
{
438 6313 acydburn
        function diff_op_add($lines)
439 6313 acydburn
        {
440 6313 acydburn
                $this->final = $lines;
441 6313 acydburn
                $this->orig = false;
442 6313 acydburn
        }
443 6313 acydburn
444 6313 acydburn
        function &reverse()
445 6313 acydburn
        {
446 8765 aptx
                $reverse = new diff_op_delete($this->final);
447 6313 acydburn
                return $reverse;
448 6313 acydburn
        }
449 6313 acydburn
}
450 6313 acydburn
451 6313 acydburn
/**
452 8034 acydburn
* @package diff
453 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
454 6313 acydburn
*
455 6313 acydburn
* @access private
456 6313 acydburn
*/
457 6313 acydburn
class diff_op_change extends diff_op
458 6313 acydburn
{
459 6313 acydburn
        function diff_op_change($orig, $final)
460 6313 acydburn
        {
461 6313 acydburn
                $this->orig = $orig;
462 6313 acydburn
                $this->final = $final;
463 6313 acydburn
        }
464 6313 acydburn
465 6313 acydburn
        function &reverse()
466 6313 acydburn
        {
467 8765 aptx
                $reverse = new diff_op_change($this->final, $this->orig);
468 6313 acydburn
                return $reverse;
469 6313 acydburn
        }
470 6313 acydburn
}
471 6313 acydburn
472 6313 acydburn
473 6313 acydburn
/**
474 6313 acydburn
* A class for computing three way diffs.
475 6313 acydburn
*
476 8034 acydburn
* @package diff
477 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
478 6313 acydburn
*/
479 6313 acydburn
class diff3 extends diff
480 6313 acydburn
{
481 6313 acydburn
        /**
482 6313 acydburn
        * Conflict counter.
483 6313 acydburn
        * @var integer
484 6313 acydburn
        */
485 6313 acydburn
        var $_conflicting_blocks = 0;
486 6313 acydburn
487 6313 acydburn
        /**
488 6313 acydburn
        * Computes diff between 3 sequences of strings.
489 6313 acydburn
        *
490 6313 acydburn
        * @param array $orig    The original lines to use.
491 6313 acydburn
        * @param array $final1  The first version to compare to.
492 6313 acydburn
        * @param array $final2  The second version to compare to.
493 6313 acydburn
        */
494 10163 acydburn
        function diff3(&$orig, &$final1, &$final2, $preserve_cr = true)
495 6313 acydburn
        {
496 8692 acydburn
                $diff_engine = new diff_engine();
497 6695 acydburn
498 10163 acydburn
                $diff_1 = $diff_engine->diff($orig, $final1, $preserve_cr);
499 10163 acydburn
                $diff_2 = $diff_engine->diff($orig, $final2, $preserve_cr);
500 6695 acydburn
501 10163 acydburn
                unset($diff_engine);
502 6695 acydburn
503 6695 acydburn
                $this->_edits = $this->_diff3($diff_1, $diff_2);
504 6313 acydburn
        }
505 6313 acydburn
506 6313 acydburn
        /**
507 9252 acydburn
        * Return number of conflicts
508 9252 acydburn
        */
509 9252 acydburn
        function get_num_conflicts()
510 9252 acydburn
        {
511 9252 acydburn
                $conflicts = 0;
512 9252 acydburn
513 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
514 9252 acydburn
                {
515 10163 acydburn
                        $edit = $this->_edits[$i];
516 10163 acydburn
517 9252 acydburn
                        if ($edit->is_conflict())
518 9252 acydburn
                        {
519 9252 acydburn
                                $conflicts++;
520 9252 acydburn
                        }
521 9252 acydburn
                }
522 9252 acydburn
523 9252 acydburn
                return $conflicts;
524 9252 acydburn
        }
525 9252 acydburn
526 9252 acydburn
        /**
527 9252 acydburn
        * Get conflicts content for download. This is generally a merged file, but preserving conflicts and adding explanations to it.
528 9252 acydburn
        * A user could then go through this file, search for the conflicts and changes the code accordingly.
529 6313 acydburn
        *
530 6313 acydburn
        * @param string $label1 the cvs file version/label from the original set of lines
531 6313 acydburn
        * @param string $label2 the cvs file version/label from the new set of lines
532 6345 acydburn
        * @param string $label_sep the explanation between label1 and label2 - more of a helper for the user
533 6313 acydburn
        *
534 6313 acydburn
        * @return mixed the merged output
535 6313 acydburn
        */
536 9252 acydburn
        function get_conflicts_content($label1 = 'CURRENT_FILE', $label2 = 'NEW_FILE', $label_sep = 'DIFF_SEP_EXPLAIN')
537 6313 acydburn
        {
538 6313 acydburn
                global $user;
539 6313 acydburn
540 6313 acydburn
                $label1 = (!empty($user->lang[$label1])) ? $user->lang[$label1] : $label1;
541 6313 acydburn
                $label2 = (!empty($user->lang[$label2])) ? $user->lang[$label2] : $label2;
542 6345 acydburn
                $label_sep = (!empty($user->lang[$label_sep])) ? $user->lang[$label_sep] : $label_sep;
543 6313 acydburn
544 6313 acydburn
                $lines = array();
545 6313 acydburn
546 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
547 6313 acydburn
                {
548 10163 acydburn
                        $edit = $this->_edits[$i];
549 10163 acydburn
550 6313 acydburn
                        if ($edit->is_conflict())
551 6313 acydburn
                        {
552 9252 acydburn
                                // Start conflict label
553 9303 acydburn
                                $label_start        = array('<<<<<<< ' . $label1);
554 9303 acydburn
                                $label_mid                = array('======= ' . $label_sep);
555 9303 acydburn
                                $label_end                = array('>>>>>>> ' . $label2);
556 9252 acydburn
557 9252 acydburn
                                $lines = array_merge($lines, $label_start, $edit->final1, $label_mid, $edit->final2, $label_end);
558 9505 acydburn
                                $this->_conflicting_blocks++;
559 6313 acydburn
                        }
560 6313 acydburn
                        else
561 6313 acydburn
                        {
562 6313 acydburn
                                $lines = array_merge($lines, $edit->merged());
563 6313 acydburn
                        }
564 6313 acydburn
                }
565 6313 acydburn
566 6313 acydburn
                return $lines;
567 6313 acydburn
        }
568 6313 acydburn
569 6313 acydburn
        /**
570 9505 acydburn
        * Return merged output (used by the renderer)
571 9505 acydburn
        *
572 9505 acydburn
        * @return mixed the merged output
573 9505 acydburn
        */
574 9505 acydburn
        function merged_output()
575 9505 acydburn
        {
576 9505 acydburn
                return $this->get_conflicts_content();
577 9505 acydburn
        }
578 9505 acydburn
579 9505 acydburn
        /**
580 6313 acydburn
        * Merge the output and use the new file code for conflicts
581 6313 acydburn
        */
582 6313 acydburn
        function merged_new_output()
583 6313 acydburn
        {
584 6313 acydburn
                $lines = array();
585 6313 acydburn
586 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
587 6313 acydburn
                {
588 10163 acydburn
                        $edit = $this->_edits[$i];
589 10163 acydburn
590 6313 acydburn
                        if ($edit->is_conflict())
591 6313 acydburn
                        {
592 6313 acydburn
                                $lines = array_merge($lines, $edit->final2);
593 6313 acydburn
                        }
594 6313 acydburn
                        else
595 6313 acydburn
                        {
596 6313 acydburn
                                $lines = array_merge($lines, $edit->merged());
597 6313 acydburn
                        }
598 6313 acydburn
                }
599 6313 acydburn
600 6313 acydburn
                return $lines;
601 6313 acydburn
        }
602 6313 acydburn
603 6313 acydburn
        /**
604 6313 acydburn
        * Merge the output and use the original file code for conflicts
605 6313 acydburn
        */
606 6313 acydburn
        function merged_orig_output()
607 6313 acydburn
        {
608 6313 acydburn
                $lines = array();
609 6313 acydburn
610 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
611 6313 acydburn
                {
612 10163 acydburn
                        $edit = $this->_edits[$i];
613 10163 acydburn
614 6313 acydburn
                        if ($edit->is_conflict())
615 6313 acydburn
                        {
616 6313 acydburn
                                $lines = array_merge($lines, $edit->final1);
617 6313 acydburn
                        }
618 6313 acydburn
                        else
619 6313 acydburn
                        {
620 6313 acydburn
                                $lines = array_merge($lines, $edit->merged());
621 6313 acydburn
                        }
622 6313 acydburn
                }
623 6313 acydburn
624 6313 acydburn
                return $lines;
625 6313 acydburn
        }
626 6313 acydburn
627 6313 acydburn
        /**
628 6313 acydburn
        * Get conflicting block(s)
629 6313 acydburn
        */
630 6313 acydburn
        function get_conflicts()
631 6313 acydburn
        {
632 6313 acydburn
                $conflicts = array();
633 6313 acydburn
634 10163 acydburn
                for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
635 6313 acydburn
                {
636 10163 acydburn
                        $edit = $this->_edits[$i];
637 10163 acydburn
638 6313 acydburn
                        if ($edit->is_conflict())
639 6313 acydburn
                        {
640 6313 acydburn
                                $conflicts[] = array($edit->final1, $edit->final2);
641 6313 acydburn
                        }
642 6313 acydburn
                }
643 6313 acydburn
644 6313 acydburn
                return $conflicts;
645 6313 acydburn
        }
646 6313 acydburn
647 6313 acydburn
        /**
648 6313 acydburn
        * @access private
649 6313 acydburn
        */
650 6695 acydburn
        function _diff3(&$edits1, &$edits2)
651 6313 acydburn
        {
652 6313 acydburn
                $edits = array();
653 8692 acydburn
                $bb = new diff3_block_builder();
654 6313 acydburn
655 6313 acydburn
                $e1 = current($edits1);
656 6313 acydburn
                $e2 = current($edits2);
657 6313 acydburn
658 6313 acydburn
                while ($e1 || $e2)
659 6313 acydburn
                {
660 6313 acydburn
                        if ($e1 && $e2 && is_a($e1, 'diff_op_copy') && is_a($e2, 'diff_op_copy'))
661 6313 acydburn
                        {
662 6313 acydburn
                                // We have copy blocks from both diffs. This is the (only) time we want to emit a diff3 copy block.
663 6313 acydburn
                                // Flush current diff3 diff block, if any.
664 6313 acydburn
                                if ($edit = $bb->finish())
665 6313 acydburn
                                {
666 6313 acydburn
                                        $edits[] = $edit;
667 6313 acydburn
                                }
668 6313 acydburn
669 6313 acydburn
                                $ncopy = min($e1->norig(), $e2->norig());
670 8692 acydburn
                                $edits[] = new diff3_op_copy(array_slice($e1->orig, 0, $ncopy));
671 6313 acydburn
672 6313 acydburn
                                if ($e1->norig() > $ncopy)
673 6313 acydburn
                                {
674 6313 acydburn
                                        array_splice($e1->orig, 0, $ncopy);
675 6313 acydburn
                                        array_splice($e1->final, 0, $ncopy);
676 6313 acydburn
                                }
677 6313 acydburn
                                else
678 6313 acydburn
                                {
679 6313 acydburn
                                        $e1 = next($edits1);
680 6313 acydburn
                                }
681 6313 acydburn
682 6313 acydburn
                                if ($e2->norig() > $ncopy)
683 6313 acydburn
                                {
684 6313 acydburn
                                        array_splice($e2->orig, 0, $ncopy);
685 6313 acydburn
                                        array_splice($e2->final, 0, $ncopy);
686 6313 acydburn
                                }
687 6313 acydburn
                                else
688 6313 acydburn
                                {
689 6313 acydburn
                                        $e2 = next($edits2);
690 6313 acydburn
                                }
691 6313 acydburn
                        }
692 6313 acydburn
                        else
693 6313 acydburn
                        {
694 6313 acydburn
                                if ($e1 && $e2)
695 6313 acydburn
                                {
696 6313 acydburn
                                        if ($e1->orig && $e2->orig)
697 6313 acydburn
                                        {
698 6313 acydburn
                                                $norig = min($e1->norig(), $e2->norig());
699 6313 acydburn
                                                $orig = array_splice($e1->orig, 0, $norig);
700 6313 acydburn
                                                array_splice($e2->orig, 0, $norig);
701 6313 acydburn
                                                $bb->input($orig);
702 6313 acydburn
                                        }
703 6313 acydburn
                                        else
704 6313 acydburn
                                        {
705 6313 acydburn
                                                $norig = 0;
706 6313 acydburn
                                        }
707 6313 acydburn
708 6313 acydburn
                                        if (is_a($e1, 'diff_op_copy'))
709 6313 acydburn
                                        {
710 6313 acydburn
                                                $bb->out1(array_splice($e1->final, 0, $norig));
711 6313 acydburn
                                        }
712 6313 acydburn
713 6313 acydburn
                                        if (is_a($e2, 'diff_op_copy'))
714 6313 acydburn
                                        {
715 6313 acydburn
                                                $bb->out2(array_splice($e2->final, 0, $norig));
716 6313 acydburn
                                        }
717 6313 acydburn
                                }
718 6313 acydburn
719 6313 acydburn
                                if ($e1 && ! $e1->orig)
720 6313 acydburn
                                {
721 6313 acydburn
                                        $bb->out1($e1->final);
722 6313 acydburn
                                        $e1 = next($edits1);
723 6313 acydburn
                                }
724 6313 acydburn
725 6313 acydburn
                                if ($e2 && ! $e2->orig)
726 6313 acydburn
                                {
727 6313 acydburn
                                        $bb->out2($e2->final);
728 6313 acydburn
                                        $e2 = next($edits2);
729 6313 acydburn
                                }
730 6313 acydburn
                        }
731 6313 acydburn
                }
732 6313 acydburn
733 6313 acydburn
                if ($edit = $bb->finish())
734 6313 acydburn
                {
735 6313 acydburn
                        $edits[] = $edit;
736 6313 acydburn
                }
737 6313 acydburn
738 6313 acydburn
                return $edits;
739 6313 acydburn
        }
740 6313 acydburn
}
741 6313 acydburn
742 6313 acydburn
/**
743 8034 acydburn
* @package diff
744 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
745 6313 acydburn
*
746 6313 acydburn
* @access private
747 6313 acydburn
*/
748 6313 acydburn
class diff3_op
749 6313 acydburn
{
750 6313 acydburn
        function diff3_op($orig = false, $final1 = false, $final2 = false)
751 6313 acydburn
        {
752 6313 acydburn
                $this->orig = $orig ? $orig : array();
753 6313 acydburn
                $this->final1 = $final1 ? $final1 : array();
754 6313 acydburn
                $this->final2 = $final2 ? $final2 : array();
755 6313 acydburn
        }
756 6313 acydburn
757 6313 acydburn
        function merged()
758 6313 acydburn
        {
759 6313 acydburn
                if (!isset($this->_merged))
760 6313 acydburn
                {
761 10163 acydburn
                        // Prepare the arrays before we compare them. ;)
762 10163 acydburn
                        $this->solve_prepare();
763 10163 acydburn
764 6313 acydburn
                        if ($this->final1 === $this->final2)
765 6313 acydburn
                        {
766 6313 acydburn
                                $this->_merged = &$this->final1;
767 6313 acydburn
                        }
768 6313 acydburn
                        else if ($this->final1 === $this->orig)
769 6313 acydburn
                        {
770 6313 acydburn
                                $this->_merged = &$this->final2;
771 6313 acydburn
                        }
772 6313 acydburn
                        else if ($this->final2 === $this->orig)
773 6313 acydburn
                        {
774 6313 acydburn
                                $this->_merged = &$this->final1;
775 6313 acydburn
                        }
776 6313 acydburn
                        else
777 6313 acydburn
                        {
778 10160 acydburn
                                // The following tries to aggressively solve conflicts...
779 6313 acydburn
                                $this->_merged = false;
780 10160 acydburn
                                $this->solve_conflict();
781 6313 acydburn
                        }
782 6313 acydburn
                }
783 6313 acydburn
784 6313 acydburn
                return $this->_merged;
785 6313 acydburn
        }
786 6313 acydburn
787 6313 acydburn
        function is_conflict()
788 6313 acydburn
        {
789 6313 acydburn
                return ($this->merged() === false) ? true : false;
790 6313 acydburn
        }
791 10160 acydburn
792 10160 acydburn
        /**
793 10163 acydburn
        * Function to prepare the arrays for comparing - we want to skip over newline changes
794 10163 acydburn
        * @author acydburn
795 10163 acydburn
        */
796 10163 acydburn
        function solve_prepare()
797 10163 acydburn
        {
798 10163 acydburn
                // We can simplify one case where the array is usually supposed to be empty...
799 10163 acydburn
                if (sizeof($this->orig) == 1 && trim($this->orig[0]) === '') $this->orig = array();
800 10163 acydburn
                if (sizeof($this->final1) == 1 && trim($this->final1[0]) === '') $this->final1 = array();
801 10163 acydburn
                if (sizeof($this->final2) == 1 && trim($this->final2[0]) === '') $this->final2 = array();
802 10163 acydburn
803 10163 acydburn
                // Now we only can have the case where the only difference between arrays are newlines, so compare all cases
804 10163 acydburn
805 10163 acydburn
                // First, some strings we can compare...
806 10163 acydburn
                $orig = $final1 = $final2 = '';
807 10163 acydburn
808 10163 acydburn
                foreach ($this->orig as $null => $line) $orig .= trim($line);
809 10163 acydburn
                foreach ($this->final1 as $null => $line) $final1 .= trim($line);
810 10163 acydburn
                foreach ($this->final2 as $null => $line) $final2 .= trim($line);
811 10163 acydburn
812 10163 acydburn
                // final1 === final2
813 10163 acydburn
                if ($final1 === $final2)
814 10163 acydburn
                {
815 10163 acydburn
                        // We preserve the part which will be used in the merge later
816 10163 acydburn
                        $this->final2 = $this->final1;
817 10163 acydburn
                }
818 10163 acydburn
                // final1 === orig
819 10163 acydburn
                else if ($final1 === $orig)
820 10163 acydburn
                {
821 10163 acydburn
                        // Here it does not really matter what we choose, but we will use the new code
822 10163 acydburn
                        $this->orig = $this->final1;
823 10163 acydburn
                }
824 10163 acydburn
                // final2 === orig
825 10163 acydburn
                else if ($final2 === $orig)
826 10163 acydburn
                {
827 10163 acydburn
                        // Here it does not really matter too (final1 will be used), but we will use the new code
828 10163 acydburn
                        $this->orig = $this->final2;
829 10163 acydburn
                }
830 10163 acydburn
        }
831 10163 acydburn
832 10163 acydburn
        /**
833 10163 acydburn
        * Find code portions from $orig in $final1 and use $final2 as merged instance if provided
834 10163 acydburn
        * @author acydburn
835 10163 acydburn
        */
836 10163 acydburn
        function _compare_conflict_seq($orig, $final1, $final2 = false)
837 10163 acydburn
        {
838 10163 acydburn
                $result = array('merge_found' => false, 'merge' => array());
839 10163 acydburn
840 10163 acydburn
                $_orig = &$this->$orig;
841 10163 acydburn
                $_final1 = &$this->$final1;
842 10163 acydburn
843 10163 acydburn
                // Ok, we basically search for $orig in $final1
844 10163 acydburn
                $compare_seq = sizeof($_orig);
845 10163 acydburn
846 10163 acydburn
                // Go through the conflict code
847 10163 acydburn
                for ($i = 0, $j = 0, $size = sizeof($_final1); $i < $size; $i++, $j = $i)
848 10163 acydburn
                {
849 10163 acydburn
                        $line = $_final1[$i];
850 10163 acydburn
                        $skip = 0;
851 10163 acydburn
852 10163 acydburn
                        for ($x = 0; $x < $compare_seq; $x++)
853 10163 acydburn
                        {
854 10163 acydburn
                                // Try to skip all matching lines
855 10163 acydburn
                                if (trim($line) === trim($_orig[$x]))
856 10163 acydburn
                                {
857 10163 acydburn
                                        $line = (++$j < $size) ? $_final1[$j] : $line;
858 10163 acydburn
                                        $skip++;
859 10163 acydburn
                                }
860 10163 acydburn
                        }
861 10163 acydburn
862 10163 acydburn
                        if ($skip === $compare_seq)
863 10163 acydburn
                        {
864 10163 acydburn
                                $result['merge_found'] = true;
865 10163 acydburn
866 10163 acydburn
                                if ($final2 !== false)
867 10163 acydburn
                                {
868 10163 acydburn
                                        $result['merge'] = array_merge($result['merge'], $this->$final2);
869 10163 acydburn
                                }
870 10163 acydburn
                                $i += ($skip - 1);
871 10163 acydburn
                        }
872 10163 acydburn
                        else if ($final2 !== false)
873 10163 acydburn
                        {
874 10163 acydburn
                                $result['merge'][] = $line;
875 10163 acydburn
                        }
876 10163 acydburn
                }
877 10163 acydburn
878 10163 acydburn
                return $result;
879 10163 acydburn
        }
880 10163 acydburn
881 10163 acydburn
        /**
882 10160 acydburn
        * Tries to solve conflicts aggressively based on typical "assumptions"
883 10160 acydburn
        * @author acydburn
884 10160 acydburn
        */
885 10160 acydburn
        function solve_conflict()
886 10160 acydburn
        {
887 10160 acydburn
                $this->_merged = false;
888 10160 acydburn
889 10160 acydburn
                // CASE ONE: orig changed into final2, but modified/unknown code in final1.
890 10160 acydburn
                // IF orig is found "as is" in final1 we replace the code directly in final1 and populate this as final2/merge
891 10160 acydburn
                if (sizeof($this->orig) && sizeof($this->final2))
892 10160 acydburn
                {
893 10163 acydburn
                        $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
894 10160 acydburn
895 10163 acydburn
                        if ($result['merge_found'])
896 10163 acydburn
                        {
897 10163 acydburn
                                $this->final2 = $result['merge'];
898 10163 acydburn
                                $this->_merged = &$this->final2;
899 10163 acydburn
                                return;
900 10163 acydburn
                        }
901 10160 acydburn
902 10163 acydburn
                        $result = $this->_compare_conflict_seq('final2', 'final1');
903 10163 acydburn
904 10163 acydburn
                        if ($result['merge_found'])
905 10160 acydburn
                        {
906 10163 acydburn
                                $this->_merged = &$this->final1;
907 10163 acydburn
                                return;
908 10163 acydburn
                        }
909 10160 acydburn
910 10163 acydburn
                        // Try to solve $Id$ issues. ;)
911 10163 acydburn
                        if (sizeof($this->orig) == 1 && sizeof($this->final1) == 1 && sizeof($this->final2) == 1)
912 10163 acydburn
                        {
913 10163 acydburn
                                $match = '#^' . preg_quote('* @version $Id: ', '#') . '[a-z\._\- ]+[0-9]+ [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9\:Z]+ [a-z0-9_\- ]+\$$#';
914 10163 acydburn
915 10163 acydburn
                                if (preg_match($match, $this->orig[0]) && preg_match($match, $this->final1[0]) && preg_match($match, $this->final2[0]))
916 10160 acydburn
                                {
917 10163 acydburn
                                        $this->_merged = &$this->final2;
918 10163 acydburn
                                        return;
919 10160 acydburn
                                }
920 10163 acydburn
                        }
921 10160 acydburn
922 10163 acydburn
                        $second_run = false;
923 10163 acydburn
924 10163 acydburn
                        // Try to solve issues where the only reason why the above did not work is a newline being removed in the final1 code but exist in the orig/final2 code
925 10163 acydburn
                        if (trim($this->orig[0]) === '' && trim($this->final2[0]) === '')
926 10163 acydburn
                        {
927 10163 acydburn
                                unset($this->orig[0], $this->final2[0]);
928 10163 acydburn
                                $this->orig = array_values($this->orig);
929 10163 acydburn
                                $this->final2 = array_values($this->final2);
930 10163 acydburn
931 10163 acydburn
                                $second_run = true;
932 10163 acydburn
                        }
933 10163 acydburn
934 10163 acydburn
                        // The same is true for a line at the end. ;)
935 10163 acydburn
                        if (sizeof($this->orig) && sizeof($this->final2) && sizeof($this->orig) === sizeof($this->final2) && trim($this->orig[sizeof($this->orig)-1]) === '' && trim($this->final2[sizeof($this->final2)-1]) === '')
936 10163 acydburn
                        {
937 10163 acydburn
                                unset($this->orig[sizeof($this->orig)-1], $this->final2[sizeof($this->final2)-1]);
938 10163 acydburn
                                $this->orig = array_values($this->orig);
939 10163 acydburn
                                $this->final2 = array_values($this->final2);
940 10163 acydburn
941 10163 acydburn
                                $second_run = true;
942 10163 acydburn
                        }
943 10163 acydburn
944 10163 acydburn
                        if ($second_run)
945 10163 acydburn
                        {
946 10163 acydburn
                                $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
947 10163 acydburn
948 10163 acydburn
                                if ($result['merge_found'])
949 10160 acydburn
                                {
950 10163 acydburn
                                        $this->final2 = $result['merge'];
951 10163 acydburn
                                        $this->_merged = &$this->final2;
952 10163 acydburn
                                        return;
953 10160 acydburn
                                }
954 10163 acydburn
955 10163 acydburn
                                $result = $this->_compare_conflict_seq('final2', 'final1');
956 10163 acydburn
957 10163 acydburn
                                if ($result['merge_found'])
958 10160 acydburn
                                {
959 10163 acydburn
                                        $this->_merged = &$this->final1;
960 10163 acydburn
                                        return;
961 10160 acydburn
                                }
962 10160 acydburn
                        }
963 10160 acydburn
964 10160 acydburn
                        return;
965 10160 acydburn
                }
966 10160 acydburn
967 10160 acydburn
                // CASE TWO: Added lines from orig to final2 but final1 had added lines too. Just merge them.
968 10160 acydburn
                if (!sizeof($this->orig) && $this->final1 !== $this->final2 && sizeof($this->final1) && sizeof($this->final2))
969 10160 acydburn
                {
970 10163 acydburn
                        $result = $this->_compare_conflict_seq('final2', 'final1');
971 10160 acydburn
972 10163 acydburn
                        if ($result['merge_found'])
973 10163 acydburn
                        {
974 10163 acydburn
                                $this->final2 = $this->final1;
975 10163 acydburn
                                $this->_merged = &$this->final1;
976 10163 acydburn
                        }
977 10163 acydburn
                        else
978 10163 acydburn
                        {
979 10163 acydburn
                                $result = $this->_compare_conflict_seq('final1', 'final2');
980 10163 acydburn
981 10163 acydburn
                                if (!$result['merge_found'])
982 10163 acydburn
                                {
983 10163 acydburn
                                        $this->final2 = array_merge($this->final1, $this->final2);
984 10163 acydburn
                                        $this->_merged = &$this->final2;
985 10163 acydburn
                                }
986 10163 acydburn
                                else
987 10163 acydburn
                                {
988 10163 acydburn
                                        $this->final2 = $this->final1;
989 10163 acydburn
                                        $this->_merged = &$this->final1;
990 10163 acydburn
                                }
991 10163 acydburn
                        }
992 10163 acydburn
993 10160 acydburn
                        return;
994 10160 acydburn
                }
995 10160 acydburn
996 10160 acydburn
                // CASE THREE: Removed lines (orig has the to-remove line(s), but final1 has additional lines which does not need to be removed). Just remove orig from final1 and then use final1 as final2/merge
997 10160 acydburn
                if (!sizeof($this->final2) && sizeof($this->orig) && sizeof($this->final1) && $this->orig !== $this->final1)
998 10160 acydburn
                {
999 10168 acydburn
                        $result = $this->_compare_conflict_seq('orig', 'final1');
1000 10168 acydburn
1001 10168 acydburn
                        if (!$result['merge_found'])
1002 10168 acydburn
                        {
1003 10168 acydburn
                                return;
1004 10168 acydburn
                        }
1005 10168 acydburn
1006 10163 acydburn
                        // First of all, try to find the code in orig in final1. ;)
1007 10163 acydburn
                        $compare_seq = sizeof($this->orig);
1008 10168 acydburn
                        $begin = $end = -1;
1009 10168 acydburn
                        $j = 0;
1010 10160 acydburn
1011 10168 acydburn
                        for ($i = 0, $size = sizeof($this->final1); $i < $size; $i++)
1012 10160 acydburn
                        {
1013 10168 acydburn
                                $line = $this->final1[$i];
1014 10168 acydburn
1015 10163 acydburn
                                if (trim($line) === trim($this->orig[$j]))
1016 10160 acydburn
                                {
1017 10168 acydburn
                                        // Mark begin
1018 10163 acydburn
                                        if ($begin === -1)
1019 10160 acydburn
                                        {
1020 10163 acydburn
                                                $begin = $i;
1021 10160 acydburn
                                        }
1022 10163 acydburn
1023 10168 acydburn
                                        // End is always $i, the last found line
1024 10168 acydburn
                                        $end = $i;
1025 10168 acydburn
1026 10163 acydburn
                                        if (isset($this->orig[$j+1]))
1027 10163 acydburn
                                        {
1028 10163 acydburn
                                                $j++;
1029 10163 acydburn
                                        }
1030 10160 acydburn
                                }
1031 10160 acydburn
                        }
1032 10160 acydburn
1033 10163 acydburn
                        if ($begin !== -1 && $begin + ($compare_seq - 1) == $end)
1034 10160 acydburn
                        {
1035 10163 acydburn
                                foreach ($this->final1 as $i => $line)
1036 10163 acydburn
                                {
1037 10163 acydburn
                                        if ($i < $begin || $i > $end)
1038 10163 acydburn
                                        {
1039 10163 acydburn
                                                $merged[] = $line;
1040 10163 acydburn
                                        }
1041 10163 acydburn
                                }
1042 10163 acydburn
1043 10163 acydburn
                                $this->final2 = $merged;
1044 10160 acydburn
                                $this->_merged = &$this->final2;
1045 10160 acydburn
                        }
1046 10160 acydburn
1047 10160 acydburn
                        return;
1048 10160 acydburn
                }
1049 10160 acydburn
1050 10160 acydburn
                return;
1051 10160 acydburn
        }
1052 6313 acydburn
}
1053 6313 acydburn
1054 6313 acydburn
/**
1055 8034 acydburn
* @package diff
1056 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
1057 6313 acydburn
*
1058 6313 acydburn
* @access private
1059 6313 acydburn
*/
1060 6313 acydburn
class diff3_op_copy extends diff3_op
1061 6313 acydburn
{
1062 6313 acydburn
        function diff3_op_copy($lines = false)
1063 6313 acydburn
        {
1064 6313 acydburn
                $this->orig = $lines ? $lines : array();
1065 6313 acydburn
                $this->final1 = &$this->orig;
1066 6313 acydburn
                $this->final2 = &$this->orig;
1067 6313 acydburn
        }
1068 6313 acydburn
1069 6313 acydburn
        function merged()
1070 6313 acydburn
        {
1071 6313 acydburn
                return $this->orig;
1072 6313 acydburn
        }
1073 6313 acydburn
1074 6313 acydburn
        function is_conflict()
1075 6313 acydburn
        {
1076 6313 acydburn
                return false;
1077 6313 acydburn
        }
1078 6313 acydburn
}
1079 6313 acydburn
1080 6313 acydburn
/**
1081 8034 acydburn
* @package diff
1082 6313 acydburn
* @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
1083 6313 acydburn
*
1084 6313 acydburn
* @access private
1085 6313 acydburn
*/
1086 6313 acydburn
class diff3_block_builder
1087 6313 acydburn
{
1088 6313 acydburn
        function diff3_block_builder()
1089 6313 acydburn
        {
1090 6313 acydburn
                $this->_init();
1091 6313 acydburn
        }
1092 6313 acydburn
1093 6313 acydburn
        function input($lines)
1094 6313 acydburn
        {
1095 6313 acydburn
                if ($lines)
1096 6313 acydburn
                {
1097 6313 acydburn
                        $this->_append($this->orig, $lines);
1098 6313 acydburn
                }
1099 6313 acydburn
        }
1100 6313 acydburn
1101 6313 acydburn
        function out1($lines)
1102 6313 acydburn
        {
1103 6313 acydburn
                if ($lines)
1104 6313 acydburn
                {
1105 6313 acydburn
                        $this->_append($this->final1, $lines);
1106 6313 acydburn
                }
1107 6313 acydburn
        }
1108 6313 acydburn
1109 6313 acydburn
        function out2($lines)
1110 6313 acydburn
        {
1111 6313 acydburn
                if ($lines)
1112 6313 acydburn
                {
1113 6313 acydburn
                        $this->_append($this->final2, $lines);
1114 6313 acydburn
                }
1115 6313 acydburn
        }
1116 6313 acydburn
1117 6313 acydburn
        function is_empty()
1118 6313 acydburn
        {
1119 6313 acydburn
                return !$this->orig && !$this->final1 && !$this->final2;
1120 6313 acydburn
        }
1121 6313 acydburn
1122 6313 acydburn
        function finish()
1123 6313 acydburn
        {
1124 6313 acydburn
                if ($this->is_empty())
1125 6313 acydburn
                {
1126 6313 acydburn
                        return false;
1127 6313 acydburn
                }
1128 6313 acydburn
                else
1129 6313 acydburn
                {
1130 8692 acydburn
                        $edit = new diff3_op($this->orig, $this->final1, $this->final2);
1131 6313 acydburn
                        $this->_init();
1132 6313 acydburn
                        return $edit;
1133 6313 acydburn
                }
1134 6313 acydburn
        }
1135 6313 acydburn
1136 6313 acydburn
        function _init()
1137 6313 acydburn
        {
1138 6313 acydburn
                $this->orig = $this->final1 = $this->final2 = array();
1139 6313 acydburn
        }
1140 6313 acydburn
1141 6313 acydburn
        function _append(&$array, $lines)
1142 6313 acydburn
        {
1143 6313 acydburn
                array_splice($array, sizeof($array), 0, $lines);
1144 6313 acydburn
        }
1145 6313 acydburn
}