home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / Text / Diff / Engine / string.php < prev    next >
Encoding:
PHP Script  |  2015-10-24  |  8.2 KB  |  249 lines

  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. }
  249.