[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/Text/ -> Diff.php (source)

   1  <?php
   2  /**
   3   * General API for generating and formatting diffs - the differences between
   4   * two sequences of strings.
   5   *
   6   * The original PHP version of this code was written by Geoffrey T. Dairiki
   7   * <dairiki@dairiki.org>, and is used/adapted with his permission.
   8   *
   9   * Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
  10   * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
  11   *
  12   * See the enclosed file COPYING for license information (LGPL). If you did
  13   * not receive this file, see https://opensource.org/license/lgpl-2-1/.
  14   *
  15   * @package Text_Diff
  16   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
  17   */
  18  class Text_Diff {
  19  
  20      /**
  21       * Array of changes.
  22       *
  23       * @var array
  24       */
  25      var $_edits;
  26  
  27      /**
  28       * Computes diffs between sequences of strings.
  29       *
  30       * @param string $engine     Name of the diffing engine to use.  'auto'
  31       *                           will automatically select the best.
  32       * @param array $params      Parameters to pass to the diffing engine.
  33       *                           Normally an array of two arrays, each
  34       *                           containing the lines from a file.
  35       */
  36      function __construct( $engine, $params )
  37      {
  38          // Backward compatibility workaround.
  39          if (!is_string($engine)) {
  40              $params = array($engine, $params);
  41              $engine = 'auto';
  42          }
  43  
  44          if ($engine == 'auto') {
  45              $engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
  46          } else {
  47              $engine = basename($engine);
  48          }
  49  
  50          // WP #7391
  51          require_once dirname(__FILE__).'/Diff/Engine/' . $engine . '.php';
  52          $class = 'Text_Diff_Engine_' . $engine;
  53          $diff_engine = new $class();
  54  
  55          $this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
  56      }
  57  
  58      /**
  59       * PHP4 constructor.
  60       */
  61  	public function Text_Diff( $engine, $params ) {
  62          self::__construct( $engine, $params );
  63      }
  64  
  65      /**
  66       * Returns the array of differences.
  67       */
  68      function getDiff()
  69      {
  70          return $this->_edits;
  71      }
  72  
  73      /**
  74       * returns the number of new (added) lines in a given diff.
  75       *
  76       * @since Text_Diff 1.1.0
  77       *
  78       * @return int The number of new lines
  79       */
  80      function countAddedLines()
  81      {
  82          $count = 0;
  83          foreach ($this->_edits as $edit) {
  84              if (is_a($edit, 'Text_Diff_Op_add') ||
  85                  is_a($edit, 'Text_Diff_Op_change')) {
  86                  $count += $edit->nfinal();
  87              }
  88          }
  89          return $count;
  90      }
  91  
  92      /**
  93       * Returns the number of deleted (removed) lines in a given diff.
  94       *
  95       * @since Text_Diff 1.1.0
  96       *
  97       * @return int The number of deleted lines
  98       */
  99      function countDeletedLines()
 100      {
 101          $count = 0;
 102          foreach ($this->_edits as $edit) {
 103              if (is_a($edit, 'Text_Diff_Op_delete') ||
 104                  is_a($edit, 'Text_Diff_Op_change')) {
 105                  $count += $edit->norig();
 106              }
 107          }
 108          return $count;
 109      }
 110  
 111      /**
 112       * Computes a reversed diff.
 113       *
 114       * Example:
 115       * <code>
 116       * $diff = new Text_Diff($lines1, $lines2);
 117       * $rev = $diff->reverse();
 118       * </code>
 119       *
 120       * @return Text_Diff  A Diff object representing the inverse of the
 121       *                    original diff.  Note that we purposely don't return a
 122       *                    reference here, since this essentially is a clone()
 123       *                    method.
 124       */
 125      function reverse()
 126      {
 127          if (version_compare(zend_version(), '2', '>')) {
 128              $rev = clone($this);
 129          } else {
 130              $rev = $this;
 131          }
 132          $rev->_edits = array();
 133          foreach ($this->_edits as $edit) {
 134              $rev->_edits[] = $edit->reverse();
 135          }
 136          return $rev;
 137      }
 138  
 139      /**
 140       * Checks for an empty diff.
 141       *
 142       * @return bool True if two sequences were identical.
 143       */
 144      function isEmpty()
 145      {
 146          foreach ($this->_edits as $edit) {
 147              if (!is_a($edit, 'Text_Diff_Op_copy')) {
 148                  return false;
 149              }
 150          }
 151          return true;
 152      }
 153  
 154      /**
 155       * Computes the length of the Longest Common Subsequence (LCS).
 156       *
 157       * This is mostly for diagnostic purposes.
 158       *
 159       * @return int The length of the LCS.
 160       */
 161      function lcs()
 162      {
 163          $lcs = 0;
 164          foreach ($this->_edits as $edit) {
 165              if (is_a($edit, 'Text_Diff_Op_copy')) {
 166                  $lcs += count($edit->orig);
 167              }
 168          }
 169          return $lcs;
 170      }
 171  
 172      /**
 173       * Gets the original set of lines.
 174       *
 175       * This reconstructs the $from_lines parameter passed to the constructor.
 176       *
 177       * @return array  The original sequence of strings.
 178       */
 179      function getOriginal()
 180      {
 181          $lines = array();
 182          foreach ($this->_edits as $edit) {
 183              if ($edit->orig) {
 184                  array_splice($lines, count($lines), 0, $edit->orig);
 185              }
 186          }
 187          return $lines;
 188      }
 189  
 190      /**
 191       * Gets the final set of lines.
 192       *
 193       * This reconstructs the $to_lines parameter passed to the constructor.
 194       *
 195       * @return array  The sequence of strings.
 196       */
 197      function getFinal()
 198      {
 199          $lines = array();
 200          foreach ($this->_edits as $edit) {
 201              if ($edit->final) {
 202                  array_splice($lines, count($lines), 0, $edit->final);
 203              }
 204          }
 205          return $lines;
 206      }
 207  
 208      /**
 209       * Removes trailing newlines from a line of text. This is meant to be used
 210       * with array_walk().
 211       *
 212       * @param string $line  The line to trim.
 213       * @param int    $key   The index of the line in the array. Not used.
 214       */
 215      static function trimNewlines(&$line, $key)
 216      {
 217          $line = str_replace(array("\n", "\r"), '', $line);
 218      }
 219  
 220      /**
 221       * Determines the location of the system temporary directory.
 222       *
 223       * @access protected
 224       *
 225       * @return string  A directory name which can be used for temp files.
 226       *                 Returns false if one could not be found.
 227       */
 228      static function _getTempDir()
 229      {
 230          $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
 231                                 'c:\windows\temp', 'c:\winnt\temp');
 232  
 233          /* Try PHP's upload_tmp_dir directive. */
 234          $tmp = ini_get('upload_tmp_dir');
 235  
 236          /* Otherwise, try to determine the TMPDIR environment variable. */
 237          if (!strlen($tmp)) {
 238              $tmp = getenv('TMPDIR');
 239          }
 240  
 241          /* If we still cannot determine a value, then cycle through a list of
 242           * preset possibilities. */
 243          while (!strlen($tmp) && count($tmp_locations)) {
 244              $tmp_check = array_shift($tmp_locations);
 245              if (@is_dir($tmp_check)) {
 246                  $tmp = $tmp_check;
 247              }
 248          }
 249  
 250          /* If it is still empty, we have failed, so return false; otherwise
 251           * return the directory determined. */
 252          return strlen($tmp) ? $tmp : false;
 253      }
 254  
 255      /**
 256       * Checks a diff for validity.
 257       *
 258       * This is here only for debugging purposes.
 259       */
 260      function _check($from_lines, $to_lines)
 261      {
 262          if (serialize($from_lines) != serialize($this->getOriginal())) {
 263              throw new Text_Exception("Reconstructed original does not match");
 264          }
 265          if (serialize($to_lines) != serialize($this->getFinal())) {
 266              throw new Text_Exception("Reconstructed final does not match");
 267          }
 268  
 269          $rev = $this->reverse();
 270          if (serialize($to_lines) != serialize($rev->getOriginal())) {
 271              throw new Text_Exception("Reversed original does not match");
 272          }
 273          if (serialize($from_lines) != serialize($rev->getFinal())) {
 274              throw new Text_Exception("Reversed final does not match");
 275          }
 276  
 277          $prevtype = null;
 278          foreach ($this->_edits as $edit) {
 279              if ($prevtype !== null && $edit instanceof $prevtype) {
 280                  throw new Text_Exception("Edit sequence is non-optimal");
 281              }
 282              $prevtype = get_class($edit);
 283          }
 284  
 285          return true;
 286      }
 287  
 288  }
 289  
 290  /**
 291   * @package Text_Diff
 292   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 293   */
 294  class Text_MappedDiff extends Text_Diff {
 295  
 296      /**
 297       * Computes a diff between sequences of strings.
 298       *
 299       * This can be used to compute things like case-insensitive diffs, or diffs
 300       * which ignore changes in white-space.
 301       *
 302       * @param array $from_lines         An array of strings.
 303       * @param array $to_lines           An array of strings.
 304       * @param array $mapped_from_lines  This array should have the same size
 305       *                                  number of elements as $from_lines.  The
 306       *                                  elements in $mapped_from_lines and
 307       *                                  $mapped_to_lines are what is actually
 308       *                                  compared when computing the diff.
 309       * @param array $mapped_to_lines    This array should have the same number
 310       *                                  of elements as $to_lines.
 311       */
 312      function __construct($from_lines, $to_lines,
 313                               $mapped_from_lines, $mapped_to_lines)
 314      {
 315          assert(count($from_lines) == count($mapped_from_lines));
 316          assert(count($to_lines) == count($mapped_to_lines));
 317  
 318          parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
 319  
 320          $xi = $yi = 0;
 321          for ($i = 0; $i < count($this->_edits); $i++) {
 322              $orig = &$this->_edits[$i]->orig;
 323              if (is_array($orig)) {
 324                  $orig = array_slice($from_lines, $xi, count($orig));
 325                  $xi += count($orig);
 326              }
 327  
 328              $final = &$this->_edits[$i]->final;
 329              if (is_array($final)) {
 330                  $final = array_slice($to_lines, $yi, count($final));
 331                  $yi += count($final);
 332              }
 333          }
 334      }
 335  
 336      /**
 337       * PHP4 constructor.
 338       */
 339  	public function Text_MappedDiff( $from_lines, $to_lines,
 340                               $mapped_from_lines, $mapped_to_lines ) {
 341          self::__construct( $from_lines, $to_lines,
 342                               $mapped_from_lines, $mapped_to_lines );
 343      }
 344  
 345  }
 346  
 347  /**
 348   * @package Text_Diff
 349   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 350   *
 351   * @access private
 352   */
 353  abstract class Text_Diff_Op {
 354  
 355      var $orig;
 356      var $final;
 357  
 358      abstract function &reverse();
 359  
 360      function norig()
 361      {
 362          return $this->orig ? count($this->orig) : 0;
 363      }
 364  
 365      function nfinal()
 366      {
 367          return $this->final ? count($this->final) : 0;
 368      }
 369  
 370  }
 371  
 372  /**
 373   * @package Text_Diff
 374   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 375   *
 376   * @access private
 377   */
 378  class Text_Diff_Op_copy extends Text_Diff_Op {
 379  
 380      /**
 381       * PHP5 constructor.
 382       */
 383      function __construct( $orig, $final = false )
 384      {
 385          if (!is_array($final)) {
 386              $final = $orig;
 387          }
 388          $this->orig = $orig;
 389          $this->final = $final;
 390      }
 391  
 392      /**
 393       * PHP4 constructor.
 394       */
 395  	public function Text_Diff_Op_copy( $orig, $final = false ) {
 396          self::__construct( $orig, $final );
 397      }
 398  
 399      function &reverse()
 400      {
 401          $reverse = new Text_Diff_Op_copy($this->final, $this->orig);
 402          return $reverse;
 403      }
 404  
 405  }
 406  
 407  /**
 408   * @package Text_Diff
 409   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 410   *
 411   * @access private
 412   */
 413  class Text_Diff_Op_delete extends Text_Diff_Op {
 414  
 415      /**
 416       * PHP5 constructor.
 417       */
 418  	function __construct( $lines )
 419      {
 420          $this->orig = $lines;
 421          $this->final = false;
 422      }
 423  
 424      /**
 425       * PHP4 constructor.
 426       */
 427  	public function Text_Diff_Op_delete( $lines ) {
 428          self::__construct( $lines );
 429      }
 430  
 431      function &reverse()
 432      {
 433          $reverse = new Text_Diff_Op_add($this->orig);
 434          return $reverse;
 435      }
 436  
 437  }
 438  
 439  /**
 440   * @package Text_Diff
 441   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 442   *
 443   * @access private
 444   */
 445  class Text_Diff_Op_add extends Text_Diff_Op {
 446  
 447      /**
 448       * PHP5 constructor.
 449       */
 450      function __construct( $lines )
 451      {
 452          $this->final = $lines;
 453          $this->orig = false;
 454      }
 455  
 456      /**
 457       * PHP4 constructor.
 458       */
 459  	public function Text_Diff_Op_add( $lines ) {
 460          self::__construct( $lines );
 461      }
 462  
 463      function &reverse()
 464      {
 465          $reverse = new Text_Diff_Op_delete($this->final);
 466          return $reverse;
 467      }
 468  
 469  }
 470  
 471  /**
 472   * @package Text_Diff
 473   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 474   *
 475   * @access private
 476   */
 477  class Text_Diff_Op_change extends Text_Diff_Op {
 478  
 479      /**
 480       * PHP5 constructor.
 481       */
 482      function __construct( $orig, $final )
 483      {
 484          $this->orig = $orig;
 485          $this->final = $final;
 486      }
 487  
 488      /**
 489       * PHP4 constructor.
 490       */
 491  	public function Text_Diff_Op_change( $orig, $final ) {
 492          self::__construct( $orig, $final );
 493      }
 494  
 495      function &reverse()
 496      {
 497          $reverse = new Text_Diff_Op_change($this->final, $this->orig);
 498          return $reverse;
 499      }
 500  
 501  }


Generated : Sat Dec 21 08:20:01 2024 Cross-referenced by PHPXref