[ Index ]

PHP Cross Reference of WordPress

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


Generated: Thu Nov 21 01:00:03 2024 Cross-referenced by PHPXref 0.7.1