443
by dcoles
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0 |
1 |
<?php
|
2 |
/**
|
|
3 |
*
|
|
4 |
* @package diff
|
|
5 |
* @version $Id: renderer.php,v 1.8 2007/10/05 14:36:33 acydburn Exp $
|
|
6 |
* @copyright (c) 2006 phpBB Group
|
|
7 |
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
|
8 |
*
|
|
9 |
*/
|
|
10 |
||
11 |
/**
|
|
12 |
* @ignore
|
|
13 |
*/
|
|
14 |
if (!defined('IN_PHPBB')) |
|
15 |
{
|
|
16 |
exit; |
|
17 |
}
|
|
18 |
||
19 |
/**
|
|
20 |
* Code from pear.php.net, Text_Diff-0.2.1 (beta) package
|
|
21 |
* http://pear.php.net/package/Text_Diff/
|
|
22 |
*
|
|
23 |
* Modified by phpBB Group to meet our coding standards
|
|
24 |
* and being able to integrate into phpBB
|
|
25 |
*
|
|
26 |
* A class to render Diffs in different formats.
|
|
27 |
*
|
|
28 |
* This class renders the diff in classic diff format. It is intended that
|
|
29 |
* this class be customized via inheritance, to obtain fancier outputs.
|
|
30 |
*
|
|
31 |
* @package diff
|
|
32 |
*/
|
|
33 |
class diff_renderer |
|
34 |
{
|
|
35 |
/**
|
|
36 |
* Number of leading context "lines" to preserve.
|
|
37 |
*
|
|
38 |
* This should be left at zero for this class, but subclasses may want to
|
|
39 |
* set this to other values.
|
|
40 |
*/
|
|
41 |
var $_leading_context_lines = 0; |
|
42 |
||
43 |
/**
|
|
44 |
* Number of trailing context "lines" to preserve.
|
|
45 |
*
|
|
46 |
* This should be left at zero for this class, but subclasses may want to
|
|
47 |
* set this to other values.
|
|
48 |
*/
|
|
49 |
var $_trailing_context_lines = 0; |
|
50 |
||
51 |
/**
|
|
52 |
* Constructor.
|
|
53 |
*/
|
|
54 |
function diff_renderer($params = array()) |
|
55 |
{
|
|
56 |
foreach ($params as $param => $value) |
|
57 |
{
|
|
58 |
$v = '_' . $param; |
|
59 |
if (isset($this->$v)) |
|
60 |
{
|
|
61 |
$this->$v = $value; |
|
62 |
}
|
|
63 |
}
|
|
64 |
}
|
|
65 |
||
66 |
/**
|
|
67 |
* Get any renderer parameters.
|
|
68 |
*
|
|
69 |
* @return array All parameters of this renderer object.
|
|
70 |
*/
|
|
71 |
function get_params() |
|
72 |
{
|
|
73 |
$params = array(); |
|
74 |
foreach (get_object_vars($this) as $k => $v) |
|
75 |
{
|
|
76 |
if ($k[0] == '_') |
|
77 |
{
|
|
78 |
$params[substr($k, 1)] = $v; |
|
79 |
}
|
|
80 |
}
|
|
81 |
||
82 |
return $params; |
|
83 |
}
|
|
84 |
||
85 |
/**
|
|
86 |
* Renders a diff.
|
|
87 |
*
|
|
88 |
* @param diff &$diff A diff object.
|
|
89 |
*
|
|
90 |
* @return string The formatted output.
|
|
91 |
*/
|
|
92 |
function render(&$diff) |
|
93 |
{
|
|
94 |
$xi = $yi = 1; |
|
95 |
$block = false; |
|
96 |
$context = array(); |
|
97 |
||
98 |
// Create a new diff object if it is a 3-way diff
|
|
99 |
if (is_a($diff, 'diff3')) |
|
100 |
{
|
|
101 |
$diff3 = &$diff; |
|
102 |
||
103 |
$diff_1 = $diff3->get_original(); |
|
104 |
$diff_2 = $diff3->merged_output(); |
|
105 |
||
106 |
unset($diff3); |
|
107 |
||
108 |
$diff = &new diff($diff_1, $diff_2); |
|
109 |
}
|
|
110 |
||
111 |
$nlead = $this->_leading_context_lines; |
|
112 |
$ntrail = $this->_trailing_context_lines; |
|
113 |
||
114 |
$output = $this->_start_diff(); |
|
115 |
$diffs = $diff->get_diff(); |
|
116 |
||
117 |
foreach ($diffs as $i => $edit) |
|
118 |
{
|
|
119 |
if (is_a($edit, 'diff_op_copy')) |
|
120 |
{
|
|
121 |
if (is_array($block)) |
|
122 |
{
|
|
123 |
$keep = ($i == sizeof($diffs) - 1) ? $ntrail : $nlead + $ntrail; |
|
124 |
if (sizeof($edit->orig) <= $keep) |
|
125 |
{
|
|
126 |
$block[] = $edit; |
|
127 |
}
|
|
128 |
else
|
|
129 |
{
|
|
130 |
if ($ntrail) |
|
131 |
{
|
|
132 |
$context = array_slice($edit->orig, 0, $ntrail); |
|
133 |
$block[] = &new diff_op_copy($context); |
|
134 |
}
|
|
135 |
||
136 |
$output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block); |
|
137 |
$block = false; |
|
138 |
}
|
|
139 |
}
|
|
140 |
$context = $edit->orig; |
|
141 |
}
|
|
142 |
else
|
|
143 |
{
|
|
144 |
if (!is_array($block)) |
|
145 |
{
|
|
146 |
$context = array_slice($context, sizeof($context) - $nlead); |
|
147 |
$x0 = $xi - sizeof($context); |
|
148 |
$y0 = $yi - sizeof($context); |
|
149 |
$block = array(); |
|
150 |
||
151 |
if ($context) |
|
152 |
{
|
|
153 |
$block[] = &new diff_op_copy($context); |
|
154 |
}
|
|
155 |
}
|
|
156 |
$block[] = $edit; |
|
157 |
}
|
|
158 |
||
159 |
$xi += ($edit->orig) ? sizeof($edit->orig) : 0; |
|
160 |
$yi += ($edit->final) ? sizeof($edit->final) : 0; |
|
161 |
}
|
|
162 |
||
163 |
if (is_array($block)) |
|
164 |
{
|
|
165 |
$output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block); |
|
166 |
}
|
|
167 |
||
168 |
return $output . $this->_end_diff(); |
|
169 |
}
|
|
170 |
||
171 |
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) |
|
172 |
{
|
|
173 |
$output = $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen)); |
|
174 |
||
175 |
foreach ($edits as $edit) |
|
176 |
{
|
|
177 |
switch (get_class($edit)) |
|
178 |
{
|
|
179 |
case 'diff_op_copy': |
|
180 |
$output .= $this->_context($edit->orig); |
|
181 |
break; |
|
182 |
||
183 |
case 'diff_op_add': |
|
184 |
$output .= $this->_added($edit->final); |
|
185 |
break; |
|
186 |
||
187 |
case 'diff_op_delete': |
|
188 |
$output .= $this->_deleted($edit->orig); |
|
189 |
break; |
|
190 |
||
191 |
case 'diff_op_change': |
|
192 |
$output .= $this->_changed($edit->orig, $edit->final); |
|
193 |
break; |
|
194 |
}
|
|
195 |
}
|
|
196 |
||
197 |
return $output . $this->_end_block(); |
|
198 |
}
|
|
199 |
||
200 |
function _start_diff() |
|
201 |
{
|
|
202 |
return ''; |
|
203 |
}
|
|
204 |
||
205 |
function _end_diff() |
|
206 |
{
|
|
207 |
return ''; |
|
208 |
}
|
|
209 |
||
210 |
function _block_header($xbeg, $xlen, $ybeg, $ylen) |
|
211 |
{
|
|
212 |
if ($xlen > 1) |
|
213 |
{
|
|
214 |
$xbeg .= ',' . ($xbeg + $xlen - 1); |
|
215 |
}
|
|
216 |
||
217 |
if ($ylen > 1) |
|
218 |
{
|
|
219 |
$ybeg .= ',' . ($ybeg + $ylen - 1); |
|
220 |
}
|
|
221 |
||
222 |
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; |
|
223 |
}
|
|
224 |
||
225 |
function _start_block($header) |
|
226 |
{
|
|
227 |
return $header . "\n"; |
|
228 |
}
|
|
229 |
||
230 |
function _end_block() |
|
231 |
{
|
|
232 |
return ''; |
|
233 |
}
|
|
234 |
||
235 |
function _lines($lines, $prefix = ' ') |
|
236 |
{
|
|
237 |
return $prefix . implode("\n$prefix", $lines) . "\n"; |
|
238 |
}
|
|
239 |
||
240 |
function _context($lines) |
|
241 |
{
|
|
242 |
return $this->_lines($lines, ' '); |
|
243 |
}
|
|
244 |
||
245 |
function _added($lines) |
|
246 |
{
|
|
247 |
return $this->_lines($lines, '> '); |
|
248 |
}
|
|
249 |
||
250 |
function _deleted($lines) |
|
251 |
{
|
|
252 |
return $this->_lines($lines, '< '); |
|
253 |
}
|
|
254 |
||
255 |
function _changed($orig, $final) |
|
256 |
{
|
|
257 |
return $this->_deleted($orig) . "---\n" . $this->_added($final); |
|
258 |
}
|
|
259 |
||
260 |
/**
|
|
261 |
* Our function to get the diff
|
|
262 |
*/
|
|
263 |
function get_diff_content($diff) |
|
264 |
{
|
|
265 |
return $this->render($diff); |
|
266 |
}
|
|
267 |
}
|
|
268 |
||
269 |
/**
|
|
270 |
* Renders a unified diff
|
|
271 |
* @package diff
|
|
272 |
*/
|
|
273 |
class diff_renderer_unified extends diff_renderer |
|
274 |
{
|
|
275 |
var $_leading_context_lines = 4; |
|
276 |
var $_trailing_context_lines = 4; |
|
277 |
||
278 |
/**
|
|
279 |
* Our function to get the diff
|
|
280 |
*/
|
|
281 |
function get_diff_content($diff) |
|
282 |
{
|
|
283 |
return nl2br($this->render($diff)); |
|
284 |
}
|
|
285 |
||
286 |
function _block_header($xbeg, $xlen, $ybeg, $ylen) |
|
287 |
{
|
|
288 |
if ($xlen != 1) |
|
289 |
{
|
|
290 |
$xbeg .= ',' . $xlen; |
|
291 |
}
|
|
292 |
||
293 |
if ($ylen != 1) |
|
294 |
{
|
|
295 |
$ybeg .= ',' . $ylen; |
|
296 |
}
|
|
297 |
return '<div class="diff"><big class="info">@@ -' . $xbeg . ' +' . $ybeg . ' @@</big></div>'; |
|
298 |
}
|
|
299 |
||
300 |
function _context($lines) |
|
301 |
{
|
|
302 |
return '<pre class="diff context">' . htmlspecialchars($this->_lines($lines, ' ')) . '<br /></pre>'; |
|
303 |
}
|
|
304 |
||
305 |
function _added($lines) |
|
306 |
{
|
|
307 |
return '<pre class="diff added">' . htmlspecialchars($this->_lines($lines, '+')) . '<br /></pre>'; |
|
308 |
}
|
|
309 |
||
310 |
function _deleted($lines) |
|
311 |
{
|
|
312 |
return '<pre class="diff removed">' . htmlspecialchars($this->_lines($lines, '-')) . '<br /></pre>'; |
|
313 |
}
|
|
314 |
||
315 |
function _changed($orig, $final) |
|
316 |
{
|
|
317 |
return $this->_deleted($orig) . $this->_added($final); |
|
318 |
}
|
|
319 |
||
320 |
function _start_diff() |
|
321 |
{
|
|
322 |
$start = '<div class="file">'; |
|
323 |
||
324 |
return $start; |
|
325 |
}
|
|
326 |
||
327 |
function _end_diff() |
|
328 |
{
|
|
329 |
return '</div>'; |
|
330 |
}
|
|
331 |
||
332 |
function _end_block() |
|
333 |
{
|
|
334 |
return ''; |
|
335 |
}
|
|
336 |
}
|
|
337 |
||
338 |
/**
|
|
339 |
* "Inline" diff renderer.
|
|
340 |
*
|
|
341 |
* This class renders diffs in the Wiki-style "inline" format.
|
|
342 |
*
|
|
343 |
* @author Ciprian Popovici
|
|
344 |
* @package diff
|
|
345 |
*/
|
|
346 |
class diff_renderer_inline extends diff_renderer |
|
347 |
{
|
|
348 |
var $_leading_context_lines = 10000; |
|
349 |
var $_trailing_context_lines = 10000; |
|
350 |
||
351 |
// Prefix and suffix for inserted text
|
|
352 |
var $_ins_prefix = '<span class="ins">'; |
|
353 |
var $_ins_suffix = '</span>'; |
|
354 |
||
355 |
// Prefix and suffix for deleted text
|
|
356 |
var $_del_prefix = '<span class="del">'; |
|
357 |
var $_del_suffix = '</span>'; |
|
358 |
||
359 |
var $_block_head = ''; |
|
360 |
||
361 |
// What are we currently splitting on? Used to recurse to show word-level
|
|
362 |
var $_split_level = 'lines'; |
|
363 |
||
364 |
/**
|
|
365 |
* Our function to get the diff
|
|
366 |
*/
|
|
367 |
function get_diff_content($diff) |
|
368 |
{
|
|
369 |
return '<pre>' . nl2br($this->render($diff)) . '<br /></pre>'; |
|
370 |
}
|
|
371 |
||
372 |
function _start_diff() |
|
373 |
{
|
|
374 |
return ''; |
|
375 |
}
|
|
376 |
||
377 |
function _end_diff() |
|
378 |
{
|
|
379 |
return ''; |
|
380 |
}
|
|
381 |
||
382 |
function _block_header($xbeg, $xlen, $ybeg, $ylen) |
|
383 |
{
|
|
384 |
return $this->_block_head; |
|
385 |
}
|
|
386 |
||
387 |
function _start_block($header) |
|
388 |
{
|
|
389 |
return $header; |
|
390 |
}
|
|
391 |
||
392 |
function _lines($lines, $prefix = ' ', $encode = true) |
|
393 |
{
|
|
394 |
if ($encode) |
|
395 |
{
|
|
396 |
array_walk($lines, array(&$this, '_encode')); |
|
397 |
}
|
|
398 |
||
399 |
if ($this->_split_level == 'words') |
|
400 |
{
|
|
401 |
return implode('', $lines); |
|
402 |
}
|
|
403 |
else
|
|
404 |
{
|
|
405 |
return implode("\n", $lines) . "\n"; |
|
406 |
}
|
|
407 |
}
|
|
408 |
||
409 |
function _added($lines) |
|
410 |
{
|
|
411 |
array_walk($lines, array(&$this, '_encode')); |
|
412 |
$lines[0] = $this->_ins_prefix . $lines[0]; |
|
413 |
$lines[sizeof($lines) - 1] .= $this->_ins_suffix; |
|
414 |
return $this->_lines($lines, ' ', false); |
|
415 |
}
|
|
416 |
||
417 |
function _deleted($lines, $words = false) |
|
418 |
{
|
|
419 |
array_walk($lines, array(&$this, '_encode')); |
|
420 |
$lines[0] = $this->_del_prefix . $lines[0]; |
|
421 |
$lines[sizeof($lines) - 1] .= $this->_del_suffix; |
|
422 |
return $this->_lines($lines, ' ', false); |
|
423 |
}
|
|
424 |
||
425 |
function _changed($orig, $final) |
|
426 |
{
|
|
427 |
// If we've already split on words, don't try to do so again - just display.
|
|
428 |
if ($this->_split_level == 'words') |
|
429 |
{
|
|
430 |
$prefix = ''; |
|
431 |
while ($orig[0] !== false && $final[0] !== false && substr($orig[0], 0, 1) == ' ' && substr($final[0], 0, 1) == ' ') |
|
432 |
{
|
|
433 |
$prefix .= substr($orig[0], 0, 1); |
|
434 |
$orig[0] = substr($orig[0], 1); |
|
435 |
$final[0] = substr($final[0], 1); |
|
436 |
}
|
|
437 |
||
438 |
return $prefix . $this->_deleted($orig) . $this->_added($final); |
|
439 |
}
|
|
440 |
||
441 |
$text1 = implode("\n", $orig); |
|
442 |
$text2 = implode("\n", $final); |
|
443 |
||
444 |
// Non-printing newline marker.
|
|
445 |
$nl = "\0"; |
|
446 |
||
447 |
// We want to split on word boundaries, but we need to preserve whitespace as well.
|
|
448 |
// Therefore we split on words, but include all blocks of whitespace in the wordlist.
|
|
449 |
$splitted_text_1 = $this->_split_on_words($text1, $nl); |
|
450 |
$splitted_text_2 = $this->_split_on_words($text2, $nl); |
|
451 |
||
452 |
$diff = &new diff($splitted_text_1, $splitted_text_2); |
|
453 |
unset($splitted_text_1, $splitted_text_2); |
|
454 |
||
455 |
// Get the diff in inline format.
|
|
456 |
$renderer = &new diff_renderer_inline(array_merge($this->get_params(), array('split_level' => 'words'))); |
|
457 |
||
458 |
// Run the diff and get the output.
|
|
459 |
return str_replace($nl, "\n", $renderer->render($diff)) . "\n"; |
|
460 |
}
|
|
461 |
||
462 |
function _split_on_words($string, $newline_escape = "\n") |
|
463 |
{
|
|
464 |
// Ignore \0; otherwise the while loop will never finish.
|
|
465 |
$string = str_replace("\0", '', $string); |
|
466 |
||
467 |
$words = array(); |
|
468 |
$length = strlen($string); |
|
469 |
$pos = 0; |
|
470 |
||
471 |
$tab_there = true; |
|
472 |
while ($pos < $length) |
|
473 |
{
|
|
474 |
// Check for tabs... do not include them
|
|
475 |
if ($tab_there && substr($string, $pos, 1) === "\t") |
|
476 |
{
|
|
477 |
$words[] = "\t"; |
|
478 |
$pos++; |
|
479 |
||
480 |
continue; |
|
481 |
}
|
|
482 |
else
|
|
483 |
{
|
|
484 |
$tab_there = false; |
|
485 |
}
|
|
486 |
||
487 |
// Eat a word with any preceding whitespace.
|
|
488 |
$spaces = strspn(substr($string, $pos), " \n"); |
|
489 |
$nextpos = strcspn(substr($string, $pos + $spaces), " \n"); |
|
490 |
$words[] = str_replace("\n", $newline_escape, substr($string, $pos, $spaces + $nextpos)); |
|
491 |
$pos += $spaces + $nextpos; |
|
492 |
}
|
|
493 |
||
494 |
return $words; |
|
495 |
}
|
|
496 |
||
497 |
function _encode(&$string) |
|
498 |
{
|
|
499 |
$string = htmlspecialchars($string); |
|
500 |
}
|
|
501 |
}
|
|
502 |
||
503 |
/**
|
|
504 |
* "raw" diff renderer.
|
|
505 |
* This class could be used to output a raw unified patch file
|
|
506 |
*
|
|
507 |
* @package diff
|
|
508 |
*/
|
|
509 |
class diff_renderer_raw extends diff_renderer |
|
510 |
{
|
|
511 |
var $_leading_context_lines = 4; |
|
512 |
var $_trailing_context_lines = 4; |
|
513 |
||
514 |
/**
|
|
515 |
* Our function to get the diff
|
|
516 |
*/
|
|
517 |
function get_diff_content($diff) |
|
518 |
{
|
|
519 |
return '<textarea style="height: 290px;" class="full">' . htmlspecialchars($this->render($diff)) . '</textarea>'; |
|
520 |
}
|
|
521 |
||
522 |
function _block_header($xbeg, $xlen, $ybeg, $ylen) |
|
523 |
{
|
|
524 |
if ($xlen != 1) |
|
525 |
{
|
|
526 |
$xbeg .= ',' . $xlen; |
|
527 |
}
|
|
528 |
||
529 |
if ($ylen != 1) |
|
530 |
{
|
|
531 |
$ybeg .= ',' . $ylen; |
|
532 |
}
|
|
533 |
return '@@ -' . $xbeg . ' +' . $ybeg . ' @@'; |
|
534 |
}
|
|
535 |
||
536 |
function _context($lines) |
|
537 |
{
|
|
538 |
return $this->_lines($lines, ' '); |
|
539 |
}
|
|
540 |
||
541 |
function _added($lines) |
|
542 |
{
|
|
543 |
return $this->_lines($lines, '+'); |
|
544 |
}
|
|
545 |
||
546 |
function _deleted($lines) |
|
547 |
{
|
|
548 |
return $this->_lines($lines, '-'); |
|
549 |
}
|
|
550 |
||
551 |
function _changed($orig, $final) |
|
552 |
{
|
|
553 |
return $this->_deleted($orig) . $this->_added($final); |
|
554 |
}
|
|
555 |
}
|
|
556 |
||
557 |
/**
|
|
558 |
* "chora (Horde)" diff renderer - similar style.
|
|
559 |
* This renderer class is a modified human_readable function from the Horde Framework.
|
|
560 |
*
|
|
561 |
* @package diff
|
|
562 |
*/
|
|
563 |
class diff_renderer_side_by_side extends diff_renderer |
|
564 |
{
|
|
565 |
var $_leading_context_lines = 3; |
|
566 |
var $_trailing_context_lines = 3; |
|
567 |
||
568 |
var $lines = array(); |
|
569 |
||
570 |
// Hold the left and right columns of lines for change blocks.
|
|
571 |
var $cols; |
|
572 |
var $state; |
|
573 |
||
574 |
var $data = false; |
|
575 |
||
576 |
/**
|
|
577 |
* Our function to get the diff
|
|
578 |
*/
|
|
579 |
function get_diff_content($diff) |
|
580 |
{
|
|
581 |
global $user; |
|
582 |
||
583 |
$output = ''; |
|
584 |
$output .= '<table cellspacing="0" class="hrdiff"> |
|
585 |
<caption>
|
|
586 |
<span class="unmodified"> </span> ' . $user->lang['LINE_UNMODIFIED'] . ' |
|
587 |
<span class="added"> </span> ' . $user->lang['LINE_ADDED'] . ' |
|
588 |
<span class="modified"> </span> ' . $user->lang['LINE_MODIFIED'] . ' |
|
589 |
<span class="removed"> </span> ' . $user->lang['LINE_REMOVED'] . ' |
|
590 |
</caption>
|
|
591 |
<tbody>
|
|
592 |
'; |
|
593 |
||
594 |
$this->render($diff); |
|
595 |
||
596 |
// Is the diff empty?
|
|
597 |
if (!sizeof($this->lines)) |
|
598 |
{
|
|
599 |
$output .= '<tr><th colspan="2">' . $user->lang['NO_VISIBLE_CHANGES'] . '</th></tr>'; |
|
600 |
}
|
|
601 |
else
|
|
602 |
{
|
|
603 |
// Iterate through every header block of changes
|
|
604 |
foreach ($this->lines as $header) |
|
605 |
{
|
|
606 |
$output .= '<tr><th>Line ' . $header['oldline'] . '</th><th>' . $user->lang['LINE'] . ' ' . $header['newline'] . '</th></tr>'; |
|
607 |
||
608 |
// Each header block consists of a number of changes (add, remove, change).
|
|
609 |
$current_context = ''; |
|
610 |
||
611 |
foreach ($header['contents'] as $change) |
|
612 |
{
|
|
613 |
if (!empty($current_context) && $change['type'] != 'empty') |
|
614 |
{
|
|
615 |
$line = $current_context; |
|
616 |
$current_context = ''; |
|
617 |
||
618 |
$output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td> |
|
619 |
<td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>'; |
|
620 |
}
|
|
621 |
||
622 |
switch ($change['type']) |
|
623 |
{
|
|
624 |
case 'add': |
|
625 |
$line = ''; |
|
626 |
||
627 |
foreach ($change['lines'] as $_line) |
|
628 |
{
|
|
629 |
$line .= htmlspecialchars($_line) . '<br />'; |
|
630 |
}
|
|
631 |
||
632 |
$output .= '<tr><td class="added_empty"> </td><td class="added"><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>'; |
|
633 |
break; |
|
634 |
||
635 |
case 'remove': |
|
636 |
$line = ''; |
|
637 |
||
638 |
foreach ($change['lines'] as $_line) |
|
639 |
{
|
|
640 |
$line .= htmlspecialchars($_line) . '<br />'; |
|
641 |
}
|
|
642 |
||
643 |
$output .= '<tr><td class="removed"><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td><td class="removed_empty"> </td></tr>'; |
|
644 |
break; |
|
645 |
||
646 |
case 'empty': |
|
647 |
$current_context .= htmlspecialchars($change['line']) . '<br />'; |
|
648 |
break; |
|
649 |
||
650 |
case 'change': |
|
651 |
// Pop the old/new stacks one by one, until both are empty.
|
|
652 |
$oldsize = sizeof($change['old']); |
|
653 |
$newsize = sizeof($change['new']); |
|
654 |
$left = $right = ''; |
|
655 |
||
656 |
for ($row = 0, $row_max = max($oldsize, $newsize); $row < $row_max; ++$row) |
|
657 |
{
|
|
658 |
$left .= isset($change['old'][$row]) ? htmlspecialchars($change['old'][$row]) : ''; |
|
659 |
$left .= '<br />'; |
|
660 |
$right .= isset($change['new'][$row]) ? htmlspecialchars($change['new'][$row]) : ''; |
|
661 |
$right .= '<br />'; |
|
662 |
}
|
|
663 |
||
664 |
$output .= '<tr>'; |
|
665 |
||
666 |
if (!empty($left)) |
|
667 |
{
|
|
668 |
$output .= '<td class="modified"><pre>' . $left . '<br /></pre></td>'; |
|
669 |
}
|
|
670 |
else if ($row < $oldsize) |
|
671 |
{
|
|
672 |
$output .= '<td class="modified"> </td>'; |
|
673 |
}
|
|
674 |
else
|
|
675 |
{
|
|
676 |
$output .= '<td class="unmodified"> </td>'; |
|
677 |
}
|
|
678 |
||
679 |
if (!empty($right)) |
|
680 |
{
|
|
681 |
$output .= '<td class="modified"><pre>' . $right . '<br /></pre></td>'; |
|
682 |
}
|
|
683 |
else if ($row < $newsize) |
|
684 |
{
|
|
685 |
$output .= '<td class="modified"> </td>'; |
|
686 |
}
|
|
687 |
else
|
|
688 |
{
|
|
689 |
$output .= '<td class="unmodified"> </td>'; |
|
690 |
}
|
|
691 |
||
692 |
$output .= '</tr>'; |
|
693 |
break; |
|
694 |
}
|
|
695 |
}
|
|
696 |
||
697 |
if (!empty($current_context)) |
|
698 |
{
|
|
699 |
$line = $current_context; |
|
700 |
$current_context = ''; |
|
701 |
||
702 |
$output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td>'; |
|
703 |
$output .= '<td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>'; |
|
704 |
}
|
|
705 |
}
|
|
706 |
}
|
|
707 |
||
708 |
$output .= '</tbody></table>'; |
|
709 |
||
710 |
return $output; |
|
711 |
}
|
|
712 |
||
713 |
function _start_diff() |
|
714 |
{
|
|
715 |
$this->lines = array(); |
|
716 |
||
717 |
$this->data = false; |
|
718 |
$this->cols = array(array(), array()); |
|
719 |
$this->state = 'empty'; |
|
720 |
||
721 |
return ''; |
|
722 |
}
|
|
723 |
||
724 |
function _end_diff() |
|
725 |
{
|
|
726 |
// Just flush any remaining entries in the columns stack.
|
|
727 |
switch ($this->state) |
|
728 |
{
|
|
729 |
case 'add': |
|
730 |
$this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]); |
|
731 |
break; |
|
732 |
||
733 |
case 'remove': |
|
734 |
// We have some removal lines pending in our stack, so flush them.
|
|
735 |
$this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]); |
|
736 |
break; |
|
737 |
||
738 |
case 'change': |
|
739 |
// We have both remove and addition lines, so this is a change block.
|
|
740 |
$this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]); |
|
741 |
break; |
|
742 |
}
|
|
743 |
||
744 |
if ($this->data !== false) |
|
745 |
{
|
|
746 |
$this->lines[] = $this->data; |
|
747 |
}
|
|
748 |
||
749 |
return ''; |
|
750 |
}
|
|
751 |
||
752 |
function _block_header($xbeg, $xlen, $ybeg, $ylen) |
|
753 |
{
|
|
754 |
// Push any previous header information to the return stack.
|
|
755 |
if ($this->data !== false) |
|
756 |
{
|
|
757 |
$this->lines[] = $this->data; |
|
758 |
}
|
|
759 |
||
760 |
$this->data = array('type' => 'header', 'oldline' => $xbeg, 'newline' => $ybeg, 'contents' => array()); |
|
761 |
$this->state = 'dump'; |
|
762 |
}
|
|
763 |
||
764 |
function _added($lines) |
|
765 |
{
|
|
766 |
array_walk($lines, array(&$this, '_perform_add')); |
|
767 |
}
|
|
768 |
||
769 |
function _perform_add($line) |
|
770 |
{
|
|
771 |
if ($this->state == 'empty') |
|
772 |
{
|
|
773 |
return ''; |
|
774 |
}
|
|
775 |
||
776 |
// This is just an addition line.
|
|
777 |
if ($this->state == 'dump' || $this->state == 'add') |
|
778 |
{
|
|
779 |
// Start adding to the addition stack.
|
|
780 |
$this->cols[0][] = $line; |
|
781 |
$this->state = 'add'; |
|
782 |
}
|
|
783 |
else
|
|
784 |
{
|
|
785 |
// This is inside a change block, so start accumulating lines.
|
|
786 |
$this->state = 'change'; |
|
787 |
$this->cols[1][] = $line; |
|
788 |
}
|
|
789 |
}
|
|
790 |
||
791 |
function _deleted($lines) |
|
792 |
{
|
|
793 |
array_walk($lines, array(&$this, '_perform_delete')); |
|
794 |
}
|
|
795 |
||
796 |
function _perform_delete($line) |
|
797 |
{
|
|
798 |
// This is a removal line.
|
|
799 |
$this->state = 'remove'; |
|
800 |
$this->cols[0][] = $line; |
|
801 |
}
|
|
802 |
||
803 |
function _context($lines) |
|
804 |
{
|
|
805 |
array_walk($lines, array(&$this, '_perform_context')); |
|
806 |
}
|
|
807 |
||
808 |
function _perform_context($line) |
|
809 |
{
|
|
810 |
// An empty block with no action.
|
|
811 |
switch ($this->state) |
|
812 |
{
|
|
813 |
case 'add': |
|
814 |
$this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]); |
|
815 |
break; |
|
816 |
||
817 |
case 'remove': |
|
818 |
// We have some removal lines pending in our stack, so flush them.
|
|
819 |
$this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]); |
|
820 |
break; |
|
821 |
||
822 |
case 'change': |
|
823 |
// We have both remove and addition lines, so this is a change block.
|
|
824 |
$this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]); |
|
825 |
break; |
|
826 |
}
|
|
827 |
||
828 |
$this->cols = array(array(), array()); |
|
829 |
$this->data['contents'][] = array('type' => 'empty', 'line' => $line); |
|
830 |
$this->state = 'dump'; |
|
831 |
}
|
|
832 |
||
833 |
function _changed($orig, $final) |
|
834 |
{
|
|
835 |
return $this->_deleted($orig) . $this->_added($final); |
|
836 |
}
|
|
837 |
||
838 |
}
|
|
839 |
||
840 |
?>
|