#!/usr/bin/perl # # comparison-summary.pl # # Compares two files and produces an HTML document describing the # differences between the two files. # # Revision Control Information: # # $Id: comparison-summary.pl,v 1.1.1.1 1999/10/16 14:44:38 ctaylor Exp $ # # $Log: comparison-summary.pl,v $ # Revision 1.1.1.1 1999/10/16 14:44:38 ctaylor # Imported source # # # # Copyright 1999 by Charles L. Taylor # # This script may be copied and modified freely under the terms of the # GNU General Public License (GPL), provided this copyright notice appears # in all copies. # use integer; use strict; use vars qw ($MaxCols $AddLinks $NoAddIntro $AddLineNumbers $SummaryLineNum $StyleFile $PrecedeAdditions $FollowAdditions $PrecedeDeletions $FollowDeletions $file1 $file2 $line_segment_length); # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Document boilerplate generation subroutines # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # StartDocHeader # # Prints the first few lines of the document header. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # Upon completion of this subroutine's processing, there will be an # open STYLE element within an open HEAD element. # # Modification History: # 29 Sep 1999 - Created. CLT # sub StartDocHeader () { print << "STOP"; Comparison: $file1, $file2 STOP } # # PrintDocHeader # # Prints the document header. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub PrintDocHeader () { StartDocHeader (); if ($StyleFile ne "") { PrintStyleFromFile $StyleFile; } else { PrintStyle (); } FinishDocHeader (); } # # StartDocBody # # Prints the first few lines of the document body. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub StartDocBody () { print << "STOP";

Comparison Summary: $file1 vs. $file2

STOP } # # FinishDocBody # # Prints the last few lines of the document body. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub FinishDocBody () { print << "STOP"; STOP } # # WriteIntro # # Prints the document introduction. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub WriteIntro () { print << "STOP";

About This Document

This document provides an annotated comparison of the files $file1 and $file2. Specifically, it lists the additions and deletions made to $file1 in order to produce $file2.

It is recommended that you view this document in an HTML browser that supports cascading style sheets (CSS). Although additions and deletions are identified in the underlying HTML markup, most of the text annotations used to identify additions and deletions are visible only in a CSS-compliant browser.

Using Netscape Navigator version 4.x to print this document is not recommended, because Navigator's poor support for CSS may prevent document additions from being properly annotated in printed copies. Microsoft Internet Explorer version 3.x is not recommended for viewing or printing.

The examples below show how additions, deletions, and unchanged text are annotated in the document: $PrecedeAdditions

This is an addition.
$FollowAdditions
This is unchanged text that appears in both files.
$PrecedeDeletions
This is a deletion.
$FollowDeletions

Comparison Summary

STOP } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Command-line argument processing and user help subroutines # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # PrintHelp # # Prints a user help message. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub PrintHelp () { print << "STOP"; usage: comparison-summary [flags] file1 file2 flag summary: -col Limit summary listing to columns; currently $MaxCols -h, -help Print this message -links Add previous/next hyperlinks to each addition or deletion -nointro Suppress the "About This Document" introduction at the beginning of the document -number Add line numbers to the comparison summary -style Replace the default style definition with the contents of -v Verbose: Precede each addition with "(Added)" and each deletion with "(Deleted)" -vv Verbose: Same as -v, but also follow additions with "(End added)" and deletions with "(End deleted)" STOP } # # ProcessCommandLineArguments # # Reads the command-line arguments and sets variables accordingly. # # Parameters: # None. # # Return Value: # The subroutine returns zero if successful or -1 in the event # of failure. # # Remarks: # Default values for user-modifiable parameters are defined # in this routine. # # Modification History: # 29 Sep 1999 - Created. CLT # sub ProcessCommandLineArguments () { my ($i); # Parse arguments and get user preferences for ($i = 0; $i < scalar (@ARGV); $i++) { $_ = $ARGV[$i]; if (/^-col$/) { $i++; $MaxCols = int $ARGV[$i]; if ($MaxCols == 0) { print "Invalid maximum column setting: $MaxCols\n"; PrintHelp (); return -1; } } elsif (/^-h/) { PrintHelp (); return -1; } elsif (/^-links$/) { $AddLinks = 1; } elsif (/^-nointro$/) { $NoAddIntro = 1; } elsif (/^-number$/) { $AddLineNumbers = 1; } elsif (/^-style$/) { $i++; $StyleFile = $ARGV[$i]; # Temporary } elsif (/^-v$/) { $PrecedeAdditions = '

(Added)

'; $PrecedeDeletions = '

(Deleted)

'; } elsif (/^-vv$/) { $PrecedeAdditions = '

(Added)

'; $PrecedeDeletions = '

(Deleted)

'; $FollowAdditions = '

(End added)

'; $FollowDeletions = '

(End deleted)

'; } elsif (/^-.*$/) { print "Invalid flag $ARGV[$i]\n"; PrintHelp (); return -1; } elsif ($file1 eq "") { $file1 = $ARGV[$i]; } else { $file2 = $ARGV[$i]; } } if (($file1 eq "") || ($file2 eq "")) { PrintHelp (); return -1; } return 0; } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Input file comparison and summary production subroutines # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # DumpLine # # Prints the supplied line to standard output, preceding it with the # current line number if desired. # # Parameters: # TBD # # Return Value: # The subroutine does not return a value. # # Remarks: # This subroutine prepends the line number to the line, if the user # has requested line numbers. # # Modification History: # 02 Oct 1999 - Created. CLT # sub DumpLine { my ($line, $line_segment); # This routine also uses $line_segment_length as a persistent # variable. $SummaryLineNum++; $line = $_[0]; chomp $line; # Set $line_segment_length first time through the routine if ($line_segment_length == 0) { if ($AddLineNumbers != 0) { # The magic number seven indicates five places for # line numbers, a colon, and a space, for a total of # seven columns. $line_segment_length = int $MaxCols - 7; } else { $line_segment_length = int $MaxCols; } } $line_segment = substr ($line, 0, $line_segment_length); $line = substr ($line, $line_segment_length); # Convert characters that might confuse an HTML user agent to # valid HTML entities ($line_segment = $line_segment) =~ s{\&}{&}g; ($line_segment = $line_segment) =~ s{\<}{<}g; ($line_segment = $line_segment) =~ s{\>}{>}g; # Dump the line to output if ($AddLineNumbers != 0) { printf "%5d: %s\n", $SummaryLineNum, $line_segment; } else { print "$line_segment\n"; } while ($line ne "") { $line_segment = substr ($line, 0, $line_segment_length); $line = substr ($line, $line_segment_length); # Convert characters that might confuse an HTML user agent to # valid HTML entities ($line_segment = $line_segment) =~ s{\&}{&}g; ($line_segment = $line_segment) =~ s{\<}{<}g; ($line_segment = $line_segment) =~ s{\>}{>}g; # Dump the line to output if ($AddLineNumbers != 0) { print " $line_segment\n"; } else { print "$line_segment\n"; } } } # # GenerateSummary # # Opens the source files and an input stream representing diff's # output, then produces the comparison summary. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # The subroutine causes the script to exit immediately if # one of the files cannot be opened. # # Modification History: # 29 Sep 1999 - Created. CLT # sub GenerateSummary () { my ($difference, $current_diff, $ref_diff, $command, $following_line, $current_line, @cmdargs, $line, $i); open (FILE1, $file1) or die "Cannot open file $file1"; # Just make sure file2 is here. We won't be using it here, except # as input to diff. open (FILE2, $file2) or die "Cannot open file $file2"; close FILE2; open (DIFF, "diff -n $file1 $file2 |") or die "Cannot open diff"; $current_line = 0; $current_diff = 0; $difference = ; while ($difference) { $current_diff++; @cmdargs = split (/ /, $difference); $command = substr $cmdargs[0], 0, 1; $following_line = substr $cmdargs[0], 1; print "
\n";

        while ($current_line < ($following_line - 1)) {
            $current_line++;
            $line = ;
            DumpLine $line;
        }
        if ($command eq "a") {
            while ($current_line < $following_line) {
                $current_line++;
                $line = ;
                DumpLine $line;
            }
        }

        print "
\n"; if (($AddLinks != 0) && ($current_diff > 1)) { $ref_diff = $current_diff - 1; print "

"; print "[Previous change]

\n"; } if ($command eq "a") { # Add new lines as directed by diff's output print $PrecedeAdditions; print "
\n";
            for ($i = 0; $i < $cmdargs[1]; $i++) {
                # Don't increment $current_line here.
                $line = ;
                DumpLine $line;
            }
            print "
\n"; print $FollowAdditions; } elsif ($command eq "d") { # Show the deleted lines, beginning with the current line print $PrecedeDeletions; print "
\n";
            for ($i = 0; $i < $cmdargs[1]; $i++) {
                $current_line++;
                $line = ;
                DumpLine $line;
            }
            print "
\n"; print $FollowDeletions; } else { print "

I don't understand diff's output:\n"; print "

\n";
            print $difference;
            print "
\n"; } $difference = ; if (($AddLinks != 0) && ($difference)) { $ref_diff = $current_diff + 1; print "

"; print "[Next change]

\n"; } } print "
\n";

    while ($line = ) {
        $current_line++;
        DumpLine $line;
    }

    print "
\n"; close DIFF; close FILE1; } # # WriteDocument # # Compares the input files and produces the comparison document. # # Parameters: # None. # # Return Value: # The subroutine does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # sub WriteDocument () { PrintDocHeader (); StartDocBody (); if ($NoAddIntro == 0) { WriteIntro (); } GenerateSummary (); FinishDocBody (); } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Main routine # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # (Main entry point) # # Top-level executive routine for the script. # # Parameters: # None. # # Return Value: # The block does not return a value. # # Remarks: # # Modification History: # 29 Sep 1999 - Created. CLT # BEGIN { # Set default values $MaxCols = 80; $AddLinks = 0; $NoAddIntro = 0; $AddLineNumbers = 0; $SummaryLineNum = 0; $StyleFile = ""; $PrecedeAdditions = ""; $FollowAdditions = ""; $PrecedeDeletions = ""; $FollowDeletions = ""; # This variable is used only in DumpLine, but it is declared globally # so it will be persistent. It is initialized here and changed on # the first run through DumpLine. $line_segment_length = 0; if (ProcessCommandLineArguments () != 0) { exit; } WriteDocument (); }