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

View | Annotate | Download (23.7 KB)

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