#!/usr/bin/perl -w # # xrcsdiff - graphical rcsdiff using a graphical diff program # such as Martin Blais's xxdiff (the default) # which can compare up to 3 revisions, # and can be obtained from: # http://xxdiff.sourceforge.net/ # or Rudy Wortel's xdiff # (which can compare up to 5 revisions, but is not supported well). # xdiff can be obtained from: # http://reality.sgi.com/rudy_aw/xdiff/ # # Usage: xrcsdiff [-v ] [-b] [-w] [-i] file # # The following options are passed on to xxdiff (which passes them on to diff): # -b - ignore trailing blanks # -w - ignore whitespace # -i - ignore case # XXX should pass on [-tabs ] too # All other command-line options are passed on to rcsdiff. # # The following programs must reside in a non-. directory in $PATH: # xxdiff (or the value of $XDIFF if set) # rlog # co # (non-. since these commands may be executed from within a directory # other than the current directory). # # If invoked as xcvsdiff, then cvs is used instead of rcs. # # Author: Don Hatch (hatch@hadron.org) # # Revision history: # Tue Jun 4 21:55:23 PDT 2002 # Default is now xxdiff instead of xdiff # Mon Mar 5 18:39:28 PST 2001 # Use env XDIFF if set, otherwise "xdiff" # Wed Jul 26 12:35:09 PDT 2000 # Added cvs support (when invoked as xcvsdiff) # Fri Jun 23 01:20:01 PDT 2000 # Initial version # # This software may be used for any purpose # as long as it is good and not evil. # use strict; sub usageError($) { my ($using_cvs) = @_; printf STDERR "Usage: $0 [-v ] [-b] [-w] [-i] <%s options> file\n", $using_cvs ? "cvs diff" : "rcsdiff"; exit 1; } main: { # # Process command line... # my $verbose = 0; my $using_cvs = 0; my $xdiff = exists($ENV{"XDIFF"}) ? $ENV{"XDIFF"} : "xxdiff"; my @xdiffOptions = (); my @rcsdiffOptions = (); my $fileName; { $using_cvs = ($0 =~ m/cvs[^\/]*$/); # if 'cvs' in trailing component @xdiffOptions = grep {/^-[bwi]/} @ARGV; @ARGV = grep {!/^-[bwi]/} @ARGV; if (@ARGV >= 2 && $ARGV[0] eq '-v') { shift @ARGV; $verbose = shift @ARGV; # XXX should make sure it's a number } if (@ARGV == 1 && $ARGV[0] eq '-v') { usageError($using_cvs); } if (@ARGV == 0) { usageError($using_cvs); } $fileName = pop @ARGV; @rcsdiffOptions = @ARGV; } my $co = 'co -q'; my $rlog = 'rlog'; if ($using_cvs) { $co = 'cvs -n -q update'; $rlog = 'cvs log'; } if ($verbose >= 1) { print "\$xdiff = $xdiff\n"; print "\@xdiffOptions = @xdiffOptions\n"; print "\@rcsdiffOptions = @rcsdiffOptions\n"; print "\$fileName = $fileName\n"; print "\$using_cvs = $using_cvs\n"; print " \$co = $co\n"; print " \$rlog = $rlog\n"; } # # Extract all r args; these are the revisions to extract. # my @revsRequested = grep {/^-r/} @rcsdiffOptions; @rcsdiffOptions = grep {!/^-r/} @rcsdiffOptions; map {s/-r//} @revsRequested; if ($verbose >= 1) { print "\n"; print "\@revsRequested = @revsRequested\n"; print "\@rcsdiffOptions = @rcsdiffOptions\n"; } if (@revsRequested == 0) { # # Zero revs requested-- check out the most recent revision # and diff it with the existing file. # Use rlog to get the version number to put in the xdiff title bar. # @revsRequested = grep {s/^head: //} split(/\n/, `$rlog -h $fileName`); # fall through to @revsRequested==1 case... } if (@revsRequested == 1) { # # One rev requested-- check out that revision and diff it # with the existing file. # exec "$co @rcsdiffOptions -r@revsRequested -p $fileName | \ $xdiff @xdiffOptions -N '$fileName @revsRequested' - $fileName"; } else { # # Two or more revisions requested-- check them all out and diff them # (currently xdiff handles up to 5 files). # This is the only case for which the temp dir is needed. # We need to catch interrupts and error returns of all executed # commands so that we can clean up the temp dir. # my $tailFileName = $fileName; $tailFileName =~ s/\/*$//; # remove any traling /'s $tailFileName =~ s/.*\///; # remove up to final / my $tmpDirName = "/var/tmp/xrcsdiff$$"; $verbose >= 1 && print "tmpDirName=$tmpDirName\n"; $SIG{HUP} = $SIG{INT} = $SIG{TERM} = sub { print STDERR "Cleaning up $tmpDirName\n"; system("/bin/rm -rf $tmpDirName"); exit 1; }; system("/bin/mkdir $tmpDirName") and kill 'HUP', $$; for my $rev (@revsRequested) { system("$co @rcsdiffOptions -r$rev -p $fileName > $tmpDirName/$tailFileName$rev") and kill 'HUP', $$; } my @tailFileNames = map {"$tailFileName$_"} @revsRequested; system("(cd $tmpDirName && $xdiff @xdiffOptions @tailFileNames)") and kill 'HUP', $$; exec("/bin/rm -rf $tmpDirName"); } # end case more than one rev specified } # main