📄 diffnew.pl
字号:
#!/usr/bin/perl
#
# `Diff' program in Perl
# Copyright 1998 M-J. Dominus. (mjd-perl-diff@plover.com)
#
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
#
# Altered to output in `context diff' format (but without context)
# September 1998 Christian Murphy (cpm@muc.de)
#
# Context lines feature added
# Unified, "Old" (Standard UNIX), Ed diff added September 1998
# Reverse_Ed (-f option) added March 1999
# Amir D. Karger (karger@bead.aecom.yu.edu)
#
# Modular functions integrated into program
# February 1999 M-J. Dominus (mjd-perl-diff@plover.com)
#
# In this file, "item" usually means "line of text", and "item number" usually
# means "line number". But theoretically the code could be used more generally
use strict;
use Algorithm::Diff qw(diff);
# GLOBAL VARIABLES ####
# After we've read up to a certain point in each file, the number of items
# we've read from each file will differ by $FLD (could be 0)
my $File_Length_Difference = 0;
#ed diff outputs hunks *backwards*, so we need to save hunks when doing ed diff
my @Ed_Hunks = ();
########################
my $usage = << "ENDUSAGE";
Usage: $0 [{-c | -C lines -e | -f | -u | -U lines}] oldfile newfile
-c do a context diff with 3 lines of context
-C do a context diff with 'lines' lines of context (implies -c)
-e create a script for the ed editor to change oldfile to newfile
-f like -e but in reverse order
-u do a unified diff with 3 lines of context
-U do a unified diff with 'lines' lines of context (implies -u)
-q report only whether or not the files differ
By default it will do an "old-style" diff, with output like UNIX diff
ENDUSAGE
my $Context_Lines = 0; # lines of context to print. 0 for old-style diff
my $Diff_Type = "OLD"; # by default, do standard UNIX diff
my ($opt_c, $opt_u, $opt_e, $opt_f, $opt_q);
while ($ARGV[0] =~ /^-/) {
my $opt = shift;
last if $opt eq '--';
if ($opt =~ /^-C(.*)/) {
$Context_Lines = $1 || shift;
$opt_c = 1;
$Diff_Type = "CONTEXT";
} elsif ($opt =~ /^-c$/) {
$Context_Lines = 3;
$opt_c = 1;
$Diff_Type = "CONTEXT";
} elsif ($opt =~ /^-e$/) {
$opt_e = 1;
$Diff_Type = "ED";
} elsif ($opt =~ /^-f$/) {
$opt_f = 1;
$Diff_Type = "REVERSE_ED";
} elsif ($opt =~ /^-U(.*)$/) {
$Context_Lines = $1 || shift;
$opt_u = 1;
$Diff_Type = "UNIFIED";
} elsif ($opt =~ /^-u$/) {
$Context_Lines = 3;
$opt_u = 1;
$Diff_Type = "UNIFIED";
} elsif ($opt =~ /^-q$/) {
$Context_Lines = 0;
$opt_q = 1;
$opt_e = 1;
$Diff_Type = "ED";
} else {
$opt =~ s/^-//;
bag("Illegal option -- $opt");
}
}
if ($opt_q and grep($_,($opt_c, $opt_f, $opt_u)) > 1) {
bag("Combining -q with other options is nonsensical");
}
if (grep($_,($opt_c, $opt_e, $opt_f, $opt_u)) > 1) {
bag("Only one of -c, -u, -f, -e are allowed");
}
bag($usage) unless @ARGV == 2;
######## DO THE DIFF!
my ($file1, $file2) = @ARGV;
my ($char1, $char2); # string to print before file names
if ($Diff_Type eq "CONTEXT") {
$char1 = '*' x 3; $char2 = '-' x 3;
} elsif ($Diff_Type eq "UNIFIED") {
$char1 = '-' x 3; $char2 = '+' x 3;
}
open (F1, $file1) or bag("Couldn't open $file1: $!");
open (F2, $file2) or bag("Couldn't open $file2: $!");
my (@f1, @f2);
#Modify For Binnary File Diff
#chomp(@f1 = <F1>);
#数据区不参加比较.
while (<F1>)
{
chomp $_;
last if /Segment type:.Pure data/ ;
push @f1,$_;
}
close F1;
#Modify For Binnary File Diff
#chomp(@f2 = <F2>);
#数据区不参加比较.
while (<F2>)
{
chomp $_;
last if /Segment type:.Pure data/ ;
push @f2,$_;
}
close F2;
# diff yields lots of pieces, each of which is basically a Block object
#Modify For Binnary File Diff
#函数:MyKeyGen
#用途:根据汇编码特性产生对比关键字
sub MyKeyGen
{
my $str=shift @_; #str就是一行汇编语句
if($str =~ /\s*([^\s]+)\s+([^\s]+)/)
{
my $op1=$1; #第一个字段
my $op2=$2; #第二个字段
#如果是注释信息,以注释符号作比较关键字
if($op1 eq ";" || $op1 eq "#")
{
return $op1;
}
#如果第一个字段类似loc_0909则截取字符部分返回
if($op1 =~ /^([a-zA-Z:]+)_[0-9]/ )
{
return $1;
}
#如果第二个字段类似loc_0909则截掉数字部分
if($op2 =~ /^([a-zA-Z:]+)_[0-9]/ )
{
$op2=$1;
}
return $op1.$op2; #以前两个字段作为比较关键字
}
else
{
return $str;
}
}
my $diffs = diff(\@f1,\@f2,\&MyKeyGen);
exit 0 unless @$diffs;
if ($opt_q and @$diffs) {
print "Files $file1 and $file2 differ\n";
exit 1;
}
if ($Diff_Type =~ /UNIFIED|CONTEXT/) {
my @st = stat($file1);
my $MTIME = 9;
print "$char1 $file1\t", scalar localtime($st[$MTIME]), "\n";
@st = stat($file2);
print "$char2 $file2\t", scalar localtime($st[$MTIME]), "\n";
}
my ($hunk,$oldhunk);
# Loop over hunks. If a hunk overlaps with the last hunk, join them.
# Otherwise, print out the old one.
foreach my $piece (@$diffs) {
$hunk = new Hunk ($piece, $Context_Lines);
next unless $oldhunk; # first time through
# Don't need to check for overlap if blocks have no context lines
if ($Context_Lines && $hunk->does_overlap($oldhunk)) {
$hunk->prepend_hunk($oldhunk);
} else {
$oldhunk->output_diff(\@f1, \@f2, $Diff_Type);
}
} continue {
$oldhunk = $hunk;
}
# print the last hunk
$oldhunk->output_diff(\@f1, \@f2, $Diff_Type);
# Print hunks backwards if we're doing an ed diff
map {$_->output_ed_diff(\@f1, \@f2, $Diff_Type)} @Ed_Hunks if @Ed_Hunks;
exit 1;
# END MAIN PROGRAM
sub bag {
my $msg = shift;
$msg .= "\n";
warn $msg;
exit 2;
}
########
# Package Hunk. A Hunk is a group of Blocks which overlap because of the
# context surrounding each block. (So if we're not using context, every
# hunk will contain one block.)
{
package Hunk;
sub new {
# Arg1 is output from &LCS::diff (which corresponds to one Block)
# Arg2 is the number of items (lines, e.g.,) of context around each block
#
# This subroutine changes $File_Length_Difference
#
# Fields in a Hunk:
# blocks - a list of Block objects
# start - index in file 1 where first block of the hunk starts
# end - index in file 1 where last block of the hunk ends
#
# Variables:
# before_diff - how much longer file 2 is than file 1 due to all hunks
# until but NOT including this one
# after_diff - difference due to all hunks including this one
my ($class, $piece, $context_items) = @_;
my $block = new Block ($piece); # this modifies $FLD!
my $before_diff = $File_Length_Difference; # BEFORE this hunk
my $after_diff = $before_diff + $block->{"length_diff"};
$File_Length_Difference += $block->{"length_diff"};
# @remove_array and @insert_array hold the items to insert and remove
# Save the start & beginning of each array. If the array doesn't exist
# though (e.g., we're only adding items in this block), then figure
# out the line number based on the line number of the other file and
# the current difference in file lenghts
my @remove_array = $block->remove;
my @insert_array = $block->insert;
my ($a1, $a2, $b1, $b2, $start1, $start2, $end1, $end2);
$a1 = @remove_array ? $remove_array[0 ]->{"item_no"} : -1;
$a2 = @remove_array ? $remove_array[-1]->{"item_no"} : -1;
$b1 = @insert_array ? $insert_array[0 ]->{"item_no"} : -1;
$b2 = @insert_array ? $insert_array[-1]->{"item_no"} : -1;
$start1 = $a1 == -1 ? $b1 - $before_diff : $a1;
$end1 = $a2 == -1 ? $b2 - $after_diff : $a2;
$start2 = $b1 == -1 ? $a1 + $before_diff : $b1;
$end2 = $b2 == -1 ? $a2 + $after_diff : $b2;
# At first, a hunk will have just one Block in it
my $hunk = {
"start1" => $start1,
"start2" => $start2,
"end1" => $end1,
"end2" => $end2,
"blocks" => [$block],
};
bless $hunk, $class;
$hunk->flag_context($context_items);
return $hunk;
}
# Change the "start" and "end" fields to note that context should be added
# to this hunk
sub flag_context {
my ($hunk, $context_items) = @_;
return unless $context_items; # no context
# add context before
my $start1 = $hunk->{"start1"};
my $num_added = $context_items > $start1 ? $start1 : $context_items;
$hunk->{"start1"} -= $num_added;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -