jablonka.czprosek.czf

websvn

Subversion Repositories:
[/] [lib/] [pear/] [Text/] [Diff/] [Engine/] [string.php] - Blame information for rev 6

 

Line No. Rev Author Line
15simandl<?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.5 2008/09/10 08:31:58 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 */
25class 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 || $unified === 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, if there is one.
59 $diff = explode("\n", $diff);
60 if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
61 ($mode == 'unified' && strpos($diff[0], '---') === 0)) {
62 array_shift($diff);
63 array_shift($diff);
64 }
65 
66 if ($mode == 'context') {
67 return $this->parseContextDiff($diff);
68 } else {
69 return $this->parseUnifiedDiff($diff);
70 }
71 }
72 
73 /**
74 * Parses an array containing the unified diff.
75 *
76 * @param array $diff Array of lines.
77 *
78 * @return array List of all diff operations.
79 */
80 function parseUnifiedDiff($diff)
81 {
82 $edits = array();
83 $end = count($diff) - 1;
84 for ($i = 0; $i < $end;) {
85 $diff1 = array();
86 switch (substr($diff[$i], 0, 1)) {
87 case ' ':
88 do {
89 $diff1[] = substr($diff[$i], 1);
90 } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
91 $edits[] = new Text_Diff_Op_copy($diff1);
92 break;
93 
94 case '+':
95 // get all new lines
96 do {
97 $diff1[] = substr($diff[$i], 1);
98 } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
99 $edits[] = new Text_Diff_Op_add($diff1);
100 break;
101 
102 case '-':
103 // get changed or removed lines
104 $diff2 = array();
105 do {
106 $diff1[] = substr($diff[$i], 1);
107 } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
108 
109 while ($i < $end && substr($diff[$i], 0, 1) == '+') {
110 $diff2[] = substr($diff[$i++], 1);
111 }
112 if (count($diff2) == 0) {
113 $edits[] = new Text_Diff_Op_delete($diff1);
114 } else {
115 $edits[] = new Text_Diff_Op_change($diff1, $diff2);
116 }
117 break;
118 
119 default:
120 $i++;
121 break;
122 }
123 }
124 
125 return $edits;
126 }
127 
128 /**
129 * Parses an array containing the context diff.
130 *
131 * @param array $diff Array of lines.
132 *
133 * @return array List of all diff operations.
134 */
135 function parseContextDiff(&$diff)
136 {
137 $edits = array();
138 $i = $max_i = $j = $max_j = 0;
139 $end = count($diff) - 1;
140 while ($i < $end && $j < $end) {
141 while ($i >= $max_i && $j >= $max_j) {
142 // Find the boundaries of the diff output of the two files
143 for ($i = $j;
144 $i < $end && substr($diff[$i], 0, 3) == '***';
145 $i++);
146 for ($max_i = $i;
147 $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
148 $max_i++);
149 for ($j = $max_i;
150 $j < $end && substr($diff[$j], 0, 3) == '---';
151 $j++);
152 for ($max_j = $j;
153 $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
154 $max_j++);
155 }
156 
157 // find what hasn't been changed
158 $array = array();
159 while ($i < $max_i &&
160 $j < $max_j &&
161 strcmp($diff[$i], $diff[$j]) == 0) {
162 $array[] = substr($diff[$i], 2);
163 $i++;
164 $j++;
165 }
166 
167 while ($i < $max_i && ($max_j-$j) <= 1) {
168 if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
169 break;
170 }
171 $array[] = substr($diff[$i++], 2);
172 }
173 
174 while ($j < $max_j && ($max_i-$i) <= 1) {
175 if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
176 break;
177 }
178 $array[] = substr($diff[$j++], 2);
179 }
180 if (count($array) > 0) {
181 $edits[] = new Text_Diff_Op_copy($array);
182 }
183 
184 if ($i < $max_i) {
185 $diff1 = array();
186 switch (substr($diff[$i], 0, 1)) {
187 case '!':
188 $diff2 = array();
189 do {
190 $diff1[] = substr($diff[$i], 2);
191 if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
192 $diff2[] = substr($diff[$j++], 2);
193 }
194 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
195 $edits[] = new Text_Diff_Op_change($diff1, $diff2);
196 break;
197 
198 case '+':
199 do {
200 $diff1[] = substr($diff[$i], 2);
201 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
202 $edits[] = new Text_Diff_Op_add($diff1);
203 break;
204 
205 case '-':
206 do {
207 $diff1[] = substr($diff[$i], 2);
208 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
209 $edits[] = new Text_Diff_Op_delete($diff1);
210 break;
211 }
212 }
213 
214 if ($j < $max_j) {
215 $diff2 = array();
216 switch (substr($diff[$j], 0, 1)) {
217 case '+':
218 do {
219 $diff2[] = substr($diff[$j++], 2);
220 } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
221 $edits[] = new Text_Diff_Op_add($diff2);
222 break;
223 
224 case '-':
225 do {
226 $diff2[] = substr($diff[$j++], 2);
227 } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
228 $edits[] = new Text_Diff_Op_delete($diff2);
229 break;
230 }
231 }
232 }
233 
234 return $edits;
235 }
236 
237}

Powered by WebSVN 2.2.1