[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Parses unified or context diffs output from eg. the diff utility.
   4   *
   5   * Example:
   6   * <code>
   7   * $patch = file_get_contents('example.patch');
   8   * $diff = new Text_Diff('string', array($patch));
   9   * $renderer = new Text_Diff_Renderer_inline();
  10   * echo $renderer->render($diff);
  11   * </code>
  12   *
  13   * $Horde: framework/Text_Diff/Diff/Engine/string.php,v 1.7 2008/01/04 10:07:50 jan Exp $
  14   *
  15   * Copyright 2005 Örjan Persson <o@42mm.org>
  16   * Copyright 2005-2008 The Horde Project (http://www.horde.org/)
  17   *
  18   * See the enclosed file COPYING for license information (LGPL). If you did
  19   * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
  20   *
  21   * @author  Örjan Persson <o@42mm.org>
  22   * @package Text_Diff
  23   * @since   0.2.0
  24   */
  25  class Text_Diff_Engine_string {
  26  
  27      /**
  28       * Parses a unified or context diff.
  29       *
  30       * First param contains the whole diff and the second can be used to force
  31       * a specific diff type. If the second parameter is 'autodetect', the
  32       * diff will be examined to find out which type of diff this is.
  33       *
  34       * @param string $diff  The diff content.
  35       * @param string $mode  The diff mode of the content in $diff. One of
  36       *                      'context', 'unified', or 'autodetect'.
  37       *
  38       * @return array  List of all diff operations.
  39       */
  40      function diff($diff, $mode = 'autodetect')
  41      {
  42          if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
  43              return PEAR::raiseError('Type of diff is unsupported');
  44          }
  45  
  46          if ($mode == 'autodetect') {
  47              $context = strpos($diff, '***');
  48              $unified = strpos($diff, '---');
  49              if ($context === $unified) {
  50                  return PEAR::raiseError('Type of diff could not be detected');
  51              } elseif ($context === false || $context === false) {
  52                  $mode = $context !== false ? 'context' : 'unified';
  53              } else {
  54                  $mode = $context < $unified ? 'context' : 'unified';
  55              }
  56          }
  57  
  58          // split by new line and remove the diff header
  59          $diff = explode("\n", $diff);
  60          array_shift($diff);
  61          array_shift($diff);
  62  
  63          if ($mode == 'context') {
  64              return $this->parseContextDiff($diff);
  65          } else {
  66              return $this->parseUnifiedDiff($diff);
  67          }
  68      }
  69  
  70      /**
  71       * Parses an array containing the unified diff.
  72       *
  73       * @param array $diff  Array of lines.
  74       *
  75       * @return array  List of all diff operations.
  76       */
  77      function parseUnifiedDiff($diff)
  78      {
  79          $edits = array();
  80          $end = count($diff) - 1;
  81          for ($i = 0; $i < $end;) {
  82              $diff1 = array();
  83              switch (substr($diff[$i], 0, 1)) {
  84              case ' ':
  85                  do {
  86                      $diff1[] = substr($diff[$i], 1);
  87                  } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
  88                  $edits[] = &new Text_Diff_Op_copy($diff1);
  89                  break;
  90  
  91              case '+':
  92                  // get all new lines
  93                  do {
  94                      $diff1[] = substr($diff[$i], 1);
  95                  } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
  96                  $edits[] = &new Text_Diff_Op_add($diff1);
  97                  break;
  98  
  99              case '-':
 100                  // get changed or removed lines
 101                  $diff2 = array();
 102                  do {
 103                      $diff1[] = substr($diff[$i], 1);
 104                  } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
 105  
 106                  while ($i < $end && substr($diff[$i], 0, 1) == '+') {
 107                      $diff2[] = substr($diff[$i++], 1);
 108                  }
 109                  if (count($diff2) == 0) {
 110                      $edits[] = &new Text_Diff_Op_delete($diff1);
 111                  } else {
 112                      $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
 113                  }
 114                  break;
 115  
 116              default:
 117                  $i++;
 118                  break;
 119              }
 120          }
 121  
 122          return $edits;
 123      }
 124  
 125      /**
 126       * Parses an array containing the context diff.
 127       *
 128       * @param array $diff  Array of lines.
 129       *
 130       * @return array  List of all diff operations.
 131       */
 132      function parseContextDiff(&$diff)
 133      {
 134          $edits = array();
 135          $i = $max_i = $j = $max_j = 0;
 136          $end = count($diff) - 1;
 137          while ($i < $end && $j < $end) {
 138              while ($i >= $max_i && $j >= $max_j) {
 139                  // Find the boundaries of the diff output of the two files
 140                  for ($i = $j;
 141                       $i < $end && substr($diff[$i], 0, 3) == '***';
 142                       $i++);
 143                  for ($max_i = $i;
 144                       $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
 145                       $max_i++);
 146                  for ($j = $max_i;
 147                       $j < $end && substr($diff[$j], 0, 3) == '---';
 148                       $j++);
 149                  for ($max_j = $j;
 150                       $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
 151                       $max_j++);
 152              }
 153  
 154              // find what hasn't been changed
 155              $array = array();
 156              while ($i < $max_i &&
 157                     $j < $max_j &&
 158                     strcmp($diff[$i], $diff[$j]) == 0) {
 159                  $array[] = substr($diff[$i], 2);
 160                  $i++;
 161                  $j++;
 162              }
 163  
 164              while ($i < $max_i && ($max_j-$j) <= 1) {
 165                  if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
 166                      break;
 167                  }
 168                  $array[] = substr($diff[$i++], 2);
 169              }
 170  
 171              while ($j < $max_j && ($max_i-$i) <= 1) {
 172                  if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
 173                      break;
 174                  }
 175                  $array[] = substr($diff[$j++], 2);
 176              }
 177              if (count($array) > 0) {
 178                  $edits[] = &new Text_Diff_Op_copy($array);
 179              }
 180  
 181              if ($i < $max_i) {
 182                  $diff1 = array();
 183                  switch (substr($diff[$i], 0, 1)) {
 184                  case '!':
 185                      $diff2 = array();
 186                      do {
 187                          $diff1[] = substr($diff[$i], 2);
 188                          if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
 189                              $diff2[] = substr($diff[$j++], 2);
 190                          }
 191                      } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
 192                      $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
 193                      break;
 194  
 195                  case '+':
 196                      do {
 197                          $diff1[] = substr($diff[$i], 2);
 198                      } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
 199                      $edits[] = &new Text_Diff_Op_add($diff1);
 200                      break;
 201  
 202                  case '-':
 203                      do {
 204                          $diff1[] = substr($diff[$i], 2);
 205                      } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
 206                      $edits[] = &new Text_Diff_Op_delete($diff1);
 207                      break;
 208                  }
 209              }
 210  
 211              if ($j < $max_j) {
 212                  $diff2 = array();
 213                  switch (substr($diff[$j], 0, 1)) {
 214                  case '+':
 215                      do {
 216                          $diff2[] = substr($diff[$j++], 2);
 217                      } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
 218                      $edits[] = &new Text_Diff_Op_add($diff2);
 219                      break;
 220  
 221                  case '-':
 222                      do {
 223                          $diff2[] = substr($diff[$j++], 2);
 224                      } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
 225                      $edits[] = &new Text_Diff_Op_delete($diff2);
 226                      break;
 227                  }
 228              }
 229          }
 230  
 231          return $edits;
 232      }
 233  
 234  }


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