diff options
Diffstat (limited to 'wp-includes/Text/Diff/Engine/shell.php')
-rw-r--r-- | wp-includes/Text/Diff/Engine/shell.php | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/wp-includes/Text/Diff/Engine/shell.php b/wp-includes/Text/Diff/Engine/shell.php new file mode 100644 index 0000000..545ac34 --- /dev/null +++ b/wp-includes/Text/Diff/Engine/shell.php @@ -0,0 +1,162 @@ +<?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. + * + * Copyright 2007-2010 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see https://opensource.org/license/lgpl-2-1/. + * + * @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 made + return 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,5d6 + preg_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 lines + assert($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 lines + array_push($edits, + new Text_Diff_Op_delete( + $this->_getLines($from_lines, $from_line_no, $match[2]))); + $to_line_no++; + break; + + case 'c': + // changed lines + array_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 lines + array_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 copied + array_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 (passed by reference). + * @param int $line_no Current line number (passed by reference). + * @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 more + while ($line_no <= $end) { + array_push($lines, array_shift($text_lines)); + $line_no++; + } + } else { + $lines = array(array_shift($text_lines)); + $line_no++; + } + + return $lines; + } + +} |