Algorithm-Diff
view release on metacpan or search on metacpan
#
# Command-line arguments and context lines feature added
# September 1998 Amir D. Karger (karger@bead.aecom.yu.edu)
#
# In this file, "item" usually means "line of text", and "item number" usually
# means "line number". But theoretically the code could be used more generally
use strict;
use Algorithm::Diff qw(diff);
use File::stat;
use vars qw ($opt_C $opt_c $opt_u $opt_U);
use Getopt::Std;
my $usage = << "ENDUSAGE";
Usage: $0 [{-c | -u}] [{-C | -U} lines] oldfile newfile
-c will do a context diff with 3 lines of context
-C will do a context diff with 'lines' lines of context
-u will do a unified diff with 3 lines of context
-U will do a unified diff with 'lines' lines of context
ENDUSAGE
getopts('U:C:cu') or bag("$usage");
bag("$usage") unless @ARGV == 2;
my ($file1, $file2) = @ARGV;
if (defined $opt_C || defined $opt_c) {
$opt_c = ""; # -c on if -C given on command line
$opt_u = undef;
} elsif (defined $opt_U || defined $opt_u) {
$opt_u = ""; # -u on if -U given on command line
$opt_c = undef;
} else {
$opt_c = ""; # by default, do context diff, not old diff
}
my ($char1, $char2); # string to print before file names
my $Context_Lines; # lines of context to print
if (defined $opt_c) {
$Context_Lines = defined $opt_C ? $opt_C : 3;
$char1 = '*' x 3; $char2 = '-' x 3;
} elsif (defined $opt_u) {
$Context_Lines = defined $opt_U ? $opt_U : 3;
$char1 = '-' x 3; $char2 = '+' x 3;
}
# After we've read up to a certain point in each file, the number of items
# we've read from each file will differ by $FLD (could be 0)
my $File_Length_Difference = 0;
open (F1, $file1) or bag("Couldn't open $file1: $!");
open (F2, $file2) or bag("Couldn't open $file2: $!");
my (@f1, @f2);
chomp(@f1 = <F1>);
close F1;
chomp(@f2 = <F2>);
close F2;
# diff yields lots of pieces, each of which is basically a Block object
my $diffs = diff(\@f1, \@f2);
exit 0 unless @$diffs;
my $st = stat($file1);
print "$char1 $file1\t", scalar localtime($st->mtime), "\n";
$st = stat($file2);
print "$char2 $file2\t", scalar localtime($st->mtime), "\n";
my ($hunk,$oldhunk);
# Loop over hunks. If a hunk overlaps with the last hunk, join them.
# Otherwise, print out the old one.
foreach my $piece (@$diffs) {
$hunk = new Hunk ($piece, $Context_Lines);
next unless $oldhunk;
if ($hunk->does_overlap($oldhunk)) {
$hunk->prepend_hunk($oldhunk);
} else {
$oldhunk->output_diff(\@f1, \@f2);
}
} continue {
$oldhunk = $hunk;
}
# print the last hunk
$oldhunk->output_diff(\@f1, \@f2);
exit 1;
# END MAIN PROGRAM
sub bag {
my $msg = shift;
$msg .= "\n";
warn $msg;
exit 2;
}
# Package Hunk. A Hunk is a group of Blocks which overlap because of the
# context surrounding each block. (So if we're not using context, every
# hunk will contain one block.)
{
package Hunk;
sub new {
# Arg1 is output from &LCS::diff (which corresponds to one Block)
# Arg2 is the number of items (lines, e.g.,) of context around each block
#
# This subroutine changes $File_Length_Difference
#
# Fields in a Hunk:
# blocks - a list of Block objects
# start - index in file 1 where first block of the hunk starts
# end - index in file 1 where last block of the hunk ends
#
# Variables:
# before_diff - how much longer file 2 is than file 1 due to all hunks
# until but NOT including this one
# after_diff - difference due to all hunks including this one
my ($class, $piece, $context_items) = @_;
my $block = new Block ($piece); # this modifies $FLD!
my $before_diff = $File_Length_Difference; # BEFORE this hunk
my $after_diff = $before_diff + $block->{"length_diff"};
$File_Length_Difference += $block->{"length_diff"};
( run in 0.642 second using v1.01-cache-2.11-cpan-e1769b4cff6 )