Text_Diff
[ class tree: Text_Diff ] [ index: Text_Diff ] [ all elements ]

Source for file string.php

Documentation is available at string.php

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

Documentation generated on Fri, 24 Jul 2009 15:00:05 +0000 by phpDocumentor 1.4.2. PEAR Logo Copyright © PHP Group 2004.