=================================================================== RCS file: /cvs/cvsweb/cvsweb.cgi,v retrieving revision 1.1.1.5 retrieving revision 1.1.1.6 diff -u -p -r1.1.1.5 -r1.1.1.6 --- cvsweb/cvsweb.cgi 2000/09/04 16:00:28 1.1.1.5 +++ cvsweb/cvsweb.cgi 2000/09/19 20:14:40 1.1.1.6 @@ -9,6 +9,7 @@ # Ken Coar # Dick Balaska # Akinori MUSHA +# Jens-Uwe Mager # # Based on: # * Bill Fenners cvsweb.cgi revision 1.28 available from: @@ -41,8 +42,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $zId: cvsweb.cgi,v 1.94 2000/08/24 06:41:22 hnordstrom Exp $ -# $kId: cvsweb.cgi,v 1.19 2000/09/04 15:53:41 knu Exp $ +# $zId: cvsweb.cgi,v 1.101 2000/09/13 22:44:05 jumager Exp $ +# $kId: cvsweb.cgi,v 1.24 2000/09/19 20:07:16 knu Exp $ # ### @@ -76,19 +77,21 @@ use vars qw ( $navigationHeaderColor $tableBorderColor $markupLogColor $tabstop $state $annTable $sel $curbranch @HideModules $module $use_descriptions %descriptions @mytz $dwhere $moddate - $use_moddate + $use_moddate $has_zlib $gzip_open ); sub printDiffSelect($); sub findLastModifiedSubdirs(@); sub htmlify($;$); -sub spacedHtmlText($); +sub spacedHtmlText($;$); sub link($$); sub revcmp($$); sub fatal($$); sub redirect($); sub safeglob($); sub getMimeTypeFromSuffix($); +sub head($;$); +sub scan_directives(@); sub doAnnotate($$); sub doCheckout($$); sub cvswebMarkup($$$); @@ -160,6 +163,13 @@ $tabstop = $use_moddate = $moddate = undef; use Time::Local; use IPC::Open2; +# Check if the zlib C library interface is installed, and if yes +# we can avoid using the extra gzip process. +eval { + require Compress::Zlib; +}; +$has_zlib = !$@; + $verbose = $v; $checkoutMagic = "~checkout~"; $pathinfo = defined($ENV{PATH_INFO}) ? $ENV{PATH_INFO} : ''; @@ -197,13 +207,12 @@ $nofilelinks = $is_textbased; # braindamaged MS-Internet Exploders claim that they # accept gzip .. but don't in fact and # display garbage then :-/ -# Turn off gzip if running under mod_perl. piping does -# not work as expected inside the server. One can probably -# achieve the same result using Apache::GZIPFilter. +# Turn off gzip if running under mod_perl and no zlib is available, +# piping does not work as expected inside the server. $maycompress = (($ENV{HTTP_ACCEPT_ENCODING} =~ m`gzip` || $is_mozilla3) && !$is_msie - && !$is_mod_perl); + && !($is_mod_perl && !$has_zlib)); # put here the variables we need in order # to hold our state - they will be added (with @@ -359,7 +368,7 @@ $defaultViewable = $allow_markup && viewable($mimetype # ge get an Internal Server Error if we try to pipe the # output through the nonexistent gzip .. # any more elegant ways to prevent this are welcome! -if ($allow_compress && $maycompress) { +if ($allow_compress && $maycompress && !$has_zlib) { foreach (split(/:/, $ENV{PATH})) { if (-x "$_/gzip") { $GZIPBIN = "$_/gzip"; @@ -710,7 +719,8 @@ elsif (-d $fullname) { foreach my $var (@stickyvars) { print "\n" if (defined($input{$var}) - && $input{$var} ne $DEFAULTVALUE{$var} + && (!defined($DEFAULTVALUE{$var}) + || $input{$var} ne $DEFAULTVALUE{$var}) && $input{$var} ne "" && $var ne "only_with_tag"); } @@ -772,15 +782,18 @@ elsif (-d $fullname) { elsif (-f $fullname . ',v') { if (defined($input{'rev'}) || $doCheckout) { &doCheckout($fullname, $input{'rev'}); + close(GZIP) if ($gzip_open); exit; } if (defined($input{'annotate'}) && $allow_annotate) { &doAnnotate($input{'annotate'}); + close(GZIP) if ($gzip_open); exit; } if (defined($input{'r1'}) && defined($input{'r2'})) { &doDiff($fullname, $input{'r1'}, $input{'tr1'}, $input{'r2'}, $input{'tr2'}, $input{'f'}); + close(GZIP) if ($gzip_open); exit; } print("going to dolog($fullname)\n") if ($verbose); @@ -803,6 +816,7 @@ elsif (-d $fullname) { # e.g. foo.c &doDiff($fullname, $input{'r1'}, $input{'tr1'}, $input{'r2'}, $input{'tr2'}, $input{'f'}); + close(GZIP) if ($gzip_open); exit; } elsif (($newname = $fullname) =~ s|/([^/]+)$|/Attic/$1| && @@ -836,6 +850,8 @@ elsif (-d $fullname) { } &fatal("404 Not Found","$where: no such file or directory"); } + +close(GZIP) if ($gzip_open); ## End MAIN sub printDiffSelect($) { @@ -916,35 +932,32 @@ sub htmlify($;$) { return $string; } -sub spacedHtmlText($) { +sub spacedHtmlText($;$) { local $_ = $_[0]; + my $ts = $_[1] || $tabstop; - # Cut trailing spaces - s/\s+$/\n/; + # Cut trailing spaces and tabs + s/[ \t]+$//; - # Expand tabs - s/\t+/' ' x (length($&) * $tabstop - length($`) % $tabstop)/e - if (defined($tabstop)); + if (defined($ts)) { + # Expand tabs + 1 while s/\t+/' ' x (length($&) * $ts - length($`) % $ts)/e + } # replace and (\001 is to protect us from htmlify) # gzip can make excellent use of this repeating pattern :-) - s/\001/\001%/g; #protect our & substitute if ($hr_breakable) { # make every other space 'breakable' - s/ / \001nbsp; \001nbsp; \001nbsp; \001nbsp;/g; # s/ / \001nbsp;/g; # 2 * # leave single space as it is - } - else { - s/ /\001nbsp;\001nbsp;\001nbsp;\001nbsp;\001nbsp;\001nbsp;\001nbsp;\001nbsp;/g; + } else { s/ /\001nbsp;/g; } $_ = htmlify($_); # unescape - s/\001([^%])/&$1/g; - s/\001%/\001/g; + y/\001/&/; return $_; } @@ -1064,6 +1077,40 @@ sub getMimeTypeFromSuffix($) { } ############################### +# read first lines like head(1) +############################### +sub head($;$) { + my $fh = $_[0]; + my $linecount = $_[1] || 10; + + my @buf; + + if ($linecount > 0) { + my $i; + for ($i = 0; !eof($fh) && $i < $linecount; $i++) { + push @buf, scalar <$fh>; + } + } else { + @buf = <$fh>; + } + + @buf; +} + +############################### +# scan vim and Emacs directives +############################### +sub scan_directives(@) { + my $ts = undef; + + for (@_) { + $ts = $1 if /\b(?:ts|tabstop|tab-width)[:=]\s*([1-9]\d*)\b/; + } + + ('tabstop' => $ts); +} + +############################### # show Annotation ############################### sub doAnnotate($$) { @@ -1164,7 +1211,15 @@ sub doAnnotate($$) { else { print "
";
     }
