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