#!perl # -*- Perl -*- # Copyright 1999 Greg Spencer (greg_spencer@acm.org) ###################################################################### # # This is a "pretty printer" for code # it takes C++, etc. as input and outputs html with # highlighted keywords, etc. # ###################################################################### use p4Config; use p4Util; require SourceToHtml; use CGI; use LWP::MediaTypes; use HTTP::Date; # here is where we find out who did what... # this is only invoked if we're in detail mode. sub GetChangeInfo { my $file = shift; my $filesize = shift; my $nameref = shift; my $changeref = shift; # Handle # and @ notation (only for numeric changes and revisions). my $change = $1 if $file =~ s/\@(\d+)//; my $head = $1 if $file =~ s/\#(\d+)//; # Get the fullname of the file and the history, all from # the filelog for the file. my ($fullname, @history) = `p4 filelog $file`; chop($fullname); $fullname =~ s/\#.*//; my @fullname = split(m;/;, $fullname); # Extract the revision to change number mapping. Also # get the author of each revision, and for merged # or copied revisions, the "branch name", which we # use instead of an author. my %change,%author,%email,$thisrev,$headseen=0; for (@history) { if (/^\.\.\. \#(\d+) change (\d+) .*? by (.*?)@/) { # If a change number or revision is specified, then ignore # later revisions. next if $change && $change < $2; next if $head && $head < $1; $change{$1} = $2; $author{$1} = $3; $email{$3} = ""; $head = $1 if !$head; $thisrev = $1; $headseen = 1; } else { # If we see a branch from, then we know that # previous revisions did not contribute to the current # revision. Don't do this, however, if we haven't seen # the revision we've been requested to print, yet. # We used to do this for copy from, but I think # it's better not to. next unless $headseen; if (/^\.\.\. \.\.\. (copy|branch|merge) from (\/\/[^\#]*)\#(\d+)(?:,(\#\d+))?/) { # If merged or copied from another part of the # tree, then we use the first component of the # name that is different, and call that the "branch" # Further, we make the "author" be the name of the # branch. my($type) = $1; my($from) = $2; my($fromrev) = $4; $fromrev =~ s/\#/%23/g if $fromrev; $from=~s,^//depot/,,i; $author{$thisrev} = "$type"; $email{$author{$thisrev}} = ""; # If branched, we don't bother getting any more # history. We treat this as starting with the branch. last if $type eq 'branch'; } } } # Get first revision, and list of remaining revisions my ($base, @revs) = sort {$a <=> $b} keys %change; # For each line in the file, set the change revision # to be the base revision. my @lines = ($base) x $filesize; # For each revision from the base to the selected revision # "apply" the diffs by manipulating the array of revision # numbers. If lines are added, we add a corresponding # set of entries with the revision number that added it. # We ignore the actual revision text--that will be merged # with the change information later. for $rev (@revs) { my($r1) = $rev - 1; # Apply the diffs in reverse order to maintain correctness # of line numbers for each range as we apply it. for (reverse `p4 diff2 $file\#$r1 $file\#$rev`) { my( $la, $lb, $op, $ra, $rb ) = /^(\d+),?(\d*)([acd])(\d+),?(\d*)/; next unless defined($ra); $lb = $la if ! $lb; ++$la if $op eq 'a'; $rb = $ra if ! $rb; ++$ra if $op eq 'd'; splice @lines, $la - 1, $lb - $la + 1, ($rev) x ($rb - $ra + 1); } } # now we need to get the e-mail addresses of each of the users. # if the user doesn't exist anymore, then we don't link it. %users = p4Util::GetUserInfo(); foreach (keys %email) { if ($users{$_}) { $email{$_} = "$_"; } else { $email{$_} = $_; } } while (@lines) { my($rev) = shift(@lines); my($ch) = "$change{$rev}"; push (@{$changeref},$ch); push (@{$nameref},$email{$author{$rev}}); } } ###################################################################### # # Argument parsing # ###################################################################### $query = new CGI; $input_file = $query->path_info(); if (!$input_file) { my @param_keys = $query->keywords; $input_file=$param_keys[0]; } $input_file =~ s,^//depot,,; $input_file = "//depot".$input_file; $output_file="-"; # stdout $filename=""; @user_keys=(); $printdate=1; $use_lineno=1; $filter=0; $typename=""; $version = 0; $changenum = 0; # strip off version or change number and keep them. $version =$1 if ($input_file=~m/(\#\d*)$/); $changenum =$1 if ($input_file=~m/(\@\d*)$/); $filename = $input_file; $filename =~ s/[\#\@].*$//; $typename = $filename; # cgi path is where this script resides... ($cgipath = $0)=~ s:/([^/]+)$::; $scriptname = $1; if ($scriptname eq "$p4file2htmlName") { $detailmode = 0; } else { $detailmode = 1; } ###################################################################### # # Main # ###################################################################### if (!open(INPUT,"p4 print \"$input_file\" |")) { print "Status: 200 OK\n"; print "Content-type: text/html\n\n"; print "