-    while (<$reader>) {
+
+    # prefetch several lines
+    my @buf = head($reader);
+
+    my %d = scan_directives(@buf);
+
+    while (@buf || !eof($reader)) {
+	$_ = @buf ? shift @buf : <$reader>;
+
 	my @words = split;
 	# Adding one is for the (single) space which follows $words[0].
 	my $rest = substr ($_, length ($words[0]) + 1);
@@ -1198,7 +1253,7 @@ sub doAnnotate($$) {
 
 	    print "" if ($isCurrentRev);
 	    printf ("%8s%s%8s %4d:", $revprint, ($isCurrentRev ? "|" : " "), $usrprint, $lineNr);
-	    print spacedHtmlText($line);
+	    print spacedHtmlText($line, $d{'tabstop'});
 	    print "" if ($isCurrentRev);
 	}
 	elsif ($words[0] eq "ok") {
@@ -1341,16 +1396,26 @@ sub cvswebMarkup($$$) {
 	    $input{only_with_tag};
     }
     print "";
-    my @content = <$filehandle>;
     my $url = download_url($fileurl, $revision, $mimetype);
     print "
"; if ($mimetype =~ /^image/) { print "
"; } + elsif ($mimetype =~ m%^application/pdf%) { + print "
"; + } else { print "
";
-	foreach (@content) {
-	    print spacedHtmlText($_);
+
+	# prefetch several lines
+	my @buf = head($filehandle);
+
+	my %d = scan_directives(@buf);
+
+	while (@buf || !eof($filehandle)) {
+	    $_ = @buf ? shift @buf : <$filehandle>;
+
+	    print spacedHtmlText($_, $d{'tabstop'});
 	}
 	print "
"; } @@ -1359,7 +1424,7 @@ sub cvswebMarkup($$$) { sub viewable($) { my ($mimetype) = @_; - $mimetype =~ m%^(text|image)/%; + $mimetype =~ m%^((text|image)/|application/pdf)% ; } ############################### @@ -1457,6 +1522,7 @@ sub doDiff($$$$$$) { if ($human_readable) { http_header(); &human_readable_diff($fh, $rev2); + close(GZIP) if ($gzip_open); exit; } else { @@ -2126,40 +2192,42 @@ EOF foreach (@stickyvars) { print "\n" if (defined($input{$_}) - && ($input{$_} ne $DEFAULTVALUE{$_} && $input{$_} ne "")); + && ((!defined($DEFAULTVALUE{$_}) + || $input{$_} ne $DEFAULTVALUE{$_}) + && $input{$_} ne "")); } - print "Diffs between \n"; + print "\n"; + print ""; + print "\n"; + print ""; + print "\n"; print "\n"; + print "
Diffs between \n"; print "\n"; $diffrev = $revdisplayorder[$#revdisplayorder]; $diffrev = $input{"r1"} if (defined($input{"r1"})); - print "\n"; - print " and \n"; + print "
and \n"; print "\n"; $diffrev = $revdisplayorder[0]; $diffrev = $input{"r2"} if (defined($input{"r2"})); - print "\n"; - print "
Type of Diff should be a "; - printDiffSelect(0); - print "\n"; + print "
\n"; print "
\n"; + print ""; + print "\n"; + print ""; + print "\n"; if (@branchnames) { + print ""; + print "\n"; } - print "\n"; - print "\n"; foreach (@stickyvars) { + next if ($_ eq "f"); next if ($_ eq "only_with_tag"); next if ($_ eq "logsort"); print "\n" - if (defined($input{$_}) && $input{$_} ne $DEFAULTVALUE{$_} + if (defined($input{$_}) + && (!defined($DEFAULTVALUE{$_}) + || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne ""); } - print "Sort log by: \n"; - print ""; + print ""; + print ""; print "\n"; + print "
Preferred Diff type:"; + printDiffSelect($use_java_script); + print "
View only Branch:"; print "\n"; - print "\n"; - foreach (@stickyvars) { - next if ($_ eq "only_with_tag"); - next if ($_ eq "logsort"); - print "\n" - if (defined($input{$_}) && $input{$_} ne $DEFAULTVALUE{$_} - && $input{$_} ne ""); - } - print "View only Branch: \n"; print "\n"; - print "\n"; - print "\n"; + print "
"; + print "\n"; + print "Sort log by:\n"; - print "\n"; + print "
"; print &html_footer; print "\n"; } @@ -2235,7 +2305,7 @@ sub flush_diff_rows($$$$) { # human_readable_diff(String revision_to_return_to); ## sub human_readable_diff($){ - my ($i,$difftxt, $where_nd, $filename, $pathname, $scriptwhere_nd); + my ($difftxt, $where_nd, $filename, $pathname, $scriptwhere_nd); my ($fh, $rev) = @_; my ($date1, $date2, $r1d, $r2d, $r1r, $r2r, $rev1, $rev2, $sym1, $sym2); my (@rightCol, @leftCol); @@ -2289,9 +2359,15 @@ sub human_readable_diff($){ # cascading style sheets because we've to set the # font and color for each row. anyone ...? #### - while (<$fh>) { - $difftxt = $_; + # prefetch several lines + my @buf = head($fh); + + my %d = scan_directives(@buf); + + while (@buf || !eof($fh)) { + $difftxt = @buf ? shift @buf : <$fh>; + if ($difftxt =~ /^@@/) { ($oldline,$newline,$funname) = $difftxt =~ /@@ \-([0-9]+).*\+([0-9]+).*@@(.*)/; print ""; @@ -2307,7 +2383,7 @@ sub human_readable_diff($){ } else { ($diffcode,$rest) = $difftxt =~ /^([-+ ])(.*)/; - $_ = spacedHtmlText ($rest); + $_ = spacedHtmlText($rest, $d{'tabstop'}); # Add fontface, size $_ = "$fs $_$fe"; @@ -2391,7 +2467,7 @@ sub navigateHeader($$$$$) { $swhere = urlencode($filename) if ($swhere eq ""); print "<\!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"; print "\n\n"; - print ''; + print ''; print "\n$path$filename - $title - $rev\n"; print "\n"; print ""; @@ -2692,7 +2768,7 @@ sub http_header(;$) { my $content_type = shift || "text/html"; if (defined($moddate)) { if ($is_mod_perl) { - Apache->request->header_out(Last_modified => scalar gmtime($moddate) . " GMT"); + Apache->request->header_out("Last-Modified" => scalar gmtime($moddate) . " GMT"); } else { print "Last-Modified: " . scalar gmtime($moddate) . " GMT\r\n"; @@ -2705,8 +2781,7 @@ sub http_header(;$) { print "Content-type: $content_type\r\n"; } if ($allow_compress && $maycompress) { - my $fh = do {local(*FH);}; - if (defined($GZIPBIN) && open($fh, "|$GZIPBIN -1 -c")) { + if ($has_zlib || (defined($GZIPBIN) && open(GZIP, "|$GZIPBIN -1 -c"))) { if ($is_mod_perl) { Apache->request->content_encoding("x-gzip"); Apache->request->header_out(Vary => "Accept-Encoding"); @@ -2718,7 +2793,11 @@ sub http_header(;$) { print "\r\n"; # Close headers } $| = 1; $| = 0; # Flush header output - select ($fh); + if ($has_zlib) { + tie *GZIP, __PACKAGE__, \*STDOUT; + } + select(GZIP); + $gzip_open = 1; # print "" if ($content_type eq "text/html"); } else { @@ -2743,7 +2822,7 @@ sub http_header(;$) { sub html_header($) { my ($title) = @_; - my $version = '$zRevision: 1.94 $ $kRevision: 1.19 $'; #' + my $version = '$zRevision: 1.101 $ $kRevision: 1.24 $'; #' http_header(); print < Compress::Zlib::Z_BEST_COMPRESSION(), + -WindowBits => -Compress::Zlib::MAX_WBITS()) or return undef; + my ($o) = { + handle => $out, + dh => $d, + crc => 0, + len => 0, + }; + my ($header) = pack("c10", MAGIC1, MAGIC2, Compress::Zlib::Z_DEFLATED(), 0,0,0,0,0,0, OSCODE); + print {$o->{handle}} $header; + return bless($o, $class); +} + +sub PRINT { + my ($o) = shift; + my ($buf) = join(defined $, ? $, : "",@_); + my ($len) = length($buf); + my ($compressed, $status) = $o->{dh}->deflate($buf); + print {$o->{handle}} $compressed if defined($compressed); + $o->{crc} = Compress::Zlib::crc32($buf, $o->{crc}); + $o->{len} += $len; + return $len; +} + +sub PRINTF { + my ($o) = shift; + my ($fmt) = shift; + my ($buf) = sprintf($fmt, @_); + my ($len) = length($buf); + my ($compressed, $status) = $o->{dh}->deflate($buf); + print {$o->{handle}} $compressed if defined($compressed); + $o->{crc} = Compress::Zlib::crc32($buf, $o->{crc}); + $o->{len} += $len; + return $len; +} + +sub WRITE { + my ($o, $buf, $len, $off) = @_; + my ($compressed, $status) = $o->{dh}->deflate(substr($buf, 0, $len)); + print {$o->{handle}} $compressed if defined($compressed); + $o->{crc} = Compress::Zlib::crc32(substr($buf, 0, $len), $o->{crc}); + $o->{len} += $len; + return $len; +} + +sub CLOSE { + my ($o) = @_; + return if !defined( $o->{dh}); + my ($buf) = $o->{dh}->flush(); + $buf .= pack("V V", $o->{crc}, $o->{len}); + print {$o->{handle}} $buf; + undef $o->{dh}; +} + +sub DESTROY { + my ($o) = @_; + CLOSE($o); }