Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
diff.php
0001 <?php
0002 /**
0003 *
0004 * This file is part of the phpBB Forum Software package.
0005 *
0006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007 * @license GNU General Public License, version 2 (GPL-2.0)
0008 *
0009 * For full copyright and license information, please see
0010 * the docs/CREDITS.txt file.
0011 *
0012 */
0013
0014 /**
0015 * @ignore
0016 */
0017 if (!defined('IN_PHPBB'))
0018 {
0019 exit;
0020 }
0021
0022 /**
0023 * Code from pear.php.net, Text_Diff-1.1.0 package
0024 * http://pear.php.net/package/Text_Diff/
0025 *
0026 * Modified by phpBB Limited to meet our coding standards
0027 * and being able to integrate into phpBB
0028 *
0029 * General API for generating and formatting diffs - the differences between
0030 * two sequences of strings.
0031 *
0032 * Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
0033 * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
0034 *
0035 * @package diff
0036 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0037 */
0038 class diff
0039 {
0040 /**
0041 * Array of changes.
0042 * @var array
0043 */
0044 var $_edits;
0045
0046 /**
0047 * Computes diffs between sequences of strings.
0048 *
0049 * @param array &$from_content An array of strings. Typically these are lines from a file.
0050 * @param array &$to_content An array of strings.
0051 * @param bool $preserve_cr If true, \r is replaced by a new line in the diff output
0052 */
0053 function diff(&$from_content, &$to_content, $preserve_cr = true)
0054 {
0055 $diff_engine = new diff_engine();
0056 $this->_edits = $diff_engine->diff($from_content, $to_content, $preserve_cr);
0057 }
0058
0059 /**
0060 * Returns the array of differences.
0061 */
0062 function get_diff()
0063 {
0064 return $this->_edits;
0065 }
0066
0067 /**
0068 * returns the number of new (added) lines in a given diff.
0069 *
0070 * @since Text_Diff 1.1.0
0071 *
0072 * @return integer The number of new lines
0073 */
0074 function count_added_lines()
0075 {
0076 $count = 0;
0077
0078 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0079 {
0080 $edit = $this->_edits[$i];
0081
0082 if (is_a($edit, 'diff_op_add') || is_a($edit, 'diff_op_change'))
0083 {
0084 $count += $edit->nfinal();
0085 }
0086 }
0087 return $count;
0088 }
0089
0090 /**
0091 * Returns the number of deleted (removed) lines in a given diff.
0092 *
0093 * @since Text_Diff 1.1.0
0094 *
0095 * @return integer The number of deleted lines
0096 */
0097 function count_deleted_lines()
0098 {
0099 $count = 0;
0100
0101 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0102 {
0103 $edit = $this->_edits[$i];
0104
0105 if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_change'))
0106 {
0107 $count += $edit->norig();
0108 }
0109 }
0110 return $count;
0111 }
0112
0113 /**
0114 * Computes a reversed diff.
0115 *
0116 * Example:
0117 * <code>
0118 * $diff = new diff($lines1, $lines2);
0119 * $rev = $diff->reverse();
0120 * </code>
0121 *
0122 * @return diff A Diff object representing the inverse of the original diff.
0123 * Note that we purposely don't return a reference here, since
0124 * this essentially is a clone() method.
0125 */
0126 function reverse()
0127 {
0128 if (version_compare(zend_version(), '2', '>'))
0129 {
0130 $rev = clone($this);
0131 }
0132 else
0133 {
0134 $rev = $this;
0135 }
0136
0137 $rev->_edits = array();
0138
0139 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0140 {
0141 $edit = $this->_edits[$i];
0142 $rev->_edits[] = $edit->reverse();
0143 }
0144
0145 return $rev;
0146 }
0147
0148 /**
0149 * Checks for an empty diff.
0150 *
0151 * @return boolean True if two sequences were identical.
0152 */
0153 function is_empty()
0154 {
0155 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0156 {
0157 $edit = $this->_edits[$i];
0158
0159 // skip diff_op_copy
0160 if (is_a($edit, 'diff_op_copy'))
0161 {
0162 continue;
0163 }
0164
0165 if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_add'))
0166 {
0167 $orig = $edit->orig;
0168 $final = $edit->final;
0169
0170 // We can simplify one case where the array is usually supposed to be empty...
0171 if (sizeof($orig) == 1 && trim($orig[0]) === '') $orig = array();
0172 if (sizeof($final) == 1 && trim($final[0]) === '') $final = array();
0173
0174 if (!$orig && !$final)
0175 {
0176 continue;
0177 }
0178
0179 return false;
0180 }
0181
0182 return false;
0183 }
0184
0185 return true;
0186 }
0187
0188 /**
0189 * Computes the length of the Longest Common Subsequence (LCS).
0190 *
0191 * This is mostly for diagnostic purposes.
0192 *
0193 * @return integer The length of the LCS.
0194 */
0195 function lcs()
0196 {
0197 $lcs = 0;
0198
0199 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0200 {
0201 $edit = $this->_edits[$i];
0202
0203 if (is_a($edit, 'diff_op_copy'))
0204 {
0205 $lcs += sizeof($edit->orig);
0206 }
0207 }
0208 return $lcs;
0209 }
0210
0211 /**
0212 * Gets the original set of lines.
0213 *
0214 * This reconstructs the $from_lines parameter passed to the constructor.
0215 *
0216 * @return array The original sequence of strings.
0217 */
0218 function get_original()
0219 {
0220 $lines = array();
0221
0222 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0223 {
0224 $edit = $this->_edits[$i];
0225
0226 if ($edit->orig)
0227 {
0228 array_splice($lines, sizeof($lines), 0, $edit->orig);
0229 }
0230 }
0231 return $lines;
0232 }
0233
0234 /**
0235 * Gets the final set of lines.
0236 *
0237 * This reconstructs the $to_lines parameter passed to the constructor.
0238 *
0239 * @return array The sequence of strings.
0240 */
0241 function get_final()
0242 {
0243 $lines = array();
0244
0245 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0246 {
0247 $edit = $this->_edits[$i];
0248
0249 if ($edit->final)
0250 {
0251 array_splice($lines, sizeof($lines), 0, $edit->final);
0252 }
0253 }
0254 return $lines;
0255 }
0256
0257 /**
0258 * Removes trailing newlines from a line of text. This is meant to be used with array_walk().
0259 *
0260 * @param string &$line The line to trim.
0261 * @param integer $key The index of the line in the array. Not used.
0262 */
0263 function trim_newlines(&$line, $key)
0264 {
0265 $line = str_replace(array("\n", "\r"), '', $line);
0266 }
0267
0268 /**
0269 * Checks a diff for validity.
0270 *
0271 * This is here only for debugging purposes.
0272 */
0273 function _check($from_lines, $to_lines)
0274 {
0275 if (serialize($from_lines) != serialize($this->get_original()))
0276 {
0277 trigger_error("[diff] Reconstructed original doesn't match", E_USER_ERROR);
0278 }
0279
0280 if (serialize($to_lines) != serialize($this->get_final()))
0281 {
0282 trigger_error("[diff] Reconstructed final doesn't match", E_USER_ERROR);
0283 }
0284
0285 $rev = $this->reverse();
0286
0287 if (serialize($to_lines) != serialize($rev->get_original()))
0288 {
0289 trigger_error("[diff] Reversed original doesn't match", E_USER_ERROR);
0290 }
0291
0292 if (serialize($from_lines) != serialize($rev->get_final()))
0293 {
0294 trigger_error("[diff] Reversed final doesn't match", E_USER_ERROR);
0295 }
0296
0297 $prevtype = null;
0298
0299 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0300 {
0301 $edit = $this->_edits[$i];
0302
0303 if ($prevtype == get_class($edit))
0304 {
0305 trigger_error("[diff] Edit sequence is non-optimal", E_USER_ERROR);
0306 }
0307 $prevtype = get_class($edit);
0308 }
0309
0310 return true;
0311 }
0312 }
0313
0314 /**
0315 * @package diff
0316 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0317 */
0318 class mapped_diff extends diff
0319 {
0320 /**
0321 * Computes a diff between sequences of strings.
0322 *
0323 * This can be used to compute things like case-insensitve diffs, or diffs
0324 * which ignore changes in white-space.
0325 *
0326 * @param array $from_lines An array of strings.
0327 * @param array $to_lines An array of strings.
0328 * @param array $mapped_from_lines This array should have the same size number of elements as $from_lines.
0329 * The elements in $mapped_from_lines and $mapped_to_lines are what is actually
0330 * compared when computing the diff.
0331 * @param array $mapped_to_lines This array should have the same number of elements as $to_lines.
0332 */
0333 function mapped_diff(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
0334 {
0335 if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines))
0336 {
0337 return false;
0338 }
0339
0340 parent::diff($mapped_from_lines, $mapped_to_lines);
0341
0342 $xi = $yi = 0;
0343 for ($i = 0; $i < sizeof($this->_edits); $i++)
0344 {
0345 $orig = &$this->_edits[$i]->orig;
0346 if (is_array($orig))
0347 {
0348 $orig = array_slice($from_lines, $xi, sizeof($orig));
0349 $xi += sizeof($orig);
0350 }
0351
0352 $final = &$this->_edits[$i]->final;
0353 if (is_array($final))
0354 {
0355 $final = array_slice($to_lines, $yi, sizeof($final));
0356 $yi += sizeof($final);
0357 }
0358 }
0359 }
0360 }
0361
0362 /**
0363 * @package diff
0364 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0365 *
0366 * @access private
0367 */
0368 class diff_op
0369 {
0370 var $orig;
0371 var $final;
0372
0373 function &reverse()
0374 {
0375 trigger_error('[diff] Abstract method', E_USER_ERROR);
0376 }
0377
0378 function norig()
0379 {
0380 return ($this->orig) ? sizeof($this->orig) : 0;
0381 }
0382
0383 function nfinal()
0384 {
0385 return ($this->final) ? sizeof($this->final) : 0;
0386 }
0387 }
0388
0389 /**
0390 * @package diff
0391 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0392 *
0393 * @access private
0394 */
0395 class diff_op_copy extends diff_op
0396 {
0397 function diff_op_copy($orig, $final = false)
0398 {
0399 if (!is_array($final))
0400 {
0401 $final = $orig;
0402 }
0403 $this->orig = $orig;
0404 $this->final = $final;
0405 }
0406
0407 function &reverse()
0408 {
0409 $reverse = new diff_op_copy($this->final, $this->orig);
0410 return $reverse;
0411 }
0412 }
0413
0414 /**
0415 * @package diff
0416 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0417 *
0418 * @access private
0419 */
0420 class diff_op_delete extends diff_op
0421 {
0422 function diff_op_delete($lines)
0423 {
0424 $this->orig = $lines;
0425 $this->final = false;
0426 }
0427
0428 function &reverse()
0429 {
0430 $reverse = new diff_op_add($this->orig);
0431 return $reverse;
0432 }
0433 }
0434
0435 /**
0436 * @package diff
0437 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0438 *
0439 * @access private
0440 */
0441 class diff_op_add extends diff_op
0442 {
0443 function diff_op_add($lines)
0444 {
0445 $this->final = $lines;
0446 $this->orig = false;
0447 }
0448
0449 function &reverse()
0450 {
0451 $reverse = new diff_op_delete($this->final);
0452 return $reverse;
0453 }
0454 }
0455
0456 /**
0457 * @package diff
0458 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0459 *
0460 * @access private
0461 */
0462 class diff_op_change extends diff_op
0463 {
0464 function diff_op_change($orig, $final)
0465 {
0466 $this->orig = $orig;
0467 $this->final = $final;
0468 }
0469
0470 function &reverse()
0471 {
0472 $reverse = new diff_op_change($this->final, $this->orig);
0473 return $reverse;
0474 }
0475 }
0476
0477
0478 /**
0479 * A class for computing three way diffs.
0480 *
0481 * @package diff
0482 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0483 */
0484 class diff3 extends diff
0485 {
0486 /**
0487 * Conflict counter.
0488 * @var integer
0489 */
0490 var $_conflicting_blocks = 0;
0491
0492 /**
0493 * Computes diff between 3 sequences of strings.
0494 *
0495 * @param array &$orig The original lines to use.
0496 * @param array &$final1 The first version to compare to.
0497 * @param array &$final2 The second version to compare to.
0498 * @param bool $preserve_cr If true, \r\n and bare \r are replaced by a new line
0499 * in the diff output
0500 */
0501 function diff3(&$orig, &$final1, &$final2, $preserve_cr = true)
0502 {
0503 $diff_engine = new diff_engine();
0504
0505 $diff_1 = $diff_engine->diff($orig, $final1, $preserve_cr);
0506 $diff_2 = $diff_engine->diff($orig, $final2, $preserve_cr);
0507
0508 unset($diff_engine);
0509
0510 $this->_edits = $this->_diff3($diff_1, $diff_2);
0511 }
0512
0513 /**
0514 * Return number of conflicts
0515 */
0516 function get_num_conflicts()
0517 {
0518 $conflicts = 0;
0519
0520 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0521 {
0522 $edit = $this->_edits[$i];
0523
0524 if ($edit->is_conflict())
0525 {
0526 $conflicts++;
0527 }
0528 }
0529
0530 return $conflicts;
0531 }
0532
0533 /**
0534 * Get conflicts content for download. This is generally a merged file, but preserving conflicts and adding explanations to it.
0535 * A user could then go through this file, search for the conflicts and changes the code accordingly.
0536 *
0537 * @param string $label1 the cvs file version/label from the original set of lines
0538 * @param string $label2 the cvs file version/label from the new set of lines
0539 * @param string $label_sep the explanation between label1 and label2 - more of a helper for the user
0540 *
0541 * @return mixed the merged output
0542 */
0543 function get_conflicts_content($label1 = 'CURRENT_FILE', $label2 = 'NEW_FILE', $label_sep = 'DIFF_SEP_EXPLAIN')
0544 {
0545 global $user;
0546
0547 $label1 = (!empty($user->lang[$label1])) ? $user->lang[$label1] : $label1;
0548 $label2 = (!empty($user->lang[$label2])) ? $user->lang[$label2] : $label2;
0549 $label_sep = (!empty($user->lang[$label_sep])) ? $user->lang[$label_sep] : $label_sep;
0550
0551 $lines = array();
0552
0553 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0554 {
0555 $edit = $this->_edits[$i];
0556
0557 if ($edit->is_conflict())
0558 {
0559 // Start conflict label
0560 $label_start = array('<<<<<<< ' . $label1);
0561 $label_mid = array('======= ' . $label_sep);
0562 $label_end = array('>>>>>>> ' . $label2);
0563
0564 $lines = array_merge($lines, $label_start, $edit->final1, $label_mid, $edit->final2, $label_end);
0565 $this->_conflicting_blocks++;
0566 }
0567 else
0568 {
0569 $lines = array_merge($lines, $edit->merged());
0570 }
0571 }
0572
0573 return $lines;
0574 }
0575
0576 /**
0577 * Return merged output (used by the renderer)
0578 *
0579 * @return mixed the merged output
0580 */
0581 function merged_output()
0582 {
0583 return $this->get_conflicts_content();
0584 }
0585
0586 /**
0587 * Merge the output and use the new file code for conflicts
0588 */
0589 function merged_new_output()
0590 {
0591 $lines = array();
0592
0593 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0594 {
0595 $edit = $this->_edits[$i];
0596
0597 if ($edit->is_conflict())
0598 {
0599 $lines = array_merge($lines, $edit->final2);
0600 }
0601 else
0602 {
0603 $lines = array_merge($lines, $edit->merged());
0604 }
0605 }
0606
0607 return $lines;
0608 }
0609
0610 /**
0611 * Merge the output and use the original file code for conflicts
0612 */
0613 function merged_orig_output()
0614 {
0615 $lines = array();
0616
0617 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0618 {
0619 $edit = $this->_edits[$i];
0620
0621 if ($edit->is_conflict())
0622 {
0623 $lines = array_merge($lines, $edit->final1);
0624 }
0625 else
0626 {
0627 $lines = array_merge($lines, $edit->merged());
0628 }
0629 }
0630
0631 return $lines;
0632 }
0633
0634 /**
0635 * Get conflicting block(s)
0636 */
0637 function get_conflicts()
0638 {
0639 $conflicts = array();
0640
0641 for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0642 {
0643 $edit = $this->_edits[$i];
0644
0645 if ($edit->is_conflict())
0646 {
0647 $conflicts[] = array($edit->final1, $edit->final2);
0648 }
0649 }
0650
0651 return $conflicts;
0652 }
0653
0654 /**
0655 * @access private
0656 */
0657 function _diff3(&$edits1, &$edits2)
0658 {
0659 $edits = array();
0660 $bb = new diff3_block_builder();
0661
0662 $e1 = current($edits1);
0663 $e2 = current($edits2);
0664
0665 while ($e1 || $e2)
0666 {
0667 if ($e1 && $e2 && is_a($e1, 'diff_op_copy') && is_a($e2, 'diff_op_copy'))
0668 {
0669 // We have copy blocks from both diffs. This is the (only) time we want to emit a diff3 copy block.
0670 // Flush current diff3 diff block, if any.
0671 if ($edit = $bb->finish())
0672 {
0673 $edits[] = $edit;
0674 }
0675
0676 $ncopy = min($e1->norig(), $e2->norig());
0677 $edits[] = new diff3_op_copy(array_slice($e1->orig, 0, $ncopy));
0678
0679 if ($e1->norig() > $ncopy)
0680 {
0681 array_splice($e1->orig, 0, $ncopy);
0682 array_splice($e1->final, 0, $ncopy);
0683 }
0684 else
0685 {
0686 $e1 = next($edits1);
0687 }
0688
0689 if ($e2->norig() > $ncopy)
0690 {
0691 array_splice($e2->orig, 0, $ncopy);
0692 array_splice($e2->final, 0, $ncopy);
0693 }
0694 else
0695 {
0696 $e2 = next($edits2);
0697 }
0698 }
0699 else
0700 {
0701 if ($e1 && $e2)
0702 {
0703 if ($e1->orig && $e2->orig)
0704 {
0705 $norig = min($e1->norig(), $e2->norig());
0706 $orig = array_splice($e1->orig, 0, $norig);
0707 array_splice($e2->orig, 0, $norig);
0708 $bb->input($orig);
0709 }
0710 else
0711 {
0712 $norig = 0;
0713 }
0714
0715 if (is_a($e1, 'diff_op_copy'))
0716 {
0717 $bb->out1(array_splice($e1->final, 0, $norig));
0718 }
0719
0720 if (is_a($e2, 'diff_op_copy'))
0721 {
0722 $bb->out2(array_splice($e2->final, 0, $norig));
0723 }
0724 }
0725
0726 if ($e1 && ! $e1->orig)
0727 {
0728 $bb->out1($e1->final);
0729 $e1 = next($edits1);
0730 }
0731
0732 if ($e2 && ! $e2->orig)
0733 {
0734 $bb->out2($e2->final);
0735 $e2 = next($edits2);
0736 }
0737 }
0738 }
0739
0740 if ($edit = $bb->finish())
0741 {
0742 $edits[] = $edit;
0743 }
0744
0745 return $edits;
0746 }
0747 }
0748
0749 /**
0750 * @package diff
0751 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
0752 *
0753 * @access private
0754 */
0755 class diff3_op
0756 {
0757 function diff3_op($orig = false, $final1 = false, $final2 = false)
0758 {
0759 $this->orig = $orig ? $orig : array();
0760 $this->final1 = $final1 ? $final1 : array();
0761 $this->final2 = $final2 ? $final2 : array();
0762 }
0763
0764 function merged()
0765 {
0766 if (!isset($this->_merged))
0767 {
0768 // Prepare the arrays before we compare them. ;)
0769 $this->solve_prepare();
0770
0771 if ($this->final1 === $this->final2)
0772 {
0773 $this->_merged = &$this->final1;
0774 }
0775 else if ($this->final1 === $this->orig)
0776 {
0777 $this->_merged = &$this->final2;
0778 }
0779 else if ($this->final2 === $this->orig)
0780 {
0781 $this->_merged = &$this->final1;
0782 }
0783 else
0784 {
0785 // The following tries to aggressively solve conflicts...
0786 $this->_merged = false;
0787 $this->solve_conflict();
0788 }
0789 }
0790
0791 return $this->_merged;
0792 }
0793
0794 function is_conflict()
0795 {
0796 return ($this->merged() === false) ? true : false;
0797 }
0798
0799 /**
0800 * Function to prepare the arrays for comparing - we want to skip over newline changes
0801 * @author acydburn
0802 */
0803 function solve_prepare()
0804 {
0805 // We can simplify one case where the array is usually supposed to be empty...
0806 if (sizeof($this->orig) == 1 && trim($this->orig[0]) === '') $this->orig = array();
0807 if (sizeof($this->final1) == 1 && trim($this->final1[0]) === '') $this->final1 = array();
0808 if (sizeof($this->final2) == 1 && trim($this->final2[0]) === '') $this->final2 = array();
0809
0810 // Now we only can have the case where the only difference between arrays are newlines, so compare all cases
0811
0812 // First, some strings we can compare...
0813 $orig = $final1 = $final2 = '';
0814
0815 foreach ($this->orig as $null => $line) $orig .= trim($line);
0816 foreach ($this->final1 as $null => $line) $final1 .= trim($line);
0817 foreach ($this->final2 as $null => $line) $final2 .= trim($line);
0818
0819 // final1 === final2
0820 if ($final1 === $final2)
0821 {
0822 // We preserve the part which will be used in the merge later
0823 $this->final2 = $this->final1;
0824 }
0825 // final1 === orig
0826 else if ($final1 === $orig)
0827 {
0828 // Here it does not really matter what we choose, but we will use the new code
0829 $this->orig = $this->final1;
0830 }
0831 // final2 === orig
0832 else if ($final2 === $orig)
0833 {
0834 // Here it does not really matter too (final1 will be used), but we will use the new code
0835 $this->orig = $this->final2;
0836 }
0837 }
0838
0839 /**
0840 * Find code portions from $orig in $final1 and use $final2 as merged instance if provided
0841 * @author acydburn
0842 */
0843 function _compare_conflict_seq($orig, $final1, $final2 = false)
0844 {
0845 $result = array('merge_found' => false, 'merge' => array());
0846
0847 $_orig = &$this->$orig;
0848 $_final1 = &$this->$final1;
0849
0850 // Ok, we basically search for $orig in $final1
0851 $compare_seq = sizeof($_orig);
0852
0853 // Go through the conflict code
0854 for ($i = 0, $j = 0, $size = sizeof($_final1); $i < $size; $i++, $j = $i)
0855 {
0856 $line = $_final1[$i];
0857 $skip = 0;
0858
0859 for ($x = 0; $x < $compare_seq; $x++)
0860 {
0861 // Try to skip all matching lines
0862 if (trim($line) === trim($_orig[$x]))
0863 {
0864 $line = (++$j < $size) ? $_final1[$j] : $line;
0865 $skip++;
0866 }
0867 }
0868
0869 if ($skip === $compare_seq)
0870 {
0871 $result['merge_found'] = true;
0872
0873 if ($final2 !== false)
0874 {
0875 $result['merge'] = array_merge($result['merge'], $this->$final2);
0876 }
0877 $i += ($skip - 1);
0878 }
0879 else if ($final2 !== false)
0880 {
0881 $result['merge'][] = $line;
0882 }
0883 }
0884
0885 return $result;
0886 }
0887
0888 /**
0889 * Tries to solve conflicts aggressively based on typical "assumptions"
0890 * @author acydburn
0891 */
0892 function solve_conflict()
0893 {
0894 $this->_merged = false;
0895
0896 // CASE ONE: orig changed into final2, but modified/unknown code in final1.
0897 // IF orig is found "as is" in final1 we replace the code directly in final1 and populate this as final2/merge
0898 if (sizeof($this->orig) && sizeof($this->final2))
0899 {
0900 $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
0901
0902 if ($result['merge_found'])
0903 {
0904 $this->final2 = $result['merge'];
0905 $this->_merged = &$this->final2;
0906 return;
0907 }
0908
0909 $result = $this->_compare_conflict_seq('final2', 'final1');
0910
0911 if ($result['merge_found'])
0912 {
0913 $this->_merged = &$this->final1;
0914 return;
0915 }
0916
0917 // Try to solve $Id$ issues. ;)
0918 if (sizeof($this->orig) == 1 && sizeof($this->final1) == 1 && sizeof($this->final2) == 1)
0919 {
0920 $match = '#^' . preg_quote('* @version $Id: ', '#') . '[a-z\._\- ]+[0-9]+ [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9\:Z]+ [a-z0-9_\- ]+\$$#';
0921
0922 if (preg_match($match, $this->orig[0]) && preg_match($match, $this->final1[0]) && preg_match($match, $this->final2[0]))
0923 {
0924 $this->_merged = &$this->final2;
0925 return;
0926 }
0927 }
0928
0929 $second_run = false;
0930
0931 // 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
0932 if (trim($this->orig[0]) === '' && trim($this->final2[0]) === '')
0933 {
0934 unset($this->orig[0], $this->final2[0]);
0935 $this->orig = array_values($this->orig);
0936 $this->final2 = array_values($this->final2);
0937
0938 $second_run = true;
0939 }
0940
0941 // The same is true for a line at the end. ;)
0942 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]) === '')
0943 {
0944 unset($this->orig[sizeof($this->orig)-1], $this->final2[sizeof($this->final2)-1]);
0945 $this->orig = array_values($this->orig);
0946 $this->final2 = array_values($this->final2);
0947
0948 $second_run = true;
0949 }
0950
0951 if ($second_run)
0952 {
0953 $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
0954
0955 if ($result['merge_found'])
0956 {
0957 $this->final2 = $result['merge'];
0958 $this->_merged = &$this->final2;
0959 return;
0960 }
0961
0962 $result = $this->_compare_conflict_seq('final2', 'final1');
0963
0964 if ($result['merge_found'])
0965 {
0966 $this->_merged = &$this->final1;
0967 return;
0968 }
0969 }
0970
0971 return;
0972 }
0973
0974 // CASE TWO: Added lines from orig to final2 but final1 had added lines too. Just merge them.
0975 if (!sizeof($this->orig) && $this->final1 !== $this->final2 && sizeof($this->final1) && sizeof($this->final2))
0976 {
0977 $result = $this->_compare_conflict_seq('final2', 'final1');
0978
0979 if ($result['merge_found'])
0980 {
0981 $this->final2 = $this->final1;
0982 $this->_merged = &$this->final1;
0983 }
0984 else
0985 {
0986 $result = $this->_compare_conflict_seq('final1', 'final2');
0987
0988 if (!$result['merge_found'])
0989 {
0990 $this->final2 = array_merge($this->final1, $this->final2);
0991 $this->_merged = &$this->final2;
0992 }
0993 else
0994 {
0995 $this->final2 = $this->final1;
0996 $this->_merged = &$this->final1;
0997 }
0998 }
0999
1000 return;
1001 }
1002
1003 // 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
1004 if (!sizeof($this->final2) && sizeof($this->orig) && sizeof($this->final1) && $this->orig !== $this->final1)
1005 {
1006 $result = $this->_compare_conflict_seq('orig', 'final1');
1007
1008 if (!$result['merge_found'])
1009 {
1010 return;
1011 }
1012
1013 // First of all, try to find the code in orig in final1. ;)
1014 $compare_seq = sizeof($this->orig);
1015 $begin = $end = -1;
1016 $j = 0;
1017
1018 for ($i = 0, $size = sizeof($this->final1); $i < $size; $i++)
1019 {
1020 $line = $this->final1[$i];
1021
1022 if (trim($line) === trim($this->orig[$j]))
1023 {
1024 // Mark begin
1025 if ($begin === -1)
1026 {
1027 $begin = $i;
1028 }
1029
1030 // End is always $i, the last found line
1031 $end = $i;
1032
1033 if (isset($this->orig[$j+1]))
1034 {
1035 $j++;
1036 }
1037 }
1038 }
1039
1040 if ($begin !== -1 && $begin + ($compare_seq - 1) == $end)
1041 {
1042 foreach ($this->final1 as $i => $line)
1043 {
1044 if ($i < $begin || $i > $end)
1045 {
1046 $merged[] = $line;
1047 }
1048 }
1049
1050 $this->final2 = $merged;
1051 $this->_merged = &$this->final2;
1052 }
1053
1054 return;
1055 }
1056
1057 return;
1058 }
1059 }
1060
1061 /**
1062 * @package diff
1063 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
1064 *
1065 * @access private
1066 */
1067 class diff3_op_copy extends diff3_op
1068 {
1069 function diff3_op_copy($lines = false)
1070 {
1071 $this->orig = $lines ? $lines : array();
1072 $this->final1 = &$this->orig;
1073 $this->final2 = &$this->orig;
1074 }
1075
1076 function merged()
1077 {
1078 return $this->orig;
1079 }
1080
1081 function is_conflict()
1082 {
1083 return false;
1084 }
1085 }
1086
1087 /**
1088 * @package diff
1089 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
1090 *
1091 * @access private
1092 */
1093 class diff3_block_builder
1094 {
1095 function diff3_block_builder()
1096 {
1097 $this->_init();
1098 }
1099
1100 function input($lines)
1101 {
1102 if ($lines)
1103 {
1104 $this->_append($this->orig, $lines);
1105 }
1106 }
1107
1108 function out1($lines)
1109 {
1110 if ($lines)
1111 {
1112 $this->_append($this->final1, $lines);
1113 }
1114 }
1115
1116 function out2($lines)
1117 {
1118 if ($lines)
1119 {
1120 $this->_append($this->final2, $lines);
1121 }
1122 }
1123
1124 function is_empty()
1125 {
1126 return !$this->orig && !$this->final1 && !$this->final2;
1127 }
1128
1129 function finish()
1130 {
1131 if ($this->is_empty())
1132 {
1133 return false;
1134 }
1135 else
1136 {
1137 $edit = new diff3_op($this->orig, $this->final1, $this->final2);
1138 $this->_init();
1139 return $edit;
1140 }
1141 }
1142
1143 function _init()
1144 {
1145 $this->orig = $this->final1 = $this->final2 = array();
1146 }
1147
1148 function _append(&$array, $lines)
1149 {
1150 array_splice($array, sizeof($array), 0, $lines);
1151 }
1152 }
1153