Algorithm-Diff

 view release on metacpan or  search on metacpan

cdiff.pl  view on Meta::CPAN

#
# 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 )