X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FFile%2FCompare.pm;h=7418fe61e5280da866576e34addc770d8eaf990e;hb=196ac2fcd2dad2d042479c51fe09289545232c66;hp=a76eb1ff59363500e85769a5f3cca731e81c91af;hpb=387d8d95fa82cdff6ade378cc9e1e344c53f8918;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/File/Compare.pm b/lib/File/Compare.pm index a76eb1f..7418fe6 100644 --- a/lib/File/Compare.pm +++ b/lib/File/Compare.pm @@ -1,82 +1,97 @@ package File::Compare; +use 5.006; use strict; -use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $Too_Big *FROM *TO); +use warnings; +our($VERSION, @ISA, @EXPORT, @EXPORT_OK, $Too_Big); require Exporter; -use Carp; -use UNIVERSAL qw(isa); -$VERSION = '1.1001'; +$VERSION = '1.1005'; @ISA = qw(Exporter); @EXPORT = qw(compare); -@EXPORT_OK = qw(cmp); +@EXPORT_OK = qw(cmp compare_text); $Too_Big = 1024 * 1024 * 2; -sub VERSION { - # Version of File::Compare - return $File::Compare::VERSION; +sub croak { + require Carp; + goto &Carp::croak; } 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); - if (ref($from) && (isa($from,'GLOB') || isa($from,'IO::Handle'))) { + if (ref($from) && + (UNIVERSAL::isa($from,'GLOB') || UNIVERSAL::isa($from,'IO::Handle'))) { *FROM = *$from; } elsif (ref(\$from) eq 'GLOB') { *FROM = $from; } else { - open(FROM,"<$from") or goto fail_open1; - binmode FROM; + open(FROM,"<",$from) or goto fail_open1; + unless ($text_mode) { + binmode FROM; + $fromsize = -s FROM; + } $closefrom = 1; - $fromsize = -s FROM; } - if (ref($to) && (isa($to,'GLOB') || isa($to,'IO::Handle'))) { + if (ref($to) && + (UNIVERSAL::isa($to,'GLOB') || UNIVERSAL::isa($to,'IO::Handle'))) { *TO = *$to; } elsif (ref(\$to) eq 'GLOB') { *TO = $to; } else { - open(TO,"<$to") or goto fail_open2; - binmode TO; + open(TO,"<",$to) or goto fail_open2; + 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 = )) { + goto fail_inner unless defined($tline = ); + 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 = ); } + else { + unless (defined($size) && $size > 0) { + $size = $fromsize || -s TO || 0; + $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; @@ -92,7 +107,7 @@ sub compare { fail_open2: if ($closefrom) { - $status = $!; + my $status = $!; $! = 0; close FROM; $! = $status unless $!; @@ -101,8 +116,21 @@ sub compare { return -1; } +sub cmp; *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__ @@ -128,10 +156,22 @@ 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 -files are unequal, or -1 if an error was encountered. +File::Compare::compare and its sibling functions return 0 if the files +are equal, 1 if the files are unequal, or -1 if an error was encountered. =head1 AUTHOR