1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16: class Horde_Text_Diff_Engine_Shell
17: {
18: 19: 20: 21: 22:
23: protected $_diffCommand = 'diff';
24:
25: 26: 27: 28: 29: 30: 31: 32:
33: public function diff($from_lines, $to_lines)
34: {
35: array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines'));
36: array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines'));
37:
38:
39: $from_file = Horde_Util::getTempFile('Horde_Text_Diff');
40: $to_file = Horde_Util::getTempFile('Horde_Text_Diff');
41: $fp = fopen($from_file, 'w');
42: fwrite($fp, implode("\n", $from_lines));
43: fclose($fp);
44: $fp = fopen($to_file, 'w');
45: fwrite($fp, implode("\n", $to_lines));
46: fclose($fp);
47: $diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
48: unlink($from_file);
49: unlink($to_file);
50:
51: if (is_null($diff)) {
52:
53: return array(new Horde_Text_Diff_Op_Copy($from_lines));
54: }
55:
56: $from_line_no = 1;
57: $to_line_no = 1;
58: $edits = array();
59:
60:
61:
62:
63:
64: preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
65: $matches, PREG_SET_ORDER);
66:
67: foreach ($matches as $match) {
68: if (!isset($match[5])) {
69:
70: $match[5] = false;
71: }
72:
73: if ($match[3] == 'a') {
74: $from_line_no--;
75: }
76:
77: if ($match[3] == 'd') {
78: $to_line_no--;
79: }
80:
81: if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
82:
83: assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
84: array_push($edits,
85: new Horde_Text_Diff_Op_Copy(
86: $this->_getLines($from_lines, $from_line_no, $match[1] - 1),
87: $this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
88: }
89:
90: switch ($match[3]) {
91: case 'd':
92:
93: array_push($edits,
94: new Horde_Text_Diff_Op_Delete(
95: $this->_getLines($from_lines, $from_line_no, $match[2])));
96: $to_line_no++;
97: break;
98:
99: case 'c':
100:
101: array_push($edits,
102: new Horde_Text_Diff_Op_Change(
103: $this->_getLines($from_lines, $from_line_no, $match[2]),
104: $this->_getLines($to_lines, $to_line_no, $match[5])));
105: break;
106:
107: case 'a':
108:
109: array_push($edits,
110: new Horde_Text_Diff_Op_Add(
111: $this->_getLines($to_lines, $to_line_no, $match[5])));
112: $from_line_no++;
113: break;
114: }
115: }
116:
117: if (!empty($from_lines)) {
118:
119: array_push($edits,
120: new Horde_Text_Diff_Op_Copy(
121: $this->_getLines($from_lines, $from_line_no,
122: $from_line_no + count($from_lines) - 1),
123: $this->_getLines($to_lines, $to_line_no,
124: $to_line_no + count($to_lines) - 1)));
125: }
126:
127: return $edits;
128: }
129:
130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141:
142: protected function _getLines(&$text_lines, &$line_no, $end = false)
143: {
144: if (!empty($end)) {
145: $lines = array();
146:
147: while ($line_no <= $end) {
148: array_push($lines, array_shift($text_lines));
149: $line_no++;
150: }
151: } else {
152: $lines = array(array_shift($text_lines));
153: $line_no++;
154: }
155:
156: return $lines;
157: }
158: }
159: