2
# Copyright (C) 2005 MySQL AB
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; version 2 of the License.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
# This is a library file used by the Perl version of mysql-test-run,
18
# and is part of the translation of the Bourne shell script with the
24
# $Data::Dumper::Indent= 1;
28
##############################################################################
30
# This is a simplified unified diff, with some special handling
31
# of unsorted result sets
33
##############################################################################
35
# FIXME replace die with mtr_error
37
#require "mtr_report.pl";
38
#mtr_diff("a.txt","b.txt");
44
# ----------------------------------------------------------------------
45
# We read in all of the files at once
46
# ----------------------------------------------------------------------
48
unless ( open(FILE1, $file1) )
50
mtr_warning("can't open \"$file1\": $!");
54
unless ( open(FILE2, $file2) )
56
mtr_warning("can't open \"$file2\": $!");
60
my $lines1= collect_lines(<FILE1>);
61
my $lines2= collect_lines(<FILE2>);
65
# print Dumper($lines1);
66
# print Dumper($lines2);
68
# ----------------------------------------------------------------------
69
# We compare line by line, but don't shift off elements until we know
70
# what to do. This way we use the "restart" method, do simple change
71
# and restart by entering the diff loop from the beginning again.
72
# ----------------------------------------------------------------------
75
my @info; # Collect information, and output later
79
while ( @$lines1 or @$lines2 )
83
push(@info, map {['+',$lno1,$lno2++,$_]} @$lines2);
88
push(@info, map {['-',$lno1++,$lno2,$_]} @$lines1);
92
# ----------------------------------------------------------------------
93
# We know both have lines
94
# ----------------------------------------------------------------------
96
if ( $lines1->[0] eq $lines2->[0] )
98
# Simple case, first line match and all is well
99
push(@info, ['',$lno1++,$lno2++,$lines1->[0]]);
105
# ----------------------------------------------------------------------
106
# Now, we know they differ
107
# ----------------------------------------------------------------------
109
# How far in the other one, is there a match?
111
my $idx2= find_next_match($lines1->[0], $lines2);
112
my $idx1= find_next_match($lines2->[0], $lines1);
114
# Here we could test "if ( !defined $idx2 or !defined $idx1 )" and
115
# use a more complicated diff algorithm in the case both contains
116
# each others lines, just dislocated. But for this application, there
119
if ( !defined $idx2 )
121
push(@info, ['-',$lno1++,$lno2,$lines1->[0]]);
126
push(@info, ['+',$lno1,$lno2++,$lines2->[0]]);
131
# ----------------------------------------------------------------------
132
# Try to output nicely
133
# ----------------------------------------------------------------------
135
# print Dumper(\@info);
137
# We divide into "chunks" to output
138
# We want at least three lines of context
142
my $state= 'pre'; # 'pre', 'in' and 'post' difference
145
foreach my $info ( @info )
147
if ( $info->[0] eq '' and $state eq 'pre' )
149
# Collect no more than three lines of context before diff
151
shift(@chunk) if @chunk > 3;
155
if ( $info->[0] =~ /(\+|\-)/ and $state =~ /(pre|in)/ )
157
# Start/continue collecting diff
163
if ( $info->[0] eq '' and $state eq 'in' )
165
# Stop collecting diff, and collect context after diff
172
if ( $info->[0] eq '' and $state eq 'post' and $post_count < 6 )
174
# We might find a new diff sequence soon, continue to collect
175
# non diffs but five up on 6.
181
if ( $info->[0] eq '' and $state eq 'post' )
183
# We put an end to this, giving three non diff lines to
184
# the old chunk, and three to the new one.
185
my @left= splice(@chunk, -3, 3);
186
push(@chunks, [@chunk]);
193
if ( $info->[0] =~ /(\+|\-)/ and $state eq 'post' )
195
# We didn't split, continue collect diff
203
if ( $post_count > 3 )
206
splice(@chunk, -$post_count, $post_count);
208
push(@chunks, [@chunk]) if @chunk and $state ne 'pre';
210
foreach my $chunk ( @chunks )
212
my $from_file_start= $chunk->[0]->[1];
213
my $to_file_start= $chunk->[0]->[2];
214
my $from_file_offset= $chunk->[$#$chunk]->[1] - $from_file_start;
215
my $to_file_offset= $chunk->[$#$chunk]->[2] - $to_file_start;
216
print "\@\@ -$from_file_start,$from_file_offset ",
217
"+$to_file_start,$to_file_offset \@\@\n";
219
foreach my $info ( @$chunk )
221
if ( $info->[0] eq '' )
223
print " $info->[3]\n";
225
elsif ( $info->[0] eq '-' )
227
print "- $info->[3]\n";
229
elsif ( $info->[0] eq '+' )
231
print "+ $info->[3]\n";
236
# print Dumper(\@chunks);
241
##############################################################################
242
# Find if the string is found in the array, return the index if found,
243
# if not found, return "undef"
244
##############################################################################
246
sub find_next_match {
250
for ( my $idx= 0; $idx < @$lines; $idx++ )
252
return $idx if $lines->[$idx] eq $line;
255
return undef; # No match found
259
##############################################################################
260
# Just read the lines, but handle "sets" of lines that are unordered
261
##############################################################################
273
if ( $line =~ /^\Q%unordered%\E\t/ )
275
push(@recordset, $line);
279
push(@lines, sort @recordset);
280
@recordset= (); # Clear it
290
push(@lines, sort @recordset);
291
@recordset= (); # Clear it