mtr_diff.pl
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. # -*- cperl -*-
  2. # This is a library file used by the Perl version of mysql-test-run,
  3. # and is part of the translation of the Bourne shell script with the
  4. # same name.
  5. #use Data::Dumper;
  6. use strict;
  7. # $Data::Dumper::Indent= 1;
  8. sub mtr_diff($$);
  9. ##############################################################################
  10. #
  11. #  This is a simplified unified diff, with some special handling
  12. #  of unsorted result sets
  13. #
  14. ##############################################################################
  15. # FIXME replace die with mtr_error
  16. #require "mtr_report.pl";
  17. #mtr_diff("a.txt","b.txt");
  18. sub mtr_diff ($$) {
  19.   my $file1 = shift;
  20.   my $file2 = shift;
  21.   # ----------------------------------------------------------------------
  22.   # We read in all of the files at once
  23.   # ----------------------------------------------------------------------
  24.   unless ( open(FILE1, $file1) )
  25.   {
  26.     mtr_warning("can't open "$file1": $!");
  27.     return;
  28.   }
  29.   unless ( open(FILE2, $file2) )
  30.   {
  31.     mtr_warning("can't open "$file2": $!");
  32.     return;
  33.   }
  34.   my $lines1= collect_lines(<FILE1>);
  35.   my $lines2= collect_lines(<FILE2>);
  36.   close FILE1;
  37.   close FILE2;
  38. #  print Dumper($lines1);
  39. #  print Dumper($lines2);
  40.   # ----------------------------------------------------------------------
  41.   # We compare line by line, but don't shift off elements until we know
  42.   # what to do. This way we use the "restart" method, do simple change
  43.   # and restart by entering the diff loop from the beginning again.
  44.   # ----------------------------------------------------------------------
  45.   my @context;
  46.   my @info;                     # Collect information, and output later
  47.   my $lno1= 1;
  48.   my $lno2= 1;
  49.   while ( @$lines1 or @$lines2 )
  50.   {
  51.     unless ( @$lines1 )
  52.     {
  53.       push(@info, map {['+',$lno1,$lno2++,$_]} @$lines2);
  54.       last;
  55.     }
  56.     unless ( @$lines2 )
  57.     {
  58.       push(@info, map {['-',$lno1++,$lno2,$_]} @$lines1);
  59.       last;
  60.     }
  61.     # ----------------------------------------------------------------------
  62.     # We know both have lines
  63.     # ----------------------------------------------------------------------
  64.     if ( $lines1->[0] eq $lines2->[0] )
  65.     {
  66.       # Simple case, first line match and all is well
  67.       push(@info, ['',$lno1++,$lno2++,$lines1->[0]]);
  68.       shift @$lines1;
  69.       shift @$lines2;
  70.       next;
  71.     }
  72.     # ----------------------------------------------------------------------
  73.     # Now, we know they differ
  74.     # ----------------------------------------------------------------------
  75.     # How far in the other one, is there a match?
  76.     my $idx2= find_next_match($lines1->[0], $lines2);
  77.     my $idx1= find_next_match($lines2->[0], $lines1);
  78.     # Here we could test "if ( !defined $idx2 or !defined $idx1 )" and
  79.     # use a more complicated diff algorithm in the case both contains
  80.     # each others lines, just dislocated. But for this application, there
  81.     # should be no need.
  82.     if ( !defined $idx2 )
  83.     {
  84.       push(@info, ['-',$lno1++,$lno2,$lines1->[0]]);
  85.       shift @$lines1;
  86.     }
  87.     else
  88.     {
  89.       push(@info, ['+',$lno1,$lno2++,$lines2->[0]]);
  90.       shift @$lines2;
  91.     }
  92.   }
  93.   # ----------------------------------------------------------------------
  94.   # Try to output nicely
  95.   # ----------------------------------------------------------------------
  96. #  print Dumper(@info);
  97.   # We divide into "chunks" to output
  98.   # We want at least three lines of context
  99.   my @chunks;
  100.   my @chunk;
  101.   my $state= 'pre';          # 'pre', 'in' and 'post' difference
  102.   my $post_count= 0;
  103.   foreach my $info ( @info )
  104.   {
  105.     if ( $info->[0] eq '' and $state eq 'pre' )
  106.     {
  107.       # Collect no more than three lines of context before diff
  108.       push(@chunk, $info);
  109.       shift(@chunk) if @chunk > 3;
  110.       next;
  111.     }
  112.     if ( $info->[0] =~ /(+|-)/ and $state =~ /(pre|in)/ )
  113.     {
  114.       # Start/continue collecting diff
  115.       $state= 'in';
  116.       push(@chunk, $info);
  117.       next;
  118.     }
  119.     if ( $info->[0] eq '' and $state eq 'in' )
  120.     {
  121.       # Stop collecting diff, and collect context after diff
  122.       $state= 'post';
  123.       $post_count= 1;
  124.       push(@chunk, $info);
  125.       next;
  126.     }
  127.     if ( $info->[0] eq '' and $state eq 'post' and $post_count < 6 )
  128.     {
  129.       # We might find a new diff sequence soon, continue to collect
  130.       # non diffs but five up on 6.
  131.       $post_count++;
  132.       push(@chunk, $info);
  133.       next;
  134.     }
  135.     if ( $info->[0] eq '' and $state eq 'post' )
  136.     {
  137.       # We put an end to this, giving three non diff lines to
  138.       # the old chunk, and three to the new one.
  139.       my @left= splice(@chunk, -3, 3);
  140.       push(@chunks, [@chunk]);
  141.       $state= 'pre';
  142.       $post_count= 0;
  143.       @chunk= @left;
  144.       next;
  145.     }
  146.     if ( $info->[0] =~ /(+|-)/ and $state eq 'post' )
  147.     {
  148.       # We didn't split, continue collect diff
  149.       $state= 'in';
  150.       push(@chunk, $info);
  151.       next;
  152.     }
  153.   }
  154.   if ( $post_count > 3 )
  155.   {
  156.     $post_count -= 3;
  157.     splice(@chunk, -$post_count, $post_count);
  158.   }
  159.   push(@chunks, [@chunk]) if @chunk and $state ne 'pre';
  160.   foreach my $chunk ( @chunks )
  161.   {
  162.     my $from_file_start=  $chunk->[0]->[1];
  163.     my $to_file_start=    $chunk->[0]->[2];
  164.     my $from_file_offset= $chunk->[$#$chunk]->[1] - $from_file_start;
  165.     my $to_file_offset=   $chunk->[$#$chunk]->[2] - $to_file_start;
  166.     print "@@ -$from_file_start,$from_file_offset ",
  167.           "+$to_file_start,$to_file_offset @@n";
  168.     foreach my $info ( @$chunk )
  169.     {
  170.       if ( $info->[0] eq '' )
  171.       {
  172.         print "  $info->[3]n";
  173.       }
  174.       elsif ( $info->[0] eq '-' )
  175.       {
  176.         print "- $info->[3]n";
  177.       }
  178.       elsif ( $info->[0] eq '+' )
  179.       {
  180.         print "+ $info->[3]n";
  181.       }
  182.     }
  183.   }
  184. #  print Dumper(@chunks);
  185.   
  186. }
  187. ##############################################################################
  188. #  Find if the string is found in the array, return the index if found,
  189. #  if not found, return "undef"
  190. ##############################################################################
  191. sub find_next_match {
  192.   my $line= shift;
  193.   my $lines= shift;
  194.   for ( my $idx= 0; $idx < @$lines; $idx++ )
  195.   {
  196.     return $idx if $lines->[$idx] eq $line;
  197.   }
  198.   return undef;                 # No match found
  199. }
  200. ##############################################################################
  201. #  Just read the lines, but handle "sets" of lines that are unordered
  202. ##############################################################################
  203. sub collect_lines {
  204.   my @recordset;
  205.   my @lines;
  206.   while (@_)
  207.   {
  208.     my $line= shift @_;
  209.     chomp($line);
  210.     if ( $line =~ /^Q%unordered%Et/ )
  211.     {
  212.       push(@recordset, $line);
  213.     }
  214.     elsif ( @recordset )
  215.     {
  216.       push(@lines, sort @recordset);
  217.       @recordset= ();         # Clear it
  218.     }
  219.     else
  220.     {
  221.       push(@lines, $line);
  222.     }
  223.   }
  224.   if ( @recordset )
  225.   {
  226.     push(@lines, sort @recordset);
  227.     @recordset= ();         # Clear it
  228.   }
  229.   return @lines;
  230. }
  231. 1;