diff options
Diffstat (limited to 'lib/File/Compare.pm')
-rw-r--r-- | lib/File/Compare.pm | 91 |
1 files changed, 64 insertions, 27 deletions
diff --git a/lib/File/Compare.pm b/lib/File/Compare.pm index 2f9c45c4c6..dce78e28ab 100644 --- a/lib/File/Compare.pm +++ b/lib/File/Compare.pm @@ -6,10 +6,10 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $Too_Big *FROM *TO); require Exporter; use Carp; -$VERSION = '1.1001'; +$VERSION = '1.1002'; @ISA = qw(Exporter); @EXPORT = qw(compare); -@EXPORT_OK = qw(cmp); +@EXPORT_OK = qw(cmp compare_text); $Too_Big = 1024 * 1024 * 2; @@ -22,13 +22,11 @@ sub compare { croak("Usage: compare( file1, file2 [, buffersize]) ") unless(@_ == 2 || @_ == 3); - my $from = shift; - my $to = shift; - my $closefrom=0; - my $closeto=0; - my ($size, $fromsize, $status, $fr, $tr, $fbuf, $tbuf); - local(*FROM, *TO); - local($\) = ''; + my ($from,$to,$size) = @_; + my $text_mode = defined($size) && (ref($size) eq 'CODE' || $size < 0); + + my ($fromsize,$closefrom,$closeto); + local (*FROM, *TO); croak("from undefined") unless (defined $from); croak("to undefined") unless (defined $to); @@ -40,9 +38,11 @@ sub compare { *FROM = $from; } else { open(FROM,"<$from") or goto fail_open1; - binmode FROM; + unless ($text_mode) { + binmode FROM; + $fromsize = -s FROM; + } $closefrom = 1; - $fromsize = -s FROM; } if (ref($to) && @@ -52,32 +52,45 @@ sub compare { *TO = $to; } else { open(TO,"<$to") or goto fail_open2; - binmode TO; + binmode TO unless $text_mode; $closeto = 1; } - if ($closefrom && $closeto) { + if (!$text_mode && $closefrom && $closeto) { # If both are opened files we know they differ if their size differ goto fail_inner if $fromsize != -s TO; } - if (@_) { - $size = shift(@_) + 0; - croak("Bad buffer size for compare: $size\n") unless ($size > 0); - } else { - $size = $fromsize; - $size = 1024 if ($size < 512); - $size = $Too_Big if ($size > $Too_Big); + if ($text_mode) { + local $/ = "\n"; + my ($fline,$tline); + while (defined($fline = <FROM>)) { + goto fail_inner unless defined($tline = <TO>); + if (ref $size) { + # $size contains ref to comparison function + goto fail_inner if &$size($fline, $tline); + } else { + goto fail_inner if $fline ne $tline; + } + } + goto fail_inner if defined($tline = <TO>); } + else { + unless (defined($size) && $size > 0) { + $size = $fromsize; + $size = 1024 if $size < 512; + $size = $Too_Big if $size > $Too_Big; + } - $fbuf = ''; - $tbuf = ''; - while(defined($fr = read(FROM,$fbuf,$size)) && $fr > 0) { - unless (defined($tr = read(TO,$tbuf,$fr)) and $tbuf eq $fbuf) { - goto fail_inner; + my ($fr,$tr,$fbuf,$tbuf); + $fbuf = $tbuf = ''; + while(defined($fr = read(FROM,$fbuf,$size)) && $fr > 0) { + unless (defined($tr = read(TO,$tbuf,$fr)) && $tbuf eq $fbuf) { + goto fail_inner; + } } + goto fail_inner if defined($tr = read(TO,$tbuf,$size)) && $tr > 0; } - goto fail_inner if (defined($tr = read(TO,$tbuf,$size)) && $tr > 0); close(TO) || goto fail_open2 if $closeto; close(FROM) || goto fail_open1 if $closefrom; @@ -93,7 +106,7 @@ sub compare { fail_open2: if ($closefrom) { - $status = $!; + my $status = $!; $! = 0; close FROM; $! = $status unless $!; @@ -104,6 +117,18 @@ sub compare { *cmp = \&compare; +sub compare_text { + my ($from,$to,$cmp) = @_; + croak("Usage: compare_text( file1, file2 [, cmp-function])") + unless @_ == 2 || @_ == 3; + croak("Third arg to compare_text() function must be a code reference") + if @_ == 3 && ref($cmp) ne 'CODE'; + + # Using a negative buffer size puts compare into text_mode too + $cmp = -1 unless defined $cmp; + compare($from, $to, $cmp); +} + 1; __END__ @@ -129,6 +154,18 @@ from File::Compare by default. File::Compare::cmp is a synonym for File::Compare::compare. It is exported from File::Compare only by request. +File::Compare::compare_text does a line by line comparison of the two +files. It stops as soon as a difference is detected. compare_text() +accepts an optional third argument: This must be a CODE reference to +a line comparison function, which returns 0 when both lines are considered +equal. For example: + + compare_text($file1, $file2) + +is basically equivalent to + + compare_text($file1, $file2, sub {$_[0] ne $_[1]} ) + =head1 RETURN File::Compare::compare return 0 if the files are equal, 1 if the |