From f4cf08518cee5962682f4588cf5ded744c9bceec Mon Sep 17 00:00:00 2001 From: Banana Date: Mon, 19 Mar 2012 13:11:29 +0100 Subject: [PATCH] diff merge script --- classes/phppatcher.php | 253 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100755 classes/phppatcher.php diff --git a/classes/phppatcher.php b/classes/phppatcher.php new file mode 100755 index 0000000..45504e8 --- /dev/null +++ b/classes/phppatcher.php @@ -0,0 +1,253 @@ +root = $root_path; + } + + public function Merge($udiff) { + $lines = $this->_linesplit($udiff); + if (!isset($lines)) { + $this->msg = _PHPP_INVALID_INPUT; + return false; + } + unset($udiff); + + $line = current($lines); + do { + if (strlen($line)<5) { + continue; + } + // start recognition when a new diff block is found + if (substr($line, 0, 4)!='--- ') { + continue; + } + $p = strpos($line, "\t", 4); + if ($p===false) $p = strlen($line); + $src = $this->root.substr($line, 4, $p-4); + $line = next($lines); + if (!isset($line)) { + $this->msg = _PHPP_UNEXPECTED_EOF; + return false; + } + if (substr($line, 0, 4)!='+++ ') { + $this->msg = _PHPP_INVALID_DIFF; + return false; + } + $p = strpos($line, "\t", 4); + if ($p===false) $p = strlen($line); + $dst = $this->root.substr($line, 4, $p-4); + + $line = next($lines); + if (!isset($line)) { + $this->msg = _PHPP_UNEXPECTED_EOF; + return false; + } + + $done=0; + while (preg_match('/@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@($)/A', $line, $m)) { + + if ($m[3]==='') + $src_size = 1; + else $src_size = (int)$m[3]; + if ($m[6]==='') + $dst_size = 1; + else $dst_size = (int)$m[6]; + if (!$this->_apply_diff($lines, $src, $dst, + (int)$m[1], $src_size, (int)$m[4], + $dst_size)) + return false; + $done++; + $line = next($lines); + if ($line === FALSE) + break 2; + } + if ($done==0) { + $this->msg = _PHPP_INVALID_DIFF; + return false; + } + + } while (FALSE !== ($line = next($lines))); + + //NOTE: previously opened files are still cached + return true; + } + + function ClearCache() { + $this->sources = array(); + $this->destinations = array(); + $this->removals = array(); + } + + function ApplyPatch() { + if (empty($this->destinations)) + return 0; + $done = 0; + $files = array_keys($this->destinations); + foreach($files as $file) { + $f = @fopen($file, 'w'); + if ($f===null) + continue; + fwrite($f, implode($this->newline, $this->destinations[$file])); + fclose($f); + $done++; + } + foreach($this->removals as $file) { + if (@unlink($file)) + $done++; + if (isset($this->sources[$file])) + unset($this->sources[$file]); + } + $this->destinations = array(); // clear the destinations cache + $this->removals = array(); + return $done; + } + + private function &_get_source($src) { + if (isset($this->sources[$src])) + return $this->sources[$src]; + if (!is_readable($src)) { + return null; + } + $_data = file_get_contents($src); + $this->sources[$src] = $this->_linesplit($_data); + return $this->sources[$src]; + } + + private function &_get_destin($dst, $src) { + if (isset($this->destinations[$dst])) + return $this->destinations[$dst]; + $this->destinations[$dst] = $this->_get_source($src); + return $this->destinations[$dst]; + } + + // separate CR or CRLF lines + private function &_linesplit(&$data) { + $lines = preg_split('/(\r\n)|(\r)|(\n)/', $data); + return $lines; + } + + private function _apply_diff(&$lines, $src, $dst, $src_line, $src_size, $dst_line, $dst_size) { + $src_line--; + $dst_line--; + $line = next($lines); + if ($line === false) { + $this->msg = _PHPP_UNEXPECTED_EOF; + return false; + } + $source = array(); // source lines (old file) + $destin = array(); // new lines (new file) + $src_left = $src_size; + $dst_left = $dst_size; + do { + if (!isset($line{0})) { + $source[] = ''; + $destin[] = ''; + $src_left--; + $dst_left--; + continue; + } + if ($line{0}=='-') { + if ($src_left==0) { + $this->msg = sprintf(_PHPP_UNEXPECTED_REMOVE_LINE, key($lines)); + return false; + } + $source[] = substr($line, 1); + $src_left--; + } else if ($line{0}=='+') { + if ($dst_left==0) { + $this->msg = sprintf(_PHPP_UNEXPECTED_ADD_LINE, key($lines)); + return false; + } + $destin[] = substr($line, 1); + $dst_left--; + } else { + if (!isset($line{1})) + $line = ''; + else if ($line{0}=='\\') { + if ($line=='\\ No newline at end of file') { + continue; + } + } else { + $line = substr($line, 1); + } + $source[] = $line; + $destin[] = $line; + $src_left--; + $dst_left--; + } + + if (($src_left==0) && ($dst_left==0)) { + // now apply the patch, finally! + if ($src_size>0) { + $src_lines =& $this->_get_source($src); + if (!isset($src_lines)) { + return false; + } + } + if ($dst_size>0) { + if ($src_size>0) { + $dst_lines =& $this->_get_destin($dst, $src); + if (!isset($dst_lines)) + return false; + $src_bottom=$src_line+count($source); + $dst_bottom=$dst_line+count($destin); + + for ($l=$src_line;$l<$src_bottom;$l++) { + if ($src_lines[$l]!=$source[$l-$src_line]) { + $this->msg = sprintf(_PHPP_FAILED_VERIFY, $src, $l); + return false; + } + } + array_splice($dst_lines, $dst_line, count($source), $destin); + } else + $this->destinations[$dst] = $destin; + } else + $this->removals[] = $src; + + return true; + } + } while (FALSE !== ($line = next($lines))); + + $this->msg = _PHPP_UNEXPECTED_EOF; + return false; + } +} + +?> -- 2.39.5