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