+sub apply_patch
+{
+ my($diff) = @_;
+
+ undef @new;
+ system "rsync -a --del --exclude='*~' cvsdir/ workdir/";
+ print "\nApplying patch $diff...\n";
+ undef @rejects;
+ my($saw_offset, $saw_fuzz);
+ open(IN, "patch -d workdir -p1 --no-backup-if-mismatch <patches/$diff |") or die $!;
+ while (<IN>) {
+ print $_;
+ chomp;
+ if (s/^patching file //) {
+ push(@new, $_) unless -f "cvsdir/$_";
+ } elsif (s/.* saving rejects to file //) {
+ push(@rejects, $_);
+ } elsif (/^Hunk #\d+ succeeded at \d+( with fuzz $interesting_fuzz)?/o) {
+ $saw_fuzz ||= defined $1;
+ $saw_offset = 1;
+ }
+ }
+ close IN;
+ return 'F,D,E' if @rejects;
+ return 'D,E' if $saw_fuzz && !$failures_only;
+ return 'D,U,N' if $saw_offset && !$failures_only;
+ 'N';
+}
+
+sub filter_diff
+{
+ my($cmd) = @_;
+ open(IN, '-|', $cmd) or die $!;
+ while (<IN>) {
+ next if /^(diff -|Index: |Only in )/;
+ s#^\Q--- cvsdir/\E([^\t]+).*#--- old/$1#;
+ s#^\Q+++ workdir/\E([^\t]+).*#+++ new/$1#;
+ print OUT $_;
+ }
+ close IN;
+}
+