-
+ 00E510B70A203F1F8673F9E26743EAA5EA94BC44A5C3D23A8314F908E04CDA2A2F7D122D86C75C005D0CC5E4011695573247A6D0A7153C8414911B026E5CC30C
mp-wp/wp-includes/Text/Diff.php
(0 . 0)(1 . 414)
70434 <?php
70435 /**
70436 * General API for generating and formatting diffs - the differences between
70437 * two sequences of strings.
70438 *
70439 * The original PHP version of this code was written by Geoffrey T. Dairiki
70440 * <dairiki@dairiki.org>, and is used/adapted with his permission.
70441 *
70442 * $Horde: framework/Text_Diff/Diff.php,v 1.26 2008/01/04 10:07:49 jan Exp $
70443 *
70444 * Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
70445 * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
70446 *
70447 * See the enclosed file COPYING for license information (LGPL). If you did
70448 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
70449 *
70450 * @package Text_Diff
70451 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70452 */
70453 class Text_Diff {
70454
70455 /**
70456 * Array of changes.
70457 *
70458 * @var array
70459 */
70460 var $_edits;
70461
70462 /**
70463 * Computes diffs between sequences of strings.
70464 *
70465 * @param string $engine Name of the diffing engine to use. 'auto'
70466 * will automatically select the best.
70467 * @param array $params Parameters to pass to the diffing engine.
70468 * Normally an array of two arrays, each
70469 * containing the lines from a file.
70470 */
70471 function Text_Diff($engine, $params)
70472 {
70473 // Backward compatibility workaround.
70474 if (!is_string($engine)) {
70475 $params = array($engine, $params);
70476 $engine = 'auto';
70477 }
70478
70479 if ($engine == 'auto') {
70480 $engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
70481 } else {
70482 $engine = basename($engine);
70483 }
70484
70485 // WP #7391
70486 require_once dirname(__FILE__).'/Diff/Engine/' . $engine . '.php';
70487 $class = 'Text_Diff_Engine_' . $engine;
70488 $diff_engine = new $class();
70489
70490 $this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
70491 }
70492
70493 /**
70494 * Returns the array of differences.
70495 */
70496 function getDiff()
70497 {
70498 return $this->_edits;
70499 }
70500
70501 /**
70502 * Computes a reversed diff.
70503 *
70504 * Example:
70505 * <code>
70506 * $diff = new Text_Diff($lines1, $lines2);
70507 * $rev = $diff->reverse();
70508 * </code>
70509 *
70510 * @return Text_Diff A Diff object representing the inverse of the
70511 * original diff. Note that we purposely don't return a
70512 * reference here, since this essentially is a clone()
70513 * method.
70514 */
70515 function reverse()
70516 {
70517 if (version_compare(zend_version(), '2', '>')) {
70518 $rev = clone($this);
70519 } else {
70520 $rev = $this;
70521 }
70522 $rev->_edits = array();
70523 foreach ($this->_edits as $edit) {
70524 $rev->_edits[] = $edit->reverse();
70525 }
70526 return $rev;
70527 }
70528
70529 /**
70530 * Checks for an empty diff.
70531 *
70532 * @return boolean True if two sequences were identical.
70533 */
70534 function isEmpty()
70535 {
70536 foreach ($this->_edits as $edit) {
70537 if (!is_a($edit, 'Text_Diff_Op_copy')) {
70538 return false;
70539 }
70540 }
70541 return true;
70542 }
70543
70544 /**
70545 * Computes the length of the Longest Common Subsequence (LCS).
70546 *
70547 * This is mostly for diagnostic purposes.
70548 *
70549 * @return integer The length of the LCS.
70550 */
70551 function lcs()
70552 {
70553 $lcs = 0;
70554 foreach ($this->_edits as $edit) {
70555 if (is_a($edit, 'Text_Diff_Op_copy')) {
70556 $lcs += count($edit->orig);
70557 }
70558 }
70559 return $lcs;
70560 }
70561
70562 /**
70563 * Gets the original set of lines.
70564 *
70565 * This reconstructs the $from_lines parameter passed to the constructor.
70566 *
70567 * @return array The original sequence of strings.
70568 */
70569 function getOriginal()
70570 {
70571 $lines = array();
70572 foreach ($this->_edits as $edit) {
70573 if ($edit->orig) {
70574 array_splice($lines, count($lines), 0, $edit->orig);
70575 }
70576 }
70577 return $lines;
70578 }
70579
70580 /**
70581 * Gets the final set of lines.
70582 *
70583 * This reconstructs the $to_lines parameter passed to the constructor.
70584 *
70585 * @return array The sequence of strings.
70586 */
70587 function getFinal()
70588 {
70589 $lines = array();
70590 foreach ($this->_edits as $edit) {
70591 if ($edit->final) {
70592 array_splice($lines, count($lines), 0, $edit->final);
70593 }
70594 }
70595 return $lines;
70596 }
70597
70598 /**
70599 * Removes trailing newlines from a line of text. This is meant to be used
70600 * with array_walk().
70601 *
70602 * @param string $line The line to trim.
70603 * @param integer $key The index of the line in the array. Not used.
70604 */
70605 function trimNewlines(&$line, $key)
70606 {
70607 $line = str_replace(array("\n", "\r"), '', $line);
70608 }
70609
70610 /**
70611 * Determines the location of the system temporary directory.
70612 *
70613 * @static
70614 *
70615 * @access protected
70616 *
70617 * @return string A directory name which can be used for temp files.
70618 * Returns false if one could not be found.
70619 */
70620 function _getTempDir()
70621 {
70622 $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
70623 'c:\windows\temp', 'c:\winnt\temp');
70624
70625 /* Try PHP's upload_tmp_dir directive. */
70626 $tmp = ini_get('upload_tmp_dir');
70627
70628 /* Otherwise, try to determine the TMPDIR environment variable. */
70629 if (!strlen($tmp)) {
70630 $tmp = getenv('TMPDIR');
70631 }
70632
70633 /* If we still cannot determine a value, then cycle through a list of
70634 * preset possibilities. */
70635 while (!strlen($tmp) && count($tmp_locations)) {
70636 $tmp_check = array_shift($tmp_locations);
70637 if (@is_dir($tmp_check)) {
70638 $tmp = $tmp_check;
70639 }
70640 }
70641
70642 /* If it is still empty, we have failed, so return false; otherwise
70643 * return the directory determined. */
70644 return strlen($tmp) ? $tmp : false;
70645 }
70646
70647 /**
70648 * Checks a diff for validity.
70649 *
70650 * This is here only for debugging purposes.
70651 */
70652 function _check($from_lines, $to_lines)
70653 {
70654 if (serialize($from_lines) != serialize($this->getOriginal())) {
70655 trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
70656 }
70657 if (serialize($to_lines) != serialize($this->getFinal())) {
70658 trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
70659 }
70660
70661 $rev = $this->reverse();
70662 if (serialize($to_lines) != serialize($rev->getOriginal())) {
70663 trigger_error("Reversed original doesn't match", E_USER_ERROR);
70664 }
70665 if (serialize($from_lines) != serialize($rev->getFinal())) {
70666 trigger_error("Reversed final doesn't match", E_USER_ERROR);
70667 }
70668
70669 $prevtype = null;
70670 foreach ($this->_edits as $edit) {
70671 if ($prevtype == get_class($edit)) {
70672 trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
70673 }
70674 $prevtype = get_class($edit);
70675 }
70676
70677 return true;
70678 }
70679
70680 }
70681
70682 /**
70683 * @package Text_Diff
70684 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70685 */
70686 class Text_MappedDiff extends Text_Diff {
70687
70688 /**
70689 * Computes a diff between sequences of strings.
70690 *
70691 * This can be used to compute things like case-insensitve diffs, or diffs
70692 * which ignore changes in white-space.
70693 *
70694 * @param array $from_lines An array of strings.
70695 * @param array $to_lines An array of strings.
70696 * @param array $mapped_from_lines This array should have the same size
70697 * number of elements as $from_lines. The
70698 * elements in $mapped_from_lines and
70699 * $mapped_to_lines are what is actually
70700 * compared when computing the diff.
70701 * @param array $mapped_to_lines This array should have the same number
70702 * of elements as $to_lines.
70703 */
70704 function Text_MappedDiff($from_lines, $to_lines,
70705 $mapped_from_lines, $mapped_to_lines)
70706 {
70707 assert(count($from_lines) == count($mapped_from_lines));
70708 assert(count($to_lines) == count($mapped_to_lines));
70709
70710 parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
70711
70712 $xi = $yi = 0;
70713 for ($i = 0; $i < count($this->_edits); $i++) {
70714 $orig = &$this->_edits[$i]->orig;
70715 if (is_array($orig)) {
70716 $orig = array_slice($from_lines, $xi, count($orig));
70717 $xi += count($orig);
70718 }
70719
70720 $final = &$this->_edits[$i]->final;
70721 if (is_array($final)) {
70722 $final = array_slice($to_lines, $yi, count($final));
70723 $yi += count($final);
70724 }
70725 }
70726 }
70727
70728 }
70729
70730 /**
70731 * @package Text_Diff
70732 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70733 *
70734 * @access private
70735 */
70736 class Text_Diff_Op {
70737
70738 var $orig;
70739 var $final;
70740
70741 function &reverse()
70742 {
70743 trigger_error('Abstract method', E_USER_ERROR);
70744 }
70745
70746 function norig()
70747 {
70748 return $this->orig ? count($this->orig) : 0;
70749 }
70750
70751 function nfinal()
70752 {
70753 return $this->final ? count($this->final) : 0;
70754 }
70755
70756 }
70757
70758 /**
70759 * @package Text_Diff
70760 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70761 *
70762 * @access private
70763 */
70764 class Text_Diff_Op_copy extends Text_Diff_Op {
70765
70766 function Text_Diff_Op_copy($orig, $final = false)
70767 {
70768 if (!is_array($final)) {
70769 $final = $orig;
70770 }
70771 $this->orig = $orig;
70772 $this->final = $final;
70773 }
70774
70775 function &reverse()
70776 {
70777 $reverse = &new Text_Diff_Op_copy($this->final, $this->orig);
70778 return $reverse;
70779 }
70780
70781 }
70782
70783 /**
70784 * @package Text_Diff
70785 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70786 *
70787 * @access private
70788 */
70789 class Text_Diff_Op_delete extends Text_Diff_Op {
70790
70791 function Text_Diff_Op_delete($lines)
70792 {
70793 $this->orig = $lines;
70794 $this->final = false;
70795 }
70796
70797 function &reverse()
70798 {
70799 $reverse = &new Text_Diff_Op_add($this->orig);
70800 return $reverse;
70801 }
70802
70803 }
70804
70805 /**
70806 * @package Text_Diff
70807 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70808 *
70809 * @access private
70810 */
70811 class Text_Diff_Op_add extends Text_Diff_Op {
70812
70813 function Text_Diff_Op_add($lines)
70814 {
70815 $this->final = $lines;
70816 $this->orig = false;
70817 }
70818
70819 function &reverse()
70820 {
70821 $reverse = &new Text_Diff_Op_delete($this->final);
70822 return $reverse;
70823 }
70824
70825 }
70826
70827 /**
70828 * @package Text_Diff
70829 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
70830 *
70831 * @access private
70832 */
70833 class Text_Diff_Op_change extends Text_Diff_Op {
70834
70835 function Text_Diff_Op_change($orig, $final)
70836 {
70837 $this->orig = $orig;
70838 $this->final = $final;
70839 }
70840
70841 function &reverse()
70842 {
70843 $reverse = &new Text_Diff_Op_change($this->final, $this->orig);
70844 return $reverse;
70845 }
70846
70847 }