patchfs context

Adam Byrtek 'alpha' alpha at student.uci.agh.edu.pl
Tue Dec 24 13:13:17 UTC 2002


Hi Andrew. I've made context format support - it wasn't so hard. Just
a nice work for Christmas :)

I decided to detect format of the first diff found in the patch, and
assume the whole file is in this format - it made things easier. I
guess nobody sane mixes unified and context in one patch, and I wonder
if even patch(1) supports this...

Could you test this feature and send me any comments, please?

I wish all mc-devel people Merry Christmas!

Regards
alpha

-- 

  _.|._ |_  _.    : Adam Byrtek, alpha@(irc.pl|debian.org)
 (_|||_)| |(_|    : gg 1802819, pgp 0xB25952C0
     |            : jid alpha.pl(at)jabber.org
-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/mc/vfs/ChangeLog,v
retrieving revision 1.571
diff -u -0 -r1.571 ChangeLog
--- ChangeLog	24 Dec 2002 06:56:16 -0000	1.571
+++ ChangeLog	24 Dec 2002 13:05:16 -0000
@@ -0,0 +1,5 @@
+2002-12-24  Adam Byrtek  <alpha at debian.org>
+ 
+	* extfs/patchfs.in: context diff format support, regular
+	expressions precompiled, some minor fixes
+
Index: extfs/patchfs.in
===================================================================
RCS file: /cvs/gnome/mc/vfs/extfs/patchfs.in,v
retrieving revision 1.11
diff -u -r1.11 patchfs.in
--- extfs/patchfs.in	19 Dec 2002 18:20:12 -0000	1.11
+++ extfs/patchfs.in	24 Dec 2002 13:05:45 -0000
@@ -1,8 +1,8 @@
 #! @PERL@ -w
 #
-# Written by Adam Byrtek <alpha at debian.org>, 2002
-# 
-# extfs to handle patches in unified diff format
+# Written by Adam Byrtek <alpha at debian.org>, 2002              -*- perl -*-
+#
+# extfs to handle patches in context and unified diff format
 
 use bytes;
 use strict;
@@ -16,6 +16,18 @@
 # date parsing requires Date::Parse from TimeDate module
 my $parsedates = eval "require Date::Parse";
 
+# regular expressions
+my $unified_header=qr/^--- .*\n\+\+\+ .*\n@@ .* @@.*\n$/;
+my $unified_extract=qr/^--- ([^\s]+).*\n\+\+\+ ([^\s]+)\s*([^\t\n]*)/;
+my $unified_contents=qr/^([+\- \n]|@@ .* @@)/;
+
+my $context_header=qr/^\*\*\* .*\n--- .*\n\*{15}\n$/;
+my $context_extract=qr/^\*\*\* ([^\s]+).*\n--- ([^\s]+)\s*([^\t\n]*)/;
+my $context_contents=qr/^([!+\- \n]|-{3} .* -{4}|\*{3} .* \*{4}|\*{15})/;
+
+my $ls_extract_id=qr/^[^\s]+\s+[^\s]+\s+([^\s]+)\s+([^\s]+)/;
+my $basename=qr|^(.*/)*([^/]+)$|;
+
 
 # output unix date in a mc-readable format
 sub timef
@@ -49,17 +61,29 @@
     my ($archive)=(quotemeta $_[0]);
     my ($state,$pos,$len,$time);
     my ($f,$fsrc,$fdst,$prefix);
+    my ($unified,$context)=(0,0);
 
     # use uid and gid from file
-    my ($uid,$gid)=(`ls -l $archive`=~/^[^\s]+\s+[^\s]+\s+([^\s]+)\s+([^\s]+)/);
+    my ($uid,$gid)=(`ls -l $archive`=~/$ls_extract_id/);
 
     import Date::Parse if ($parsedates);
     
     # state==1 means diff contents, state==0 means comments
-    $state=1; $len=0; $f='';
+    $state=0; $len=0; $f='';
     while (<I>) {
-	if (/^--- /) {
-	    # parse diff header
+
+	# recognize diff type
+	if (!$unified && !$context) {
+	    $unified=1 if (/^--- /);
+	    $context=1 if (/^\*\*\* /);
+	    if (!$unified && !$context) {
+		$len+=length;
+		next;
+	    }
+	}
+	
+	if (($unified && /^--- /) || ($context && /^\*\*\* [^\*]*$/)) {
+	    # start of new file
 	    if ($state==1) {
 		printf "-rw-r--r-- 1 %s %s %d %s %s%s\n", $uid, $gid, $len, datetime($time), $prefix, $f
 		  if $f;
@@ -67,22 +91,27 @@
 	    }
 	    $state=1;
 
-	    error "Can't parse unified diff header"
-	      unless ((($_.=<I>).=<I>)=~/^\--- .*\n\+\+\+ .*\n@@ .* @@.*\n$/);
-	    ($fsrc)=/^--- ([^\s]+).*\n.*\n.*\n$/;
-	    ($fdst)=/^.*\n\+\+\+ ([^\s]+).*\n.*\n$/;
-	    ($time)=/^.*\n\+\+\+ [^\s]+\s+([^\t\n]+).*\n.*\n$/;
+	    # parse diff header
+	    if ($unified) {
+		error "Can't parse unified diff header"
+		  unless ((($_.=<I>).=<I>)=~/$unified_header/);
+		($fsrc,$fdst,$time)=/$unified_extract/;
+	    } elsif ($context) {
+		error "Can't parse context diff header"
+		  unless ((($_.=<I>).=<I>)=~/$context_header/);
+		($fsrc,$fdst,$time)=/$context_extract/;
+	    }
 
 	    # select filename, conform with (diff.info)Multiple patches
 	    $prefix="";
-	    if ($fsrc eq "/dev/null") {
+	    if (!$fdst && !$fsrc) {
+		error "Index: not yet implemented";
+	    } elsif (!$fsrc || $fsrc eq "/dev/null") {
 		$f=$fdst; $prefix="PATCH-CREATE/";
-	    } elsif ($fdst eq "/dev/null") {
+	    } elsif (!$fdst || $fdst eq "/dev/null") {
 		$f=$fsrc; $prefix="PATCH-REMOVE/";
 	    } elsif (($fdst eq "/dev/null") && ($fsrc eq "/dev/null")) {
 		error "Malformed diff";
-	    } elsif (!$fdst && !$fsrc) {
-		error "Index: not yet implemented";
 	    } else {
 		# fewest path name components
 		if ($fdst=~s|/|/|g < $fsrc=~s|/|/|g) {
@@ -91,9 +120,9 @@
 		    $f=$fsrc;
 		} else {
 		    # shorter base name
-		    if (($fdst=~m|^.*/([^/]+)$|,length $1) < ($fsrc=~m|^.*/([^/]+)$|,length $1)) {
+		    if (($fdst=~/$basename/,length $2) < ($fsrc=~/$basename/,length $2)) {
 			$f=$fdst;
-		    } elsif (($fdst=~m|^.*/([^/]+)$|,length $1) > ($fsrc=~m|^.*/([^/]+)$|,length $1)) {
+		    } elsif (($fdst=~/$basename/,length $2) > ($fsrc=~/$basename/,length $2)) {
 			$f=$fsrc;
 		    } else {
 			# shortest names
@@ -107,45 +136,65 @@
 	    }
 	    $f=$f.".diff";
 
-	} elsif ($state==1 && !/^([+\- \n]|@@)/) {
+	} elsif ($state==1 && (($unified && !/$unified_contents/) || ($context && !/$context_contents/))) {
 	    # start of comments, end of diff contents
 	    printf "-rw-r--r-- 1 %s %s %d %s %s%s\n", $uid, $gid, $len, datetime($time), $prefix, $f
 	      if $f;
 	    $state=$len=0;
 	}
+
 	$len+=length;
     }
     printf "-rw-r--r-- 1 %s %s %d %s %s%s\n", $uid, $gid, $len, datetime($time), $prefix, $f
       if $f;
 }
 
+# extract diff from patch
 sub copyout
 {
     my ($file,$out)=@_;
     my ($fsrc,$fdst,$found,$state,$buf);
+    my ($unified,$context)=(0,0);
 
     $file=~s/^(PATCH-(CREATE|REMOVE)\/)?(.*)\.diff$/$3/;
     
     # state==1 means diff contents, state==0 mens comments
-    $state=1; $found=0; $buf="";
+    $state=0; $found=0; $buf="";
     while (<I>) {
-	if (/^--- /) {
-	    # parse diff header
+
+	# recognize diff type
+	if (!$unified && !$context) {
+	    $unified=1 if (/^--- /);
+	    $context=1 if (/^\*\*\* /);
+	    if (!$unified && !$context) {
+		$buf.=$_;
+		next;
+	    }
+	}
+
+	if (($unified && /^--- /) || ($context && /^\*\*\* [^\*]*$/)) {
 	    last if ($state==1 && $found);
 	    $state=1;
 
-	    error "Can't parse unified diff header"
-	      unless ((($_.=<I>).=<I>)=~/^\--- .*\n\+\+\+ .*\n@@ .* @@.*\n$/);
-	    ($fsrc)=/^--- ([^\s]+).*\n.*\n.*\n$/;
-	    ($fdst)=/^.*\n\+\+\+ ([^\s]+).*\n.*\n$/;
+	    # parse diff header
+	    if ($unified) {
+		error "Can't parse unified diff header"
+		  unless ((($_.=<I>).=<I>)=~/$unified_header/);
+		($fsrc,$fdst)=/$unified_extract/;
+	    } elsif ($context) {
+		error "Can't parse context diff header"
+		  unless ((($_.=<I>).=<I>)=~/$context_header/);
+		($fsrc,$fdst)=/$context_extract/;
+	    }
 	    $found=1 if (($fsrc eq $file) || ($fdst eq $file));
 
-	} elsif ($state==1 && !/^([+\- \n]|@@)/) {
+	} elsif ($state==1 && (($unified && !/$unified_contents/) || ($context && !/$context_contents/))) {
 	    # start of comments, end of diff contents
 	    last if ($found);
 	    $state=0;
 	    $buf="";
 	}
+
 	$buf.=$_ if ($found || $state==0)
     }
     if ($found) {
@@ -155,9 +204,9 @@
     }
 }
 
+# append diff to archive
 sub copyin
 {
-    # append diff to archive
     my ($archive,$name,$f)=(quotemeta $_[0],$_[1],quotemeta $_[2]);
     my ($cmd);
 
@@ -183,9 +232,9 @@
     }
 }
 
+# open (compressed) archive for reading
 sub openread
 {
-    # open (compressed) archive for reading
     my ($archive) = (quotemeta $_[0]);
 
     $_=`$file $archive`;


More information about the mc-devel mailing list