![]() ![]() |
websvn |
Subversion Repositories: |
Compare with Previous - Blame - Download
<?php/*** Class used internally by Diff to actually compute the diffs.** This class uses the Unix `diff` program via shell_exec to compute the* differences between the two input arrays.** $Horde: framework/Text_Diff/Diff/Engine/shell.php,v 1.6.2.3 2008/01/04 10:37:27 jan Exp $** Copyright 2007-2008 The Horde Project (http://www.horde.org/)** See the enclosed file COPYING for license information (LGPL). If you did* not receive this file, see http://opensource.org/licenses/lgpl-license.php.** @author Milian Wolff <mail@milianw.de>* @package Text_Diff* @since 0.3.0*/class Text_Diff_Engine_shell {/*** Path to the diff executable** @var string*/var $_diffCommand = 'diff';/*** Returns the array of differences.** @param array $from_lines lines of text from old file* @param array $to_lines lines of text from new file** @return array all changes made (array with Text_Diff_Op_* objects)*/function diff($from_lines, $to_lines){array_walk($from_lines, array('Text_Diff', 'trimNewlines'));array_walk($to_lines, array('Text_Diff', 'trimNewlines'));$temp_dir = Text_Diff::_getTempDir();// Execute gnu diff or similar to get a standard diff file.$from_file = tempnam($temp_dir, 'Text_Diff');$to_file = tempnam($temp_dir, 'Text_Diff');$fp = fopen($from_file, 'w');fwrite($fp, implode("\n", $from_lines));fclose($fp);$fp = fopen($to_file, 'w');fwrite($fp, implode("\n", $to_lines));fclose($fp);$diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);unlink($from_file);unlink($to_file);if (is_null($diff)) {// No changes were madereturn array(new Text_Diff_Op_copy($from_lines));}$from_line_no = 1;$to_line_no = 1;$edits = array();// Get changed lines by parsing something like:// 0a1,2// 1,2c4,6// 1,5d6preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,$matches, PREG_SET_ORDER);foreach ($matches as $match) {if (!isset($match[5])) {// This paren is not set every time (see regex).$match[5] = false;}if ($match[3] == 'a') {$from_line_no--;}if ($match[3] == 'd') {$to_line_no--;}if ($from_line_no < $match[1] || $to_line_no < $match[4]) {// copied linesassert('$match[1] - $from_line_no == $match[4] - $to_line_no');array_push($edits,new Text_Diff_Op_copy($this->_getLines($from_lines, $from_line_no, $match[1] - 1),$this->_getLines($to_lines, $to_line_no, $match[4] - 1)));}switch ($match[3]) {case 'd':// deleted linesarray_push($edits,new Text_Diff_Op_delete($this->_getLines($from_lines, $from_line_no, $match[2])));$to_line_no++;break;case 'c':// changed linesarray_push($edits,new Text_Diff_Op_change($this->_getLines($from_lines, $from_line_no, $match[2]),$this->_getLines($to_lines, $to_line_no, $match[5])));break;case 'a':// added linesarray_push($edits,new Text_Diff_Op_add($this->_getLines($to_lines, $to_line_no, $match[5])));$from_line_no++;break;}}if (!empty($from_lines)) {// Some lines might still be pending. Add them as copiedarray_push($edits,new Text_Diff_Op_copy($this->_getLines($from_lines, $from_line_no,$from_line_no + count($from_lines) - 1),$this->_getLines($to_lines, $to_line_no,$to_line_no + count($to_lines) - 1)));}return $edits;}/*** Get lines from either the old or new text** @access private** @param array &$text_lines Either $from_lines or $to_lines* @param int &$line_no Current line number* @param int $end Optional end line, when we want to chop more* than one line.** @return array The chopped lines*/function _getLines(&$text_lines, &$line_no, $end = false){if (!empty($end)) {$lines = array();// We can shift even morewhile ($line_no <= $end) {array_push($lines, array_shift($text_lines));$line_no++;}} else {$lines = array(array_shift($text_lines));$line_no++;}return $lines;}}