Rev Author Line No. Line
4988 kaklik 1 <?php
2 // WebSVN - Subversion repository viewing via the web using PHP
3 // Copyright (C) 2004-2006 Tim Armes
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //
19 // --
20 //
21 // diff_inc.php
22 //
23 // Diff to files
24  
25 if (!defined('USE_AUTOLOADER')) {
26 @include_once 'Horde/String.php';
27 @include_once 'Horde/Text/Diff.php';
28 @include_once 'Horde/Text/Diff/Mapped.php';
29 @include_once 'Horde/Text/Diff/Engine/Native.php';
30 @include_once 'Horde/Text/Diff/Op/Base.php';
31 @include_once 'Horde/Text/Diff/Op/Copy.php';
32 @include_once 'Horde/Text/Diff/Op/Delete.php';
33 @include_once 'Horde/Text/Diff/Op/Add.php';
34 @include_once 'Horde/Text/Diff/Op/Change.php';
35 @include_once 'Horde/Text/Diff/Renderer.php';
36 @include_once 'Horde/Text/Diff/Renderer/Unified.php';
37 }
38 include_once 'include/diff_util.php';
39  
40 $arrayBased = false;
41 $fileBased = false;
42  
43 class ListingHelper {
44 var $_listing = array();
45 var $_index = 0;
46 var $_blockStart = false;
47  
48 function _add($text1, $lineno1, $class1, $text2, $lineno2, $class2) {
49 $listing = &$this->_listing;
50 $index = &$this->_index;
51  
52 $listvar = &$listing[$index];
53 $listvar['rev1diffclass'] = $class1;
54 $listvar['rev2diffclass'] = $class2;
55  
56 $listvar['rev1line'] = $text1;
57 $listvar['rev2line'] = $text2;
58  
59 $listvar['rev1lineno'] = $lineno1;
60 $listvar['rev2lineno'] = $lineno2;
61 $listvar['startblock'] = $this->_blockStart;
62 $this->_blockStart = false;
63 $index++;
64 }
65  
66 function addDeletedLine($text, $lineno) {
67 $this->_add($text, $lineno, 'diffdeleted', '&nbsp;', '-', 'diffempty');
68 }
69  
70 function addAddedLine($text, $lineno) {
71 $this->_add('&nbsp;', '-', 'diffempty', $text, $lineno, 'diffadded');
72 }
73  
74 function addChangedLine($text1, $lineno1, $text2, $lineno2) {
75 $this->_add($text1, $lineno1, 'diffchanged', $text2, $lineno2, 'diffchanged');
76 }
77  
78 // note that $text1 do not need to be equal $text2 if $ignoreWhitespace is true
79 function addLine($text1, $lineno1, $text2, $lineno2) {
80 $this->_add($text1, $lineno1, 'diff', $text2, $lineno2, 'diff');
81 }
82  
83 function startNewBlock() {
84 $this->_blockStart = true;
85 }
86  
87 function getListing() {
88 return $this->_listing;
89 }
90 }
91  
92 function nextLine(&$obj) {
93 global $arrayBased, $fileBased;
94 if ($arrayBased) return array_shift($obj);
95 if ($fileBased) return fgets($obj);
96 return '';
97 }
98  
99 function endOfFile(&$obj) {
100 global $arrayBased, $fileBased;
101 if ($arrayBased) return count($obj) == 0;
102 if ($fileBased) return feof($obj);
103 return true;
104 }
105  
106  
107 function getWrappedLineFromFile($file, $is_highlighted) {
108 $line = fgets($file);
109 if ($line === false) return false;
110 $line = toOutputEncoding($line);
111 if (!$is_highlighted) {
112 $line = escape($line);
113 }
114 $line = rtrim($line, "\n\r");
115 if (strip_tags($line) === '') $line = '&nbsp;';
116 return wrapInCodeTagIfNecessary($line);
117 }
118  
119 function diff_result($all, $highlighted, $newtname, $oldtname, $obj, $ignoreWhitespace) {
120 $ofile = fopen($oldtname, 'r');
121 $nfile = fopen($newtname, 'r');
122  
123 // Get the first real line
124 $line = nextLine($obj);
125  
126 $index = 0;
127 $listingHelper = new ListingHelper();
128  
129 $curoline = 1;
130 $curnline = 1;
131  
132 $sensibleLineChanges = new SensibleLineChanges(new LineDiff($ignoreWhitespace));
133  
134 while (!endOfFile($obj)) {
135 // Get the first line of this range
136 $oline = 0;
137 sscanf($line, '@@ -%d', $oline);
138 $line = substr($line, strpos($line, '+'));
139 $nline = 0;
140 sscanf($line, '+%d', $nline);
141  
142 while ($curoline < $oline || $curnline < $nline) {
143 if ($curoline < $oline) {
144 $text1 = getWrappedLineFromFile($ofile, $highlighted);
145 $tmpoline = $curoline;
146 $curoline++;
147 } else {
148 $tmpoline = '?';
149 $text1 = '&nbsp';
150 }
151  
152 if ($curnline < $nline) {
153 $text2 = getWrappedLineFromFile($nfile, $highlighted);
154 $tmpnline = $curnline;
155 $curnline++;
156 } else {
157 $tmpnline = '?';
158 $text2 = '&nbsp;';
159 }
160  
161 if ($all) {
162 $listingHelper->addLine($text1, $tmpoline, $text2, $tmpnline);
163 }
164 }
165  
166 if (!$all && $line !== false) {
167 $listingHelper->startNewBlock();
168 }
169  
170 $fin = false;
171 while (!endOfFile($obj) && !$fin) {
172 $line = nextLine($obj);
173 if ($line === false || $line === '' || strncmp($line, '@@', 2) == 0) {
174 $sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
175 $fin = true;
176 } else {
177 $mod = $line[0];
178 $line = substr($line, 1);
179  
180 switch ($mod) {
181 case '-':
182 $text = getWrappedLineFromFile($ofile, $highlighted);
183 $sensibleLineChanges->addDeletedLine($line, $text, $curoline);
184 $curoline++;
185 break;
186  
187 case '+':
188 $text = getWrappedLineFromFile($nfile, $highlighted);
189 $sensibleLineChanges->addAddedLine($line, $text, $curnline);
190 $curnline++;
191 break;
192  
193 default:
194 $sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
195  
196 $text1 = getWrappedLineFromFile($ofile, $highlighted);
197 $text2 = getWrappedLineFromFile($nfile, $highlighted);
198 $listingHelper->addLine($text1, $curoline, $text2, $curnline);
199  
200 $curoline++;
201 $curnline++;
202  
203 break;
204 }
205 }
206  
207 if (!$fin) {
208 $index++;
209 }
210 }
211 }
212 $sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
213  
214 // Output the rest of the files
215 if ($all) {
216 while (!feof($ofile) || !feof($nfile)) {
217 $noneof = false;
218  
219 $text1 = getWrappedLineFromFile($ofile, $highlighted);
220 if ($text1 !== false) {
221 $tmpoline = $curoline;
222 $curoline++;
223 $noneof = true;
224 } else {
225 $tmpoline = '-';
226 $text1 = '&nbsp;';
227 }
228  
229  
230 $text2 = getWrappedLineFromFile($nfile, $highlighted);
231 if ($text2 !== false) {
232 $tmpnline = $curnline;
233 $curnline++;
234 $noneof = true;
235 } else {
236 $tmpnline = '-';
237 $text2 = '&nbsp;';
238 }
239  
240 if ($noneof) {
241 $listingHelper->addLine($text1, $tmpoline, $text2, $tmpnline);
242 }
243  
244 }
245 }
246  
247 fclose($ofile);
248 fclose($nfile);
249  
250 return $listingHelper->getListing();
251 }
252  
253 function command_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
254 global $config, $lang, $arrayBased, $fileBased;
255  
256 $context = 5;
257  
258 if ($all) {
259 // Setting the context to 0 makes diff generate the wrong line numbers!
260 $context = 1;
261 }
262  
263 if ($ignoreWhitespace) {
264 $whitespaceFlag = ' -w';
265 } else {
266 $whitespaceFlag = '';
267 }
268  
269 // Open a pipe to the diff command with $context lines of context:
270 $cmd = $config->diff.$whitespaceFlag.' -U '.$context.' "'.$oldtname.'" "'.$newtname.'"';
271 $diff = runCommand($cmd, true);
272  
273 // Ignore the 3 header lines:
274 $line = array_shift($diff);
275 $line = array_shift($diff);
276  
277 $arrayBased = true;
278 $fileBased = false;
279  
280 if ($highlighted) {
281 $listing = diff_result($all, $highlighted, $newhlname, $oldhlname, $diff, $ignoreWhitespace);
282 } else {
283 $listing = diff_result($all, $highlighted, $newtname, $oldtname, $diff, $ignoreWhitespace);
284 }
285  
286 return $listing;
287 }
288  
289 function inline_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
290 global $arrayBased, $fileBased;
291  
292 $context = 5;
293 if ($all) {
294 // Setting the context to 0 makes diff generate the wrong line numbers!
295 $context = 1;
296 }
297  
298 // modify error reporting level to suppress deprecated/strict warning "Assigning the return value of new by reference"
299 $bckLevel = error_reporting();
300 $removeLevel = E_DEPRECATED;
301 $modLevel = $bckLevel & (~$removeLevel);
302 error_reporting($modLevel);
303  
304 // Create the diff class
305 $fromLines = file($oldtname);
306 $toLines = file($newtname);
307 if (!$ignoreWhitespace) {
308 $diff = new Horde_Text_Diff('Native', array($fromLines, $toLines));
309 } else {
310 $whitespaces = array(' ', "\t", "\n", "\r");
311 $mappedFromLines = array();
312 foreach ($fromLines as $k => $line) {
313 $line = rtrim($line, "\n\r");
314 $fromLines[$k] = $line;
315 $mappedFromLines[] = str_replace($whitespaces, array(), $line);
316 }
317 $mappedToLines = array();
318 foreach ($toLines as $k => $line) {
319 $line = rtrim($line, "\n\r");
320 $toLines[$k] = $line;
321 $mappedToLines[] = str_replace($whitespaces, array(), $line);
322 }
323 $diff = new Horde_Text_Diff_Mapped('Native', array($fromLines, $toLines, $mappedFromLines, $mappedToLines));
324 }
325 $renderer = new Horde_Text_Diff_Renderer_Unified(array('leading_context_lines' => $context, 'trailing_context_lines' => $context));
326 $rendered = explode("\n", $renderer->render($diff));
327  
328 // restore previous error reporting level
329 error_reporting($bckLevel);
330  
331 $arrayBased = true;
332 $fileBased = false;
333 if ($highlighted) {
334 $listing = diff_result($all, $highlighted, $newhlname, $oldhlname, $rendered, $ignoreWhitespace);
335 } else {
336 $listing = diff_result($all, $highlighted, $newtname, $oldtname, $rendered, $ignoreWhitespace);
337 }
338  
339 return $listing;
340 }
341  
342 function do_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
343 if ((!$ignoreWhitespace ? class_exists('Horde_Text_Diff') : class_exists('Horde_Text_Diff_Mapped'))
344 && class_exists('Horde_Text_Diff_Renderer_Unified')) {
345 return inline_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname);
346 } else {
347 return command_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname);
348 }
349 }