source: trunk/www.guidonia.net/wp/wp-includes/Text/Diff/Engine/shell.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 15 years ago
File size: 5.1 KB
Line 
1<?php
2/**
3 * Class used internally by Diff to actually compute the diffs.
4 *
5 * This class uses the Unix `diff` program via shell_exec to compute the
6 * differences between the two input arrays.
7 *
8 * $Horde: framework/Text_Diff/Diff/Engine/shell.php,v 1.8 2008/01/04 10:07:50 jan Exp $
9 *
10 * Copyright 2007-2008 The Horde Project (http://www.horde.org/)
11 *
12 * See the enclosed file COPYING for license information (LGPL). If you did
13 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
14 *
15 * @author Milian Wolff <mail@milianw.de>
16 * @package Text_Diff
17 * @since 0.3.0
18 */
19class Text_Diff_Engine_shell {
20
21 /**
22 * Path to the diff executable
23 *
24 * @var string
25 */
26 var $_diffCommand = 'diff';
27
28 /**
29 * Returns the array of differences.
30 *
31 * @param array $from_lines lines of text from old file
32 * @param array $to_lines lines of text from new file
33 *
34 * @return array all changes made (array with Text_Diff_Op_* objects)
35 */
36 function diff($from_lines, $to_lines)
37 {
38 array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
39 array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
40
41 $temp_dir = Text_Diff::_getTempDir();
42
43 // Execute gnu diff or similar to get a standard diff file.
44 $from_file = tempnam($temp_dir, 'Text_Diff');
45 $to_file = tempnam($temp_dir, 'Text_Diff');
46 $fp = fopen($from_file, 'w');
47 fwrite($fp, implode("\n", $from_lines));
48 fclose($fp);
49 $fp = fopen($to_file, 'w');
50 fwrite($fp, implode("\n", $to_lines));
51 fclose($fp);
52 $diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
53 unlink($from_file);
54 unlink($to_file);
55
56 if (is_null($diff)) {
57 // No changes were made
58 return array(new Text_Diff_Op_copy($from_lines));
59 }
60
61 $from_line_no = 1;
62 $to_line_no = 1;
63 $edits = array();
64
65 // Get changed lines by parsing something like:
66 // 0a1,2
67 // 1,2c4,6
68 // 1,5d6
69 preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
70 $matches, PREG_SET_ORDER);
71
72 foreach ($matches as $match) {
73 if (!isset($match[5])) {
74 // This paren is not set every time (see regex).
75 $match[5] = false;
76 }
77
78 if ($match[3] == 'a') {
79 $from_line_no--;
80 }
81
82 if ($match[3] == 'd') {
83 $to_line_no--;
84 }
85
86 if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
87 // copied lines
88 assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
89 array_push($edits,
90 new Text_Diff_Op_copy(
91 $this->_getLines($from_lines, $from_line_no, $match[1] - 1),
92 $this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
93 }
94
95 switch ($match[3]) {
96 case 'd':
97 // deleted lines
98 array_push($edits,
99 new Text_Diff_Op_delete(
100 $this->_getLines($from_lines, $from_line_no, $match[2])));
101 $to_line_no++;
102 break;
103
104 case 'c':
105 // changed lines
106 array_push($edits,
107 new Text_Diff_Op_change(
108 $this->_getLines($from_lines, $from_line_no, $match[2]),
109 $this->_getLines($to_lines, $to_line_no, $match[5])));
110 break;
111
112 case 'a':
113 // added lines
114 array_push($edits,
115 new Text_Diff_Op_add(
116 $this->_getLines($to_lines, $to_line_no, $match[5])));
117 $from_line_no++;
118 break;
119 }
120 }
121
122 if (!empty($from_lines)) {
123 // Some lines might still be pending. Add them as copied
124 array_push($edits,
125 new Text_Diff_Op_copy(
126 $this->_getLines($from_lines, $from_line_no,
127 $from_line_no + count($from_lines) - 1),
128 $this->_getLines($to_lines, $to_line_no,
129 $to_line_no + count($to_lines) - 1)));
130 }
131
132 return $edits;
133 }
134
135 /**
136 * Get lines from either the old or new text
137 *
138 * @access private
139 *
140 * @param array &$text_lines Either $from_lines or $to_lines
141 * @param int &$line_no Current line number
142 * @param int $end Optional end line, when we want to chop more
143 * than one line.
144 *
145 * @return array The chopped lines
146 */
147 function _getLines(&$text_lines, &$line_no, $end = false)
148 {
149 if (!empty($end)) {
150 $lines = array();
151 // We can shift even more
152 while ($line_no <= $end) {
153 array_push($lines, array_shift($text_lines));
154 $line_no++;
155 }
156 } else {
157 $lines = array(array_shift($text_lines));
158 $line_no++;
159 }
160
161 return $lines;
162 }
163
164}
Note: See TracBrowser for help on using the repository browser.