Commit | Line | Data |
360aca43 |
1 | package TestCompare; |
2 | |
3 | use vars qw(@ISA @EXPORT $MYPKG); |
4 | #use strict; |
5 | #use diagnostics; |
6 | use Carp; |
7 | use Exporter; |
8 | use File::Basename; |
9 | use File::Spec; |
10 | |
11 | @ISA = qw(Exporter); |
12 | @EXPORT = qw(&testcmp); |
13 | $MYPKG = eval { (caller)[0] }; |
14 | |
15 | ##-------------------------------------------------------------------------- |
16 | |
17 | =head1 NAME |
18 | |
19 | testcmp -- compare two files line-by-line |
20 | |
21 | =head1 SYNOPSIS |
22 | |
23 | $is_diff = testcmp($file1, $file2); |
24 | |
25 | or |
26 | |
27 | $is_diff = testcmp({-cmplines => \&mycmp}, $file1, $file2); |
28 | |
29 | =head2 DESCRIPTION |
30 | |
31 | Compare two text files line-by-line and return 0 if they are the |
32 | same, 1 if they differ. Each of $file1 and $file2 may be a filenames, |
33 | or a filehandles (in which case it must already be open for reading). |
34 | |
35 | If the first argument is a hashref, then the B<-cmplines> key in the |
36 | hash may have a subroutine reference as its corresponding value. |
37 | The referenced user-defined subroutine should be a line-comparator |
38 | function that takes two pre-chomped text-lines as its arguments |
39 | (the first is from $file1 and the second is from $file2). It should |
40 | return 0 if it considers the two lines equivalent, and non-zero |
41 | otherwise. |
42 | |
43 | =cut |
44 | |
45 | ##-------------------------------------------------------------------------- |
46 | |
47 | sub testcmp( $ $ ; $) { |
48 | my %opts = ref($_[0]) eq 'HASH' ? %{shift()} : (); |
49 | my ($file1, $file2) = @_; |
50 | my ($fh1, $fh2) = ($file1, $file2); |
51 | unless (ref $fh1) { |
52 | $fh1 = FileHandle->new($file1, "r") or die "Can't open $file1: $!"; |
53 | } |
54 | unless (ref $fh2) { |
55 | $fh2 = FileHandle->new($file2, "r") or die "Can't open $file2: $!"; |
56 | } |
57 | |
58 | my $cmplines = $opts{'-cmplines'} || undef; |
59 | my ($f1text, $f2text) = ("", ""); |
60 | my ($line, $diffs) = (0, 0); |
61 | |
62 | while ( defined($f1text) and defined($f2text) ) { |
63 | defined($f1text = <$fh1>) and chomp($f1text); |
64 | defined($f2text = <$fh2>) and chomp($f2text); |
65 | ++$line; |
66 | last unless ( defined($f1text) and defined($f2text) ); |
67 | $diffs = (ref $cmplines) ? &$cmplines($f1text, $f2text) |
68 | : ($f1text ne $f2text); |
69 | last if $diffs; |
70 | } |
71 | close($fh1) unless (ref $file1); |
72 | close($fh2) unless (ref $file2); |
73 | |
74 | $diffs = 1 if (defined($f1text) or defined($f2text)); |
75 | if ( defined($f1text) and defined($f2text) ) { |
76 | ## these two lines must be different |
77 | warn "$file1 and $file2 differ at line $line\n"; |
78 | } |
79 | elsif (defined($f1text) and (! defined($f1text))) { |
80 | ## file1 must be shorter |
81 | warn "$file1 is shorter than $file2\n"; |
82 | } |
83 | elsif (defined $f2text) { |
84 | ## file2 must be longer |
85 | warn "$file1 is shorter than $file2\n"; |
86 | } |
87 | return $diffs; |
88 | } |
89 | |
90 | 1; |