~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to www/php/phpBB3/includes/diff/renderer.php

  • Committer: dcoles
  • Date: 2008-02-13 04:10:55 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:443
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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">&nbsp;</span> ' . $user->lang['LINE_UNMODIFIED'] . '
 
587
        <span class="added">&nbsp;</span> ' . $user->lang['LINE_ADDED'] . '
 
588
        <span class="modified">&nbsp;</span> ' . $user->lang['LINE_MODIFIED'] . '
 
589
        <span class="removed">&nbsp;</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 : '&nbsp;') . '<br /></pre></td>
 
619
                                                        <td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<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">&nbsp;</td><td class="added"><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<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 : '&nbsp;') . '<br /></pre></td><td class="removed_empty">&nbsp;</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">&nbsp;</td>';
 
673
                                                        }
 
674
                                                        else
 
675
                                                        {
 
676
                                                                $output .= '<td class="unmodified">&nbsp;</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">&nbsp;</td>';
 
686
                                                        }
 
687
                                                        else
 
688
                                                        {
 
689
                                                                $output .= '<td class="unmodified">&nbsp;</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 : '&nbsp;') . '<br /></pre></td>';
 
703
                                        $output .= '<td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<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
?>
 
 
b'\\ No newline at end of file'