[ Index ]

PHP Cross Reference of Wordpress 2.9.1

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7