#!/usr/local/bin/perl5 # -*- perl -*- use P4CGI ; use strict ; # ##################################################################### ## ## CONFIGURATION INFORMATION ## All config info should be in $configFile (see init() in P4CGI.pm) ## ##################################################################### ## ## File Diff Viewer ## ##################################################################### # Set back references my $homepage="index.cgi"; my $backtohome="Back to Home" ; # Get filespec argument my @files = split /,/,P4CGI::cgi()->param("FSPC") ; &P4CGI::bail("No file specified") unless @files > 0 ; # Get revision number my @revs = split / /,P4CGI::cgi()->param("REV") ; $files[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs[0] = $2 ; } ; &P4CGI::bail("No revision specified") unless @revs > 0 ; # Get action my @modes ; @modes = split / /,P4CGI::cgi()->param("ACT") if defined P4CGI::cgi()->param("ACT") ; &P4CGI::bail("No mode specified") unless @modes > 0 ; # Get list of restricted files, if any my @restrict = &P4CGI::RESTRICTED() ; # Disallow viewing restricted files (single-file case) if( @files == 1 ) { my $file = $files[0] ; if( @restrict ) { my $restricted ; foreach $restricted ( @restrict ) { chomp ; if ( $file =~ /\/${restricted}/ ) { my $legend = "" ; print "", &P4CGI::start_page("Diff Output",$legend,$homepage,$backtohome) ; print "", "<font color=red>Restricted file:</font> <font color=green> $file</font>", &P4CGI::end_page() ; exit 1 ; } } } } # Get diff-file arg and rev, if specified my @files2 ; @files2 = split /,/,P4CGI::cgi()->param("FSPC2") if defined P4CGI::cgi()->param("FSPC2") ; my @revs2 ; @revs2 = split / /,P4CGI::cgi()->param("REV2") if defined P4CGI::cgi()->param("REV2") ; if(defined $files2[0]) { $files2[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs2[0] = $2 ; } ; } ; my $change = P4CGI::cgi()->param("CH") ; # Disallow viewing restricted files (multi-file case) my $skipfile ; my @skipfiles ; my @showfiles ; my @showrevs ; while ( @files ) { my $file = shift @files ; my $rev = shift @revs ; if( @restrict ) { my $restricted ; foreach $restricted ( @restrict ) { chomp ; if ( $file =~ /\/${restricted}/ ) { push ( @skipfiles, $file ) ; next ; } } if( grep(/${file}/, @skipfiles) ) { next ; } else { push ( @showfiles, $file ) ; push ( @showrevs, $rev ) ; } } } # Associate the files/revs to diff my $n ; for($n = 0 ; $n < @showfiles ; $n++) { $files2[$n] = $showfiles[$n] unless defined $files2[$n] ; $revs2[$n] = $showrevs[$n]-1 unless defined $revs2[$n] ; } # Make sure numbers of files and revision numbers match if((@showfiles != @showrevs) || (@showfiles != @files2) || (@showfiles != @revs2)) { &P4CGI::bail("Argument counts not correct") ; } ## Constants for the file diff display # # $NCONTEXT - number of context lines before and after a diff my $NCONTEXT = P4CGI::cgi()->param("CONTEXT") ; $NCONTEXT = 10 unless defined $NCONTEXT ; # # $MAXCONTEXT - max number of context lines between diffs my $MAXCONTEXT = $NCONTEXT+20; # Put it all together local *LOG ; open(*LOG,">>fdv.LOG") ; print LOG "\n ------------\n" ; my $title ; if(@showfiles == 1) { if($showfiles[0] eq $files2[0]) { if($showrevs[0] < $revs2[0]) { my $r = $revs2[0] ; $revs2[0] = $showrevs[0] ; $showrevs[0] = $r ; } $title = "Diff Output" ; } else { $title = "Diff Output" ; } } else { $title = "Diff Output" ; } my $nextNCONTEXT= $NCONTEXT*2 ; my $pstr ; my $p ; foreach $p (&P4CGI::cgi()->param) { next if $p eq "CONTEXT" ; if(defined $pstr) { $pstr .= "&" ; } else { $pstr = "" ; } ; $pstr .= $p . "=" . P4CGI::cgi()->param($p) ; } my $moreContext=&P4CGI::ahref($pstr, "CONTEXT=$nextNCONTEXT", "Show more context") ; my $showWholeFile=&P4CGI::ahref($pstr, "CONTEXT=9999999", "Show complete file") ; # Print title and legend if( $modes[0] ne "NO" ) { print "", &P4CGI::start_page($title, &P4CGI::ul_list("<b>Line number:</b> to go to line in file viewer", "<hr>", "<b>$moreContext:</b> to see more context", "<b>$showWholeFile:</b> to see whole file"), $homepage,$backtohome) ; } else { print "", &P4CGI::start_page($title, "", $homepage, $backtohome) ; } my $currentFile ; my $currentRev ; local *P4 ; my $P4lineNo ; sub getLine() { $P4lineNo++ if defined $P4lineNo ; return <P4> ; } # Print count and list of skipped files my $skipfile ; my $skipped = scalar( @skipfiles ) ; if( $skipped > 0 ) { print "", "Change contains <b>$skipped</b> <font color=red>restricted</font> file", $skipped==1 ? "" : "s", ".<br>", "Not diffed:<br>" ; foreach $skipfile ( @skipfiles ) { print " ", "<font color=green>$skipfile</font>", "<br>" ; } print "<hr>" ; } # Print diffs while(@showfiles>0) { my $f1start= "<font color=blue>" ; my $f1end="</font>" ; my $f2start = "<font color=red><strike>" ; my $f2end = "</strike></font>" ; my $showfile = shift @showfiles ; my $file2 = shift @files2 ; my $showrev = shift @showrevs ; my $rev2 = shift @revs2 ; my $mode = shift @modes ; if($showfile eq $file2) { if($showrev < $rev2) { my $r = $rev2 ; $rev2 = $showrev ; $showrev = $r ; } } else { $f2start = "<font color=green>" ; $f2end = "</font>" ; } $currentFile = $showfile ; $currentRev = $showrev ; print &P4CGI::start_table("width=100% align=center bgcolor=white"), &P4CGI::table_row({-align=>"center", -text =>"<big>$f1start$showfile\#$showrev$f1end<br>$f2start$file2\#$rev2$f2end</big>"}), &P4CGI::end_table(), "<pre>" ; my $f1 = "$showfile#$showrev"; my $f2 = "$file2#$rev2"; # Use "p4 diff2" to get a list of modifications (diff chunks) my $nchunk =0 ; # Counter for diff chunks my @start ; # Start line for chunk in latest file my @dels ; # No. of deleted lines in chunk my @adds ; # No. of added lines in chunk my @delLines ; # Memory for deleted lines if ($mode ne 'add' && $mode ne 'delete' && $mode ne 'branch') { &P4CGI::p4call(*P4, "diff2 \"$f2\" \"$f1\"" ); $_ = <P4>; while (<P4>) { # Check if line matches start of a diff chunk /(\d+),?(\d*)([acd])(\d+),?(\d*)/ or do { next ; } ; # $la, $lb: start and end line in old (left) file # $op: operation (one of a,d or c) # $ra, $rb: start and end line in new (right) file my ( $la, $lb, $op, $ra, $rb ) = ($1,$2,$3,$4,$5) ; # End lines may have to be calculated if( !$lb ) { $lb = $op ne 'a' ? $la : $la - 1; } if( !$rb ) { $rb = $op ne 'd' ? $ra : $ra - 1; } my ( $dels, $adds ); # Temporary vars for No of adds/deletes # Calculate start position in new (right) file $start[ $nchunk ] = $op ne 'd' ? $ra : $ra + 1; # Calculate number of deleted lines $dels[ $nchunk ] = $dels = $lb - $la + 1; # Calculate number of added lines $adds[ $nchunk ] = $adds = $rb - $ra + 1; # Init deleted lines $delLines[ $nchunk ] = ""; # Get the deleted lines from the old (left) file while( $dels-- ) { $_ = <P4>; s/^. //; $_ = &P4CGI::fixSpecChar($_) ; $delLines[ $nchunk ] .= "<small> </small> <font color=red>|</font>$_"; } # If it was a change, skip over separator if ($op eq 'c') { $_ = <P4>; } # Skip over added lines (we don't need to know them yet) while( $adds-- ) { $_ = <P4>; } # Next chunk. $nchunk++; } close P4; } # Now walk through the diff chunks, reading the new (right) file and # displaying it as necessary. &P4CGI::p4call(*P4, "print -q \"$f1\""); if( $mode eq 'add' ) { print "<font color=blue>" ; while( <P4> ) { print "<small> </small> <font color=red>|</font>$_" ; } print "</font>" ; } $P4lineNo = 0 ; # Current line my $n ; for( $n = 0; $n < $nchunk; $n++ ) { # print up to this chunk. &catchup( $start[ $n ] - $P4lineNo - 1 ) ; # display deleted lines -- we saved these from the diff if( $dels[ $n ] ) { print LOG "PrintDels\n" ; print "$f2start"; print $delLines[ $n ]; print "$f2end"; } # display added lines -- these are in the file stream. if( $adds[ $n ] ) { print "$f1start"; &display($adds[ $n ]) ; print "$f1end"; } # $curlin = $start[ $n ] + $adds[ $n ] ; } &catchup(999999999) ; close P4 ; print "</pre>" ; } # End the page print &P4CGI::end_page() ; # Subroutines for processing diff chunks. # # skip: skip lines in source file # display: display lines in source file, handling funny chars # catchup: display & skip as necessary # skip(<handle>,no of lines) # Returns: 0 or number of lines not skipped if file ends sub skip { my $to = shift @_; print LOG "skip($to)\n" ; # DEBUG while( $to > 0 && ( $_ = &getLine() ) ) { $to--; } return $to; } # display(<handle>,no of lines) # Displays a number of lines from handle sub display { my $to = shift @_; print LOG "display($to)\n" ; # DEBUG while( $to-- > 0 && ( $_ = &getLine() ) ) { my $line = &P4CGI::fixSpecChar($_) ; $line = &P4CGI::rmTabs($line) ; my $ls ; if(($P4lineNo % 5) == 0) { $ls = sprintf("<small>%5d:</small>",$P4lineNo) ; $ls = &P4CGI::ahref(-url=>&P4CGI::FV_URL() . "#L$P4lineNo", "FSPC=$currentFile", "REV=$currentRev", $ls) ; } else { $ls = "<small> </small>" ; } print "$ls <font color=red>|</font>$line" ; } } # catchup(<handle>,no of lines) # Print/skip lines to next diff chunk sub catchup { my $to = shift @_; print LOG "catchup($to)\n" ; # DEBUG if( $to > $MAXCONTEXT ) { my $skipped = $to - $NCONTEXT ; if($P4lineNo > 0) { &display($NCONTEXT ); $skipped -= $NCONTEXT ; } $skipped -= &skip($skipped ); print "<hr><center><strong>", "$skipped lines skipped", "</strong></center><hr>\n" if( $skipped ); &display($NCONTEXT ); } else { &display($to); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 278 | Diane Holt | Fix printing diff on "add". | ||
#1 | 271 | Diane Holt |
The Perl files for P4DB. These (almost) match the files in rev 1 of the p4db.tar file -- a few files have some minor cosmetic changes in the code, and chv.cgi has a Legend item added that was missing in the one in the tar-file. These files, at rev 1 (and the files in p4db.tar at rev 1), are suitable for for running the app with release 98.2 of P4. |