[ Index ]

WordPress Cross Reference

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 http://opensource.org/licenses/lgpl-license.php.
  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 Text_Diff($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       * Returns the array of differences.
  60       */
  61      function getDiff()
  62      {
  63          return $this->_edits;
  64      }
  65  
  66      /**
  67       * returns the number of new (added) lines in a given diff.
  68       *
  69       * @since Text_Diff 1.1.0
  70       *
  71       * @return integer The number of new lines
  72       */
  73      function countAddedLines()
  74      {
  75          $count = 0;
  76          foreach ($this->_edits as $edit) {
  77              if (is_a($edit, 'Text_Diff_Op_add') ||
  78                  is_a($edit, 'Text_Diff_Op_change')) {
  79                  $count += $edit->nfinal();
  80              }
  81          }
  82          return $count;
  83      }
  84  
  85      /**
  86       * Returns the number of deleted (removed) lines in a given diff.
  87       *
  88       * @since Text_Diff 1.1.0
  89       *
  90       * @return integer The number of deleted lines
  91       */
  92      function countDeletedLines()
  93      {
  94          $count = 0;
  95          foreach ($this->_edits as $edit) {
  96              if (is_a($edit, 'Text_Diff_Op_delete') ||
  97                  is_a($edit, 'Text_Diff_Op_change')) {
  98                  $count += $edit->norig();
  99              }
 100          }
 101          return $count;
 102      }
 103  
 104      /**
 105       * Computes a reversed diff.
 106       *
 107       * Example:
 108       * <code>
 109       * $diff = new Text_Diff($lines1, $lines2);
 110       * $rev = $diff->reverse();
 111       * </code>
 112       *
 113       * @return Text_Diff  A Diff object representing the inverse of the
 114       *                    original diff.  Note that we purposely don't return a
 115       *                    reference here, since this essentially is a clone()
 116       *                    method.
 117       */
 118      function reverse()
 119      {
 120          if (version_compare(zend_version(), '2', '>')) {
 121              $rev = clone($this);
 122          } else {
 123              $rev = $this;
 124          }
 125          $rev->_edits = array();
 126          foreach ($this->_edits as $edit) {
 127              $rev->_edits[] = $edit->reverse();
 128          }
 129          return $rev;
 130      }
 131  
 132      /**
 133       * Checks for an empty diff.
 134       *
 135       * @return boolean  True if two sequences were identical.
 136       */
 137      function isEmpty()
 138      {
 139          foreach ($this->_edits as $edit) {
 140              if (!is_a($edit, 'Text_Diff_Op_copy')) {
 141                  return false;
 142              }
 143          }
 144          return true;
 145      }
 146  
 147      /**
 148       * Computes the length of the Longest Common Subsequence (LCS).
 149       *
 150       * This is mostly for diagnostic purposes.
 151       *
 152       * @return integer  The length of the LCS.
 153       */
 154      function lcs()
 155      {
 156          $lcs = 0;
 157          foreach ($this->_edits as $edit) {
 158              if (is_a($edit, 'Text_Diff_Op_copy')) {
 159                  $lcs += count($edit->orig);
 160              }
 161          }
 162          return $lcs;
 163      }
 164  
 165      /**
 166       * Gets the original set of lines.
 167       *
 168       * This reconstructs the $from_lines parameter passed to the constructor.
 169       *
 170       * @return array  The original sequence of strings.
 171       */
 172      function getOriginal()
 173      {
 174          $lines = array();
 175          foreach ($this->_edits as $edit) {
 176              if ($edit->orig) {
 177                  array_splice($lines, count($lines), 0, $edit->orig);
 178              }
 179          }
 180          return $lines;
 181      }
 182  
 183      /**
 184       * Gets the final set of lines.
 185       *
 186       * This reconstructs the $to_lines parameter passed to the constructor.
 187       *
 188       * @return array  The sequence of strings.
 189       */
 190      function getFinal()
 191      {
 192          $lines = array();
 193          foreach ($this->_edits as $edit) {
 194              if ($edit->final) {
 195                  array_splice($lines, count($lines), 0, $edit->final);
 196              }
 197          }
 198          return $lines;
 199      }
 200  
 201      /**
 202       * Removes trailing newlines from a line of text. This is meant to be used
 203       * with array_walk().
 204       *
 205       * @param string $line  The line to trim.
 206       * @param integer $key  The index of the line in the array. Not used.
 207       */
 208      static function trimNewlines(&$line, $key)
 209      {
 210          $line = str_replace(array("\n", "\r"), '', $line);
 211      }
 212  
 213      /**
 214       * Determines the location of the system temporary directory.
 215       *
 216       * @static
 217       *
 218       * @access protected
 219       *
 220       * @return string  A directory name which can be used for temp files.
 221       *                 Returns false if one could not be found.
 222       */
 223      function _getTempDir()
 224      {
 225          $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
 226                                 'c:\windows\temp', 'c:\winnt\temp');
 227  
 228          /* Try PHP's upload_tmp_dir directive. */
 229          $tmp = ini_get('upload_tmp_dir');
 230  
 231          /* Otherwise, try to determine the TMPDIR environment variable. */
 232          if (!strlen($tmp)) {
 233              $tmp = getenv('TMPDIR');
 234          }
 235  
 236          /* If we still cannot determine a value, then cycle through a list of
 237           * preset possibilities. */
 238          while (!strlen($tmp) && count($tmp_locations)) {
 239              $tmp_check = array_shift($tmp_locations);
 240              if (@is_dir($tmp_check)) {
 241                  $tmp = $tmp_check;
 242              }
 243          }
 244  
 245          /* If it is still empty, we have failed, so return false; otherwise
 246           * return the directory determined. */
 247          return strlen($tmp) ? $tmp : false;
 248      }
 249  
 250      /**
 251       * Checks a diff for validity.
 252       *
 253       * This is here only for debugging purposes.
 254       */
 255      function _check($from_lines, $to_lines)
 256      {
 257          if (serialize($from_lines) != serialize($this->getOriginal())) {
 258              trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
 259          }
 260          if (serialize($to_lines) != serialize($this->getFinal())) {
 261              trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
 262          }
 263  
 264          $rev = $this->reverse();
 265          if (serialize($to_lines) != serialize($rev->getOriginal())) {
 266              trigger_error("Reversed original doesn't match", E_USER_ERROR);
 267          }
 268          if (serialize($from_lines) != serialize($rev->getFinal())) {
 269              trigger_error("Reversed final doesn't match", E_USER_ERROR);
 270          }
 271  
 272          $prevtype = null;
 273          foreach ($this->_edits as $edit) {
 274              if ($prevtype == get_class($edit)) {
 275                  trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
 276              }
 277              $prevtype = get_class($edit);
 278          }
 279  
 280          return true;
 281      }
 282  
 283  }
 284  
 285  /**
 286   * @package Text_Diff
 287   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 288   */
 289  class Text_MappedDiff extends Text_Diff {
 290  
 291      /**
 292       * Computes a diff between sequences of strings.
 293       *
 294       * This can be used to compute things like case-insensitve diffs, or diffs
 295       * which ignore changes in white-space.
 296       *
 297       * @param array $from_lines         An array of strings.
 298       * @param array $to_lines           An array of strings.
 299       * @param array $mapped_from_lines  This array should have the same size
 300       *                                  number of elements as $from_lines.  The
 301       *                                  elements in $mapped_from_lines and
 302       *                                  $mapped_to_lines are what is actually
 303       *                                  compared when computing the diff.
 304       * @param array $mapped_to_lines    This array should have the same number
 305       *                                  of elements as $to_lines.
 306       */
 307      function Text_MappedDiff($from_lines, $to_lines,
 308                               $mapped_from_lines, $mapped_to_lines)
 309      {
 310          assert(count($from_lines) == count($mapped_from_lines));
 311          assert(count($to_lines) == count($mapped_to_lines));
 312  
 313          parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
 314  
 315          $xi = $yi = 0;
 316          for ($i = 0; $i < count($this->_edits); $i++) {
 317              $orig = &$this->_edits[$i]->orig;
 318              if (is_array($orig)) {
 319                  $orig = array_slice($from_lines, $xi, count($orig));
 320                  $xi += count($orig);
 321              }
 322  
 323              $final = &$this->_edits[$i]->final;
 324              if (is_array($final)) {
 325                  $final = array_slice($to_lines, $yi, count($final));
 326                  $yi += count($final);
 327              }
 328          }
 329      }
 330  
 331  }
 332  
 333  /**
 334   * @package Text_Diff
 335   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 336   *
 337   * @access private
 338   */
 339  class Text_Diff_Op {
 340  
 341      var $orig;
 342      var $final;
 343  
 344      function &reverse()
 345      {
 346          trigger_error('Abstract method', E_USER_ERROR);
 347      }
 348  
 349      function norig()
 350      {
 351          return $this->orig ? count($this->orig) : 0;
 352      }
 353  
 354      function nfinal()
 355      {
 356          return $this->final ? count($this->final) : 0;
 357      }
 358  
 359  }
 360  
 361  /**
 362   * @package Text_Diff
 363   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 364   *
 365   * @access private
 366   */
 367  class Text_Diff_Op_copy extends Text_Diff_Op {
 368  
 369      function Text_Diff_Op_copy($orig, $final = false)
 370      {
 371          if (!is_array($final)) {
 372              $final = $orig;
 373          }
 374          $this->orig = $orig;
 375          $this->final = $final;
 376      }
 377  
 378      function &reverse()
 379      {
 380          $reverse = new Text_Diff_Op_copy($this->final, $this->orig);
 381          return $reverse;
 382      }
 383  
 384  }
 385  
 386  /**
 387   * @package Text_Diff
 388   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 389   *
 390   * @access private
 391   */
 392  class Text_Diff_Op_delete extends Text_Diff_Op {
 393  
 394      function Text_Diff_Op_delete($lines)
 395      {
 396          $this->orig = $lines;
 397          $this->final = false;
 398      }
 399  
 400      function &reverse()
 401      {
 402          $reverse = new Text_Diff_Op_add($this->orig);
 403          return $reverse;
 404      }
 405  
 406  }
 407  
 408  /**
 409   * @package Text_Diff
 410   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 411   *
 412   * @access private
 413   */
 414  class Text_Diff_Op_add extends Text_Diff_Op {
 415  
 416      function Text_Diff_Op_add($lines)
 417      {
 418          $this->final = $lines;
 419          $this->orig = false;
 420      }
 421  
 422      function &reverse()
 423      {
 424          $reverse = new Text_Diff_Op_delete($this->final);
 425          return $reverse;
 426      }
 427  
 428  }
 429  
 430  /**
 431   * @package Text_Diff
 432   * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
 433   *
 434   * @access private
 435   */
 436  class Text_Diff_Op_change extends Text_Diff_Op {
 437  
 438      function Text_Diff_Op_change($orig, $final)
 439      {
 440          $this->orig = $orig;
 441          $this->final = $final;
 442      }
 443  
 444      function &reverse()
 445      {
 446          $reverse = new Text_Diff_Op_change($this->final, $this->orig);
 447          return $reverse;
 448      }
 449  
 450  }


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu