]> 91.132.146.200 Git - dolphin.git/commitdiff
diff merge script
authorBanana <banana@starscream.de>
Mon, 19 Mar 2012 12:11:29 +0000 (13:11 +0100)
committerBanana <banana@starscream.de>
Mon, 19 Mar 2012 12:11:29 +0000 (13:11 +0100)
classes/phppatcher.php [new file with mode: 0755]

diff --git a/classes/phppatcher.php b/classes/phppatcher.php
new file mode 100755 (executable)
index 0000000..45504e8
--- /dev/null
@@ -0,0 +1,253 @@
+<?php
+/**
+ * PhpPatcher class
+ * @author legolas558
+ * @version 1.0
+ *
+ * improved, code cleanup and PHP5 done by jumpin.banana@gmail.com 2012
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ *
+ * You should have received a copy of the
+ * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+ * along with this program.  If not, see http://www.sun.com/cddl/cddl.html
+ *
+ * 
+ * Facility to merge unified diff files
+ * First use Merge() and then ApplyPatch() to commit changes
+ * files will be created, updated and/or deleted
+ *
+ */
+
+define('_PHPP_INVALID_INPUT', 'Invalid input');
+define('_PHPP_UNEXPECTED_EOF', 'Unexpected end of file');
+define('_PHPP_UNEXPECTED_ADD_LINE', 'Unexpected add line at line %d');
+define('_PHPP_UNEXPECTED_REMOVE_LINE', 'Unexpected remove line at line %d');
+define('_PHPP_INVALID_DIFF', 'Invalid unified diff block');
+define('_PHPP_FAILED_VERIFY', 'Failed source verification of file %s at line %d');
+
+class  PhpPatcher {
+       
+       var $root;
+       var $msg;
+       var $sources = array();
+       var $destinations = array();
+       var $removals = array();
+       var $newline = "\n";
+       
+       public function __construct($root_path) {
+               // if you specify a root path all paths will be intended as relative to it (and not written, too)
+               $this->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;
+       }
+}
+
+?>