=================================================================== RCS file: /cvs/cvsweb/cvsweb.cgi,v retrieving revision 3.18 retrieving revision 3.36 diff -u -p -r3.18 -r3.36 --- cvsweb/cvsweb.cgi 2000/09/04 14:50:22 3.18 +++ cvsweb/cvsweb.cgi 2000/10/20 12:28:45 3.36 @@ -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 $ -# $Id: cvsweb.cgi,v 3.18 2000/09/04 14:50:22 knu Exp $ +# $zId: cvsweb.cgi,v 1.103 2000/09/20 17:02:29 jumager Exp $ +# $Id: cvsweb.cgi,v 3.36 2000/10/20 12:28:45 knu Exp $ # ### @@ -58,13 +59,14 @@ use vars qw ( $checkoutMagic $doCheckout $scriptname $scriptwhere $where $pathinfo $Browser $nofilelinks $maycompress @stickyvars %funcline_regexp $is_mod_perl - $is_lynx $is_w3m $is_msie $is_mozilla3 $is_textbased + $is_links $is_lynx $is_w3m $is_msie $is_mozilla3 $is_textbased %input $query $barequery $sortby $bydate $byrev $byauthor $bylog $byfile $hr_default $logsort $cvstree $cvsroot $mimetype $defaultTextPlain $defaultViewable $allow_compress $GZIPBIN $backicon $diricon $fileicon $fullname $newname - $cvstreedefault $body_tag $logo $defaulttitle $address - $backcolor $long_intro $short_instruction $shortLogLen + $cvstreedefault $body_tag $body_tag_for_src + $logo $defaulttitle $address + $long_intro $short_instruction $shortLogLen $show_author $dirtable $tablepadding $columnHeaderColorDefault $columnHeaderColorSorted $hr_breakable $showfunc $hr_ignwhite $hr_ignkeysubst $diffcolorHeading $diffcolorEmpty $diffcolorRemove @@ -72,23 +74,27 @@ use vars qw ( $difffontsize $inputTextSize $mime_types $allow_annotate $allow_markup $use_java_script $open_extern_window $extern_window_width $extern_window_height $edit_option_form - $checkout_magic $show_subdir_lastmod $show_log_in_markup $v + $show_subdir_lastmod $show_log_in_markup $v $navigationHeaderColor $tableBorderColor $markupLogColor $tabstop $state $annTable $sel $curbranch @HideModules $module $use_descriptions %descriptions @mytz $dwhere $moddate - $use_moddate + $use_moddate $has_zlib $gzip_open + $LOG_FILESEPARATOR $LOG_REVSEPARATOR ); sub printDiffSelect($); sub findLastModifiedSubdirs(@); +sub htmlify_sub(&$); 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($$$); @@ -111,6 +117,8 @@ sub download_url($$;$); sub download_link($$$;$); sub toggleQuery($$); sub urlencode($); +sub htmlquote($); +sub htmlunquote($); sub http_header(;$); sub html_header($); sub html_footer(); @@ -121,14 +129,13 @@ sub forbidden_module($); use Cwd; # == EDIT this == -# User configuration is stored in -$config = undef; - -for ($ENV{CVSWEB_CONFIG}, -# '/home/knu/etc/cvsweb.conf', +# Locations to search for user configuration, in order: +for ( + $ENV{CVSWEB_CONFIG}, '/usr/local/etc/cvsweb.conf', - getcwd . '/cvsweb.conf') { - $config = $_ if defined($_) && -r $_; + getcwd() . '/cvsweb.conf' + ) { + $config = $_ if defined($_) && -r $_; } # == Configuration defaults == @@ -142,8 +149,9 @@ $allow_version_select = 1; # These are defined to allow checking with perl -cw %CVSROOT = %MIRRORS = %DEFAULTVALUE = %ICONS = %MTYPES = %tags = %alltags = @tabcolors = (); -$cvstreedefault = $body_tag = $logo = $defaulttitle = $address = -$backcolor = $long_intro = $short_instruction = $shortLogLen = +$cvstreedefault = $body_tag = $body_tag_for_src = +$logo = $defaulttitle = $address = +$long_intro = $short_instruction = $shortLogLen = $show_author = $dirtable = $tablepadding = $columnHeaderColorDefault = $columnHeaderColorSorted = $hr_breakable = $showfunc = $hr_ignwhite = $hr_ignkeysubst = $diffcolorHeading = $diffcolorEmpty = $diffcolorRemove = @@ -151,15 +159,25 @@ $diffcolorChange = $diffcolorAdd = $diffcolorDarkChang $difffontsize = $inputTextSize = $mime_types = $allow_annotate = $allow_markup = $use_java_script = $open_extern_window = $extern_window_width = $extern_window_height = $edit_option_form = -$checkout_magic = $show_subdir_lastmod = $show_log_in_markup = $v = +$show_subdir_lastmod = $show_log_in_markup = $v = $navigationHeaderColor = $tableBorderColor = $markupLogColor = -$tabstop = $use_moddate = $moddate = undef; +$tabstop = $use_moddate = $moddate = $gzip_open = undef; +$LOG_FILESEPARATOR = q/^={77}$/; +$LOG_REVSEPARATOR = q/^-{28}$/; + ##### End of configuration variables ##### 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} : ''; @@ -181,12 +199,13 @@ $is_mod_perl = defined($ENV{MOD_PERL}); # per file, so disable the link at the icon # in this case: $Browser = $ENV{HTTP_USER_AGENT}; +$is_links = ($Browser =~ m`^Links `); $is_lynx = ($Browser =~ m`^Lynx/`i); $is_w3m = ($Browser =~ m`^w3m/`i); $is_msie = ($Browser =~ m`MSIE`); $is_mozilla3 = ($Browser =~ m`^Mozilla/[3-9]`); -$is_textbased = ($is_lynx || $is_w3m); +$is_textbased = ($is_links || $is_lynx || $is_w3m); $nofilelinks = $is_textbased; @@ -197,13 +216,13 @@ $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. -$maycompress = (($ENV{HTTP_ACCEPT_ENCODING} =~ m`gzip` +# Turn off gzip if running under mod_perl and no zlib is available, +# piping does not work as expected inside the server. +$maycompress = (((defined($ENV{HTTP_ACCEPT_ENCODING}) + && $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 @@ -212,9 +231,11 @@ $maycompress = (($ENV{HTTP_ACCEPT_ENCODING} =~ m`gzip` @stickyvars = qw(cvsroot hideattic sortby logsort f only_with_tag); if (-f $config) { - do $config; -} -else { + do $config + || &fatal("500 Internal Error", + sprintf('Error in loading configuration file: %s

%s
', + $config, &htmlify($@))); +} else { &fatal("500 Internal Error", 'Configuration not found. Set the variable $config ' . 'in cvsweb.cgi, or the environment variable ' @@ -266,25 +287,24 @@ foreach (keys %DEFAULTVALUE) } $barequery = ""; +my @barequery; foreach (@stickyvars) { # construct a query string with the sticky non default parameters set if (defined($input{$_}) && $input{$_} ne '' && !(defined($DEFAULTVALUE{$_}) && $input{$_} eq $DEFAULTVALUE{$_})) { - if ($barequery) { - $barequery = $barequery . "&"; - } - my $thisval = urlencode($_) . "=" . urlencode($input{$_}); - $barequery .= $thisval; + push @barequery, join('=', urlencode($_), urlencode($input{$_})); } } # is there any query ? -if ($barequery) { +if (@barequery) { + $barequery = join('&', @barequery); $query = "?$barequery"; - $barequery = "&" . $barequery; + $barequery = "&$barequery"; } else { $query = ""; } +undef @barequery; # get actual parameters $sortby = $input{"sortby"}; @@ -309,7 +329,7 @@ else { $byfile = 1; } -$hr_default = $input{'f'} eq 'h'; +$hr_default = ($input{'f'} eq 'h' || $input{'f'} eq 'H'); $logsort = $input{'logsort'}; @@ -332,19 +352,30 @@ if ($input{'cvsroot'} && $CVSROOT{$input{'cvsroot'}}) $cvsroot = $CVSROOT{$cvstree}; # create icons out of description -foreach my $k (keys %ICONS) { +my $k; +foreach $k (keys %ICONS) { no strict 'refs'; my ($itxt,$ipath,$iwidth,$iheight) = @{$ICONS{$k}}; if ($ipath) { - ${"${k}icon"} = "\"$itxt\""; + ${"${k}icon"} = sprintf('%s', + htmlquote($ipath), htmlquote($itxt), $iwidth, $iheight) } else { ${"${k}icon"} = $itxt; } } +undef $k; +my $config_cvstree = "$config-$cvstree"; + # Do some special configuration for cvstrees -do "$config-$cvstree" if (-f "$config-$cvstree"); +if (-f $config_cvstree) { + do $config_cvstree + || &fatal("500 Internal Error", + sprintf('Error in loading configuration file: %s

%s
', + $config_cvstree, &htmlify($@))); +} +undef $config_cvstree; $prcategories = '(?:' . join('|', @prcategories) . ')'; $prcgi .= '%s' if defined($prcgi) && $prcgi !~ /%s/; @@ -359,7 +390,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"; @@ -453,57 +484,63 @@ elsif (-d $fullname) { } print "\n"; $infocols++; - print ""; # do not display the other column-headers, if we do not have any files # with revision information: if (scalar(%fileinfo)) { $infocols++; - print ""; $infocols++; - print ""; if ($show_author) { $infocols++; - print ""; } $infocols++; - print ""; } elsif ($use_descriptions) { - print "
"; - print "" if (!$byfile); - print "File"; - print "" if (!$byfile); + printf '
', + $byfile ? $columnHeaderColorSorted : $columnHeaderColorDefault; + if ($byfile) { + print 'File'; + } else { + print &link('File', sprintf('./%s#dirlist', + &toggleQuery("sortby", "file"))); + } print ""; - print "" if (!$byrev); - print "Rev."; - print "" if (!$byrev); + printf '', + $byrev ? $columnHeaderColorSorted : $columnHeaderColorDefault; + if ($byrev) { + print 'Rev.'; + } else { + print &link('Rev.', sprintf('./%s#dirlist', + &toggleQuery("sortby", "rev"))); + } print ""; - print "" if (!$bydate); - print "Age"; - print "" if (!$bydate); + printf '', + $bydate ? $columnHeaderColorSorted : $columnHeaderColorDefault; + if ($bydate) { + print 'Age'; + } else { + print &link('Age', sprintf('./%s#dirlist', + &toggleQuery("sortby", "date"))); + } print ""; - print "" if (!$byauthor); - print "Author"; - print "" if (!$byauthor); + printf '', + $byauthor ? $columnHeaderColorSorted : $columnHeaderColorDefault; + if ($byauthor) { + print 'Author'; + } else { + print &link('Author', sprintf('./%s#dirlist', + &toggleQuery("sortby", "author"))); + } print ""; - print "" if (!$bylog); - print "Last log entry"; - print "" if (!$bylog); + printf '', + $bylog ? $columnHeaderColorSorted : $columnHeaderColorDefault; + if ($bylog) { + print 'Last log entry'; + } else { + print &link('Last log entry', sprintf('./%s#dirlist', + &toggleQuery("sortby", "log"))); + } print ""; + printf '', $columnHeaderColorDefault; print "Description"; $infocols++; } @@ -528,9 +565,9 @@ elsif (-d $fullname) { closedir($dh); } - my $hideAtticToggleLink = "[Hide]" if (!$input{'hideattic'}); + my $hideAtticToggleLink = $input{'hideattic'} ? '' : + &link('[Hide]', sprintf('./%s#dirlist', + &toggleQuery ("hideattic"))); # Sort without the Attic/ pathname. # place directories first @@ -568,38 +605,38 @@ elsif (-d $fullname) { next if ($_ eq '..' && $where eq '/'); my ($rev,$date,$log,$author,$filename) = @{$fileinfo{$_}} if (defined($fileinfo{$_})); - print "
" if ($dirtable); + printf '
', $tabcolors[$dirrow % 2] if $dirtable; if ($_ eq '..') { - $url = "../" . $query; + $url = "../$query"; if ($nofilelinks) { print $backicon; } else { - print &link($backicon,$url); + print &link($backicon, $url); } - print " ", &link("Previous Directory",$url); + print " ", &link("Previous Directory", $url); } else { - $url = urlencode($_) . '/' . $query; + $url = urlencode($_) . "/$query"; print ""; if ($nofilelinks) { print $diricon; } else { - print &link($diricon,$url); + print &link($diricon, $url); } - print " ", &link($_ . "/", $url), $attic; + print " ", &link("$_/", $url), $attic; if ($_ eq "Attic") { - print "  [Don't hide]"; + print "  "; + print &link("[Don't hide]", sprintf('./%s#dirlist', + &toggleQuery ("hideattic"))); } } # Show last change in dir if ($filename) { print "  " if ($dirtable); if ($date) { - print " " . readableTime(time() - $date,0) . ""; + print " ", readableTime(time() - $date,0), ""; } if ($show_author) { print " " if ($dirtable); @@ -610,8 +647,8 @@ elsif (-d $fullname) { print "$filename/$rev"; print "
" if ($dirtable); if ($log) { - print " " - . &htmlify(substr($log,0,$shortLogLen)); + print " ", + &htmlify(substr($log,0,$shortLogLen)); if (length $log > 80) { print "..."; } @@ -621,7 +658,7 @@ elsif (-d $fullname) { else { my ($dwhere) = ($where ne "/" ? $where : "") . $_; if ($use_descriptions && defined $descriptions{$dwhere}) { - print "
 " if $dirtable; + print " " if $dirtable; print $descriptions{$dwhere}; } elsif ($dirtable && $infocols > 1) { # close the row with the appropriate number of @@ -652,7 +689,7 @@ elsif (-d $fullname) { next if (!defined($fileinfo{$_})); ($rev,$date,$log,$author) = @{$fileinfo{$_}}; $filesfound++; - print "
" if ($dirtable); + printf '
', $tabcolors[$dirrow % 2] if $dirtable; print ""; if ($nofilelinks) { print $fileicon; @@ -663,11 +700,11 @@ elsif (-d $fullname) { print " ", &link($_, $url), $attic; print " " if ($dirtable); download_link($fileurl, - $rev, $rev, - $defaultViewable ? "text/x-cvsweb-markup" : undef); + $rev, $rev, + $defaultViewable ? "text/x-cvsweb-markup" : undef); print " " if ($dirtable); if ($date) { - print " " . readableTime(time() - $date,0) . ""; + print " ", readableTime(time() - $date,0), ""; } if ($show_author) { print " " if ($dirtable); @@ -675,7 +712,7 @@ elsif (-d $fullname) { } print " " if ($dirtable); if ($log) { - print " " . &htmlify(substr($log,0,$shortLogLen)); + print " ", &htmlify(substr($log,0,$shortLogLen)); if (length $log > 80) { print "..."; } @@ -690,7 +727,7 @@ elsif (-d $fullname) { if ($dirtable && defined($tableBorderColor)) { print "
"; } - print "". ($dirtable == 1) ? "" : "" . "\n"; + print( $dirtable == 1 ? "\n" : "\n" ); if ($filesexists && !$filesfound) { print "

NOTE: There are $filesexists files, but none matches the current tag ($input{only_with_tag})\n"; @@ -710,7 +747,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 +810,18 @@ elsif (-d $fullname) { elsif (-f $fullname . ',v') { if (defined($input{'rev'}) || $doCheckout) { &doCheckout($fullname, $input{'rev'}); + gzipclose(); exit; } if (defined($input{'annotate'}) && $allow_annotate) { &doAnnotate($input{'annotate'}); + gzipclose(); exit; } if (defined($input{'r1'}) && defined($input{'r2'})) { &doDiff($fullname, $input{'r1'}, $input{'tr1'}, $input{'r2'}, $input{'tr2'}, $input{'f'}); + gzipclose(); exit; } print("going to dolog($fullname)\n") if ($verbose); @@ -803,6 +844,7 @@ elsif (-d $fullname) { # e.g. foo.c &doDiff($fullname, $input{'r1'}, $input{'tr1'}, $input{'r2'}, $input{'tr2'}, $input{'f'}); + gzipclose(); exit; } elsif (($newname = $fullname) =~ s|/([^/]+)$|/Attic/$1| && @@ -836,6 +878,8 @@ elsif (-d $fullname) { } &fatal("404 Not Found","$where: no such file or directory"); } + +gzipclose(); ## End MAIN sub printDiffSelect($) { @@ -886,65 +930,120 @@ sub findLastModifiedSubdirs(@) { return @files; } +sub htmlify_sub(&$) { + (my $proc, local $_) = @_; + local @_ = split(m`(]+>[^<]*)`i); + my ($linked, $result); + + while (($_, $linked) = splice(@_, 0, 2)) { + &$proc(); + $result .= $_; + $result .= $linked; + } + + $result; +} + sub htmlify($;$) { - my($string, $extra) = @_; + (local $_, my $extra) = @_; - # Special Characters; RFC 1866 - $string =~ s/&/&/g; - $string =~ s/\"/"/g; - $string =~ s//>/g; + $_ = htmlquote($_); - # get URL's as link .. - $string =~ s`(http|ftp|https)(://[-a-zA-Z0-9%.~:_/]+)([?&]([-a-zA-Z0-9%.~:_]+)=([-a-zA-Z0-9%.~:_])+)*`$1$2$3`g; - # get e-mails as link - $string =~ s`([-a-zA-Z0-9_.]+@([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})`$1`g; + # get URL's as link + s{ + (http|ftp|https)://\S+ + }{ + &link($&, htmlunquote($&)) + }egx; - if ($extra) { - # get PR #'s as link .. - if (defined($prcgi)) { - 1 while $string =~ s`\b(pr[:#]?\s*(?:#?\d+[,\s]\s*)*#?)(\d+)\b`sprintf('%s%s', $1, sprintf($prcgi, $2), $2)`ie; - $string =~ s`\b${prcategories}/(\d+)\b`sprintf('%s', sprintf($prcgi, $1), $&)`igeo; - } + # get e-mails as link + $_ = htmlify_sub { + s< + [\w+=\-.!]+@[\w\-]+(\.[\w\-]+)+ + >< + &link($&, "mailto:$&") + >egix; + } $_; - # get manpage specs as link .. - if (defined($mancgi)) { - $string =~ s`\b([a-zA-Z]\w+)\(([0-9n])\)\B`sprintf('%s', sprintf($mancgi, $2, $1), $&)`ge; - } + if ($extra) { + # get PR #'s as link: "PR#nnnn" "PR: nnnn, ..." "PR nnnn, ..." "bin/nnnn" + if (defined($prcgi)) { + my $prev; + + do { + $prev = $_; + + $_ = htmlify_sub { + s{ + (\bPR[:\#]?\s* + (?: + \#? + \d+[,\s]\s* + )* + \#?) + (\d+)\b + }{ + $1 . &link($2, sprintf($prcgi, $2)) . $3 + }egix; + } $_; + } while ($_ ne $prev); + + $_ = htmlify_sub { + s{ + (\b$prcategories/(\d+)\b) + }{ + &link($1, sprintf($prcgi, $2)) . $3 + }egox; + } $_; } - return $string; + # get manpage specs as link: "foo.1" "foo(1)" + if (defined($mancgi)) { + $_ = htmlify_sub { + s{ + (\b([a-zA-Z][\w_.]+) + (?: + \( ([0-9n]) \)\B + | + \.([0-9n])\b + ) + ) + }{ + &link($1, sprintf($mancgi, $3 ne '' ? $3 : $4, $2)) . $5 + }egx; + } $_; + } + } + + $_; } -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 $_; } @@ -952,7 +1051,7 @@ sub spacedHtmlText($) { sub link($$) { my($name, $where) = @_; - return "$name\n"; + sprintf '%s', htmlquote($where), $name; } sub revcmp($$) { @@ -1000,7 +1099,7 @@ sub redirect($) { print "Location: $url\r\n"; } html_header("Moved"); - print "This document is located here.\n"; + print "This document is located ", &link('here', $url), "\n"; print &html_footer; exit(1); } @@ -1026,7 +1125,7 @@ sub safeglob($) { $glob =~ s/{([^}]+)}/($t = $1) =~ s-,-|-g; "($t)"/eg; foreach (readdir($dh)) { if (/^${glob}$/) { - push(@results, $dirname . "/" .$_); + push(@results, "$dirname/" .$_); } } } @@ -1064,6 +1163,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($$) { @@ -1083,11 +1216,6 @@ sub doAnnotate($$) { ($pathname = $where) =~ s/(Attic\/)?[^\/]*$//; ($filename = $where) =~ s/^.*\///; - http_header(); - - navigateHeader($scriptwhere,$pathname,$filename,$rev, "annotate"); - print "

Annotation of $pathname$filename, Revision $rev

\n"; - # this seems to be necessary $| = 1; $| = 0; # Flush @@ -1097,7 +1225,7 @@ sub doAnnotate($$) { # the public domain. # we could abandon the use of rlog, rcsdiff and co using # the cvsserver in a similiar way one day (..after rewrite) - $pid = open2($reader, $writer, "cvs server") || fatal ("500 Internal Error", + $pid = open2($reader, $writer, "cvs -Rl server") || fatal ("500 Internal Error", "Fatal Error - unable to open cvs for annotation"); # OK, first send the request to the server. A simplified example is: @@ -1149,6 +1277,11 @@ sub doAnnotate($$) { # were nicer about buffering, then we could just leave it open, I think. close ($writer) || die "cannot close: $!"; + http_header(); + + navigateHeader($scriptwhere,$pathname,$filename,$rev, "annotate"); + print "

Annotation of $pathname$filename, Revision $rev

\n"; + # Ready to get the responses from the server. # For example: # E Annotations for foo/xx @@ -1164,7 +1297,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);
@@ -1173,39 +1314,48 @@ sub doAnnotate($$) {
 	}
 	elsif ($words[0] eq "M") {
 	    $lineNr++;
-	    my $lrev = substr ($_, 2, 13);
-	    my $lusr = substr ($_, 16,  9);
-	    my $line = substr ($_, 36);
+	    (my $lrev = substr($_, 2, 13)) =~ y/ //d;
+	    (my $lusr = substr($_, 16,  9)) =~ y/ //d;
+	    my $line = substr($_, 36);
+	    my $isCurrentRev = ($rev eq $lrev);
 	    # we should parse the date here ..
 	    if ($lrev eq $oldLrev) {
-		$revprint = "             ";
+		$revprint = sprintf('%-8s', '');
 	    }
 	    else {
-		$revprint = $lrev; $oldLusr = "";
+		$revprint = sprintf('%-8s', $lrev);
+		$revprint =~ s`\S+`&link($&, "$scriptwhere$query#rev$&")`e;	# `
+		$oldLusr = '';
 	    }
 	    if ($lusr eq $oldLusr) {
-		$usrprint = "         ";
+		$usrprint = '';
 	    }
 	    else {
 		$usrprint = $lusr;
 	    }
 	    $oldLrev = $lrev;
 	    $oldLusr = $lusr;
-	    # is there a less timeconsuming way to strip spaces ?
-	    ($lrev = $lrev) =~ s/\s+//g;
-	    my $isCurrentRev = ($rev eq $lrev);
 
-	    print "" if ($isCurrentRev);
-	    printf ("%8s%s%8s %4d:", $revprint, ($isCurrentRev ? "|" : " "), $usrprint, $lineNr);
-	    print spacedHtmlText($line);
-	    print "" if ($isCurrentRev);
+	    # Set bold for text-based browsers only - graphical
+	    # browsers show bold fonts a bit wider than regular fonts,
+	    # so it looks irregular.
+	    print "" if ($isCurrentRev && $is_textbased);
+
+	    printf "%s%s %-8s %4d:",
+		    $revprint,
+		    $isCurrentRev ? '!' : ' ',
+		    $usrprint,
+		    $lineNr;
+	    print spacedHtmlText($line, $d{'tabstop'});
+
+	    print "" if ($isCurrentRev && $is_textbased);
 	}
 	elsif ($words[0] eq "ok") {
 	    # We could complain about any text received after this, like the
 	    # CVS command line client.  But for simplicity, we don't.
 	}
 	elsif ($words[0] eq "error") {
-	    fatal ("500 Internal Error", "Error occured during annotate: $_");
+	    fatal("500 Internal Error", "Error occured during annotate: $_");
 	}
     }
     if ($annTable) {
@@ -1322,12 +1472,14 @@ sub cvswebMarkup($$$) {
     print "
"; print "
"; print "File: ", &clickablePath($where, 1); - print " "; - &download_link(urlencode($fileurl), $revision, "(download)"); + print " ("; + &download_link($fileurl, $revision, "download"); + print ")"; if (!$defaultTextPlain) { - print " "; - &download_link(urlencode($fileurl), $revision, "(as text)", + print " ("; + &download_link($fileurl, $revision, "as text", "text/plain"); + print ")"; } print "
\n"; if ($show_log_in_markup) { @@ -1340,16 +1492,26 @@ sub cvswebMarkup($$$) { $input{only_with_tag}; } print "
"; - my @content = <$filehandle>; my $url = download_url($fileurl, $revision, $mimetype); print "
"; if ($mimetype =~ /^image/) { - print "
"; + printf '
', htmlquote("$url$barequery"); } + elsif ($mimetype =~ m%^application/pdf%) { + printf '
', htmlquote("$url$barequery"); + } 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 "
"; } @@ -1358,7 +1520,7 @@ sub cvswebMarkup($$$) { sub viewable($) { my ($mimetype) = @_; - $mimetype =~ m%^(text|image)/%; + $mimetype =~ m%^((text|image)/|application/pdf)% ; } ############################### @@ -1456,6 +1618,7 @@ sub doDiff($$$$$$) { if ($human_readable) { http_header(); &human_readable_diff($fh, $rev2); + gzipclose(); exit; } else { @@ -1491,14 +1654,14 @@ sub doDiff($$$$$$) { s|$cvsroot/||o; if ($sym1) { chop; - $_ .= " " . $sym1 . "\n"; + $_ .= " $sym1\n"; } } elsif (m|^$f2 $cvsroot|o) { s|$cvsroot/||o; if ($sym2) { chop; - $_ .= " " . $sym2 . "\n"; + $_ .= " $sym2\n"; } } print $_; @@ -1606,7 +1769,7 @@ again: $state = "head"; goto again; } - if ($state eq "head" && /^----------------------------$/) { + if ($state eq "head" && /$LOG_REVSEPARATOR/o) { $state = "log"; $rev = undef; $date = undef; @@ -1616,14 +1779,13 @@ again: next; } if ($state eq "log") { - if (/^----------------------------$/ - || /^=============================/) { + if (/$LOG_REVSEPARATOR/o || /$LOG_FILESEPARATOR/o) { # End of a log entry. my $revbranch; ($revbranch = $rev) =~ s/\.\d+$//; - print "$filename $rev Wanted: $revwanted " - . "Revbranch: $revbranch Branch: $branch " - . "Branchpoint: $branchpoint\n" if ($verbose); + print "$filename $rev Wanted: $revwanted ", + "Revbranch: $revbranch Branch: $branch ", + "Branchpoint: $branchpoint\n" if ($verbose); if (!defined($revwanted) && defined($branch) && $branch eq $revbranch || !defined($tag)) { print "File revision $rev found for branch $branch\n" @@ -1661,10 +1823,10 @@ again: next; } else { - $log = $log . $_; + $log .= $_; } } - if (/^===============/) { + if (/$LOG_FILESEPARATOR/o) { $state = "start"; next; } @@ -1738,7 +1900,7 @@ sub readLog($;$) { # log info # ---------------------------- logentry: - while (!/^=========/) { + while (!/$LOG_FILESEPARATOR/o) { $_ = <$fh>; last logentry if (!defined($_)); # EOF print "R:", $_ if ($verbose); @@ -1746,7 +1908,7 @@ sub readLog($;$) { $rev = $1; unshift(@allrevisions,$rev); } - elsif (/^========/ || /^----------------------------$/) { + elsif (/$LOG_FILESEPARATOR/o || /$LOG_REVSEPARATOR/o) { next logentry; } else { @@ -1780,7 +1942,7 @@ sub readLog($;$) { while (<$fh>) { print "L:", $_ if ($verbose); next line if (/^branches:\s/); - last line if (/^----------------------------$/ || /^=========/); + last line if (/$LOG_FILESEPARATOR/o || /$LOG_REVSEPARATOR/o); $log{$rev} .= $_; } print "E:", $_ if ($verbose); @@ -1932,29 +2094,40 @@ sub printLog($;$) { } print "\n Revision "; &download_link($fileurl, $_, $_, - $defaultViewable ? "text/x-cvsweb-markup" : undef); + $defaultViewable ? "text/x-cvsweb-markup" : undef); if ($defaultViewable) { - print " / "; - &download_link($fileurl, $_, "(download)", $mimetype); + print " / ("; + &download_link($fileurl, $_, "download", $mimetype); + print ")"; } if (not $defaultTextPlain) { - print " / "; - &download_link($fileurl, $_, "(as text)", - "text/plain"); + print " / ("; + &download_link($fileurl, $_, "as text", "text/plain"); + print ")"; } if (!$defaultViewable) { - print " / "; - &download_link($fileurl, $_, "(view)", "text/x-cvsweb-markup"); + print " / ("; + &download_link($fileurl, $_, "view", "text/x-cvsweb-markup"); + print ")"; } if ($allow_annotate) { - print " - "; - print "annotate"; + print " - "; + print &link('annotate', + sprintf('%s/%s?annotate=%s%s', + $scriptname, + urlencode($where), + $_, + $barequery)); } # Plus a select link if enabled, and this version isn't selected if ($allow_version_select) { if ((!defined($input{"r1"}) || $input{"r1"} ne $_)) { - print " - [select for diffs]\n"; + print " - "; + print &link('[select for diffs]', + sprintf('%s?r1=%s%s', + $scriptwhere, + $_, + $barequery)); } else { print " - [selected]"; @@ -1969,13 +2142,13 @@ sub printLog($;$) { } if (defined @mytz) { my ($est) = $mytz[(localtime($date{$_}))[8]]; - print ", " . scalar localtime($date{$_}) . " $est ("; + print ", ", scalar localtime($date{$_}), " $est ("; } else { - print ", " . scalar gmtime($date{$_}) . " UTC ("; + print ", ", scalar gmtime($date{$_}), " UTC ("; } - print readableTime(time() - $date{$_},1) . " ago)"; + print readableTime(time() - $date{$_},1), " ago)"; print " by "; - print "" . $author{$_} . "\n"; + print "", $author{$_}, "\n"; print "
Branch: ",$link?link_tags($revsym{$br}):$revsym{$br},"\n" if ($revsym{$br}); print "
CVS Tags: ",$link?link_tags($revsym{$_}):$revsym{$_},"" @@ -2009,22 +2182,33 @@ sub printLog($;$) { # Offer diff to previous revision if ($prev) { $diffrev{$prev} = 1; - print " to previous $prev\n"; + + my $url = sprintf('%s.diff?r1=%s&r2=%s%s', + $scriptwhere, + $prev, + $_, + $barequery); + + print " to previous "; + print &link($prev, $url); if (!$hr_default) { # offer a human readable version if not default - print "(colored)\n"; + print ' (', &link('colored', "$url&f=h"), ')'; } } # # Plus, if it's on a branch, and it's not a vendor branch, # offer a diff with the branch point. if ($revsym{$brp} && !/^1\.1\.1\.\d+$/ && !defined($diffrev{$brp})) { - print " to branchpoint $brp\n"; + my $url = sprintf('%s.diff?r1=%s&r2=%s%s', + $scriptwhere, + $brp, + $_, + $barequery); + + print " to branchpoint "; + print &link($brp, $url); if (!$hr_default) { # offer a human readable version if not default - print "(colored)\n"; + print ' (', &link('colored', "$url&f=h"), ')'; } } # @@ -2050,13 +2234,17 @@ sub printLog($;$) { } if (!defined($diffrev{$nextmain})) { $diffrev{$nextmain} = 1; - print " next main $nextmain\n"; + + my $url = sprintf('%s.diff?r1=%s&r2=%s%s', + $scriptwhere, + $nextmain, + $_, + $barequery); + + print " next main "; + print &link($nextmain, $url); if (!$hr_default) { # offer a human readable version if not default - print "(colored)\n"; + print ' (', &link('colored', "$url&f=h"), ')'; } } } @@ -2064,14 +2252,17 @@ sub printLog($;$) { # to make a diff to that revision if (defined($input{"r1"}) && !defined($diffrev{$input{"r1"}})) { $diffrev{$input{"r1"}} = 1; - print " to selected $input{'r1'}\n"; - if (!$hr_default) { # offer a human readable version if not default - print "(colored)\n"; + my $url = sprintf('%s.diff?r1=%s&r2=%s%s', + $scriptwhere, + $input{'r1'}, + $_, + $barequery); + + print " to selected "; + print &link($input{'r1'}, $url); + if (!$hr_default) { # offer a human readable version if not default + print ' (', &link('colored', "$url&f=h"), ')'; } } } @@ -2091,11 +2282,10 @@ sub doLog($) { ($filename = $where) =~ s|^.*/||; $backurl = $scriptname . "/" . urlencode($upwhere) . $query; print &link($backicon, "$backurl#$filename"), - " Up to ", &clickablePath($upwhere, 1), "

\n"; - print <Request diff between arbitrary revisions -


-EOF + " Up to ", &clickablePath($upwhere, 1), "

\n"; + print &link('Request diff between arbitrary revisions', '#diff'); + print '


'; + if ($curbranch) { print "Default branch: ", ($revsym{$curbranch} || $curbranch); } @@ -2123,42 +2313,44 @@ EOF print "

\n"; print "

\n"; foreach (@stickyvars) { - print "\n" + printf('', $_, $input{$_}) 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"; } @@ -2234,7 +2428,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); @@ -2261,17 +2455,16 @@ sub human_readable_diff($){ $date2 = $r2d; } - print "

Diff for /$where_nd between version $rev1 and $rev2

\n"; - - print "\n"; - print "\n"; - print "
"; - print "version $rev1"; + print "

Diff for /$where_nd between version $rev1 and $rev2

\n", + "\n", + "\n", + "\n"; - print "\n", + "\n"; @@ -2288,9 +2481,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 "
", + "version $rev1"; print ", $date1" if (defined($date1)); print "
Tag: $sym1\n" if ($sym1); - print "
"; - print "version $rev2"; + print "", + "version $rev2"; print ", $date2" if (defined($date2)); print "
Tag: $sym2\n" if ($sym1); print "
"; @@ -2306,7 +2505,7 @@ sub human_readable_diff($){ } else { ($diffcode,$rest) = $difftxt =~ /^([-+ ])(.*)/; - $_ = spacedHtmlText ($rest); + $_ = spacedHtmlText($rest, $d{'tabstop'}); # Add fontface, size $_ = "$fs $_$fe"; @@ -2390,12 +2589,12 @@ 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 "$body_tag_for_src\n"; print ""; print ""; @@ -2406,10 +2605,10 @@ sub navigateHeader($$$$$) { sub plural_write($$) { my ($num,$text) = @_; if ($num != 1) { - $text = $text . "s"; + $text .= "s"; } if ($num > 0) { - return $num . " " . $text; + return join(' ', $num, $text); } else { return ""; @@ -2453,7 +2652,7 @@ sub readableTime($$) { my $resttime = plural_write(int ($rest / $break), $desc{$break}); if ($resttime) { - $retval = $retval . ", " . $resttime; + $retval .= ", $resttime"; } } @@ -2477,24 +2676,26 @@ sub clickablePath($$) { $retval = "[$cvstree]"; } else { - $retval = $retval . " [$cvstree]"; + $retval .= ' ' . &link("[$cvstree]", sprintf('%s/%s#dirlist', + $scriptname, + $query)); my $wherepath = ''; my ($lastslash) = $pathname =~ m|/$|; foreach (split(/\//, $pathname)) { - $retval = $retval . " / "; - $wherepath = $wherepath . '/' . $_; + $retval .= " / "; + $wherepath .= "/$_"; my ($last) = "$wherepath/" eq "/$pathname" || $wherepath eq "/$pathname"; if ($clickLast || !$last) { - $retval = $retval . "$_"; + $retval .= &link($_, join('', + $scriptname, + urlencode($wherepath), + (!$last || $lastslash ? '/' : ''), + $query, + (!$last || $lastslash ? "#dirlist" : ""))); } else { # do not make a link to the current dir - $retval = $retval . $_; + $retval .= $_; } } } @@ -2526,8 +2727,7 @@ sub chooseCVSRoot() { foreach $k (@foo) { print "\n"; + print ">", ($CVSROOTdescr{$k} ? $CVSROOTdescr{$k} : $k), "\n"; } print "\n"; print ""; @@ -2551,7 +2751,7 @@ sub chooseMirror() { print "\nThis cvsweb is mirrored in:\n"; foreach $mirror (keys %MIRRORS) { print ", " if ($moremirrors); - print qq($mirror\n); + print &link(htmlquote($mirror),$MIRRORS{$mirror}); $moremirrors = 1; } print "

\n"; @@ -2594,32 +2794,28 @@ sub download_url($$;$) { $revision =~ s/\b0\.//; - if (defined($checkout_magic) + if (defined($checkoutMagic) && (!defined($mimetype) || $mimetype ne "text/x-cvsweb-markup")) { - my ($path); - ($path = $where) =~ s|/[^/]*$|/|; + my $path = $where; + $path =~ s|/[^/]*$|/|; $url = "$scriptname/$checkoutMagic/${path}$url"; } $url .= "?rev=$revision"; - $url .= "&content-type=$mimetype" if (defined($mimetype)); + $url .= '&content-type=' . urlencode($mimetype) if (defined($mimetype)); - return $url; + $url; } # Presents a link to download the # selected revision sub download_link($$$;$) { - my ($url,$revision,$textlink,$mimetype) = @_; - my ($fullurl) = download_url($url,$revision,$mimetype); - my ($paren) = $textlink =~ /^\(/; - $textlink =~ s/^\(// if ($paren); - $textlink =~ s/\)$// if ($paren); - print "(" if ($paren); - print "$textlink"; - print ")" if ($paren); } # Returns a Query string with the @@ -2670,7 +2871,7 @@ sub toggleQuery($$) { my ($value) = defined($vars{$var}) ? $vars{$var} : ""; my ($default) = defined($DEFAULTVALUE{$var}) ? $DEFAULTVALUE{$var} : ""; if ($value ne $default) { - $newquery .= "&" if ($newquery ne ""); + $newquery .= "&" if ($newquery ne ""); $newquery .= urlencode($var) . "=" . urlencode($value); } } @@ -2681,20 +2882,46 @@ sub toggleQuery($$) { } sub urlencode($) { - my ($in) = @_; - my ($out); - ($out = $in) =~ s/([\000-+{-\377])/sprintf("%%%02x", ord($1))/ge; - return $out; + local($_) = @_; + + s/[\000-+{-\377]/sprintf("%%%02x", ord($&))/ge; + + + $_; } +sub htmlquote($) { + local($_) = @_; + + # Special Characters; RFC 1866 + s/&/&/g; + s/\"/"/g; + s//>/g; + + $_; +} + +sub htmlunquote($) { + local($_) = @_; + + # Special Characters; RFC 1866 + s/"/\"/g; + s/<//g; + s/&/&/g; + + $_; +} + 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"; + print "Last-Modified: ", scalar gmtime($moddate), " GMT\r\n"; } } if ($is_mod_perl) { @@ -2704,8 +2931,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"); @@ -2717,7 +2943,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 { @@ -2742,7 +2972,7 @@ sub http_header(;$) { sub html_header($) { my ($title) = @_; - my $version = '$zRevision: 1.94 $ $Revision: 3.18 $'; #' + my $version = '$zRevision: 1.103 $ $Revision: 3.36 $'; #' http_header(); print <$sym"; + $ret .= &link($sym, $fileurl . toggleQuery('only_with_tag',$sym)); } - return $ret."\n"; + return "$ret\n"; } # @@ -2787,4 +3016,83 @@ sub forbidden_module($) { } return 0; +} + +# Close the GZIP handle remove the tie. + +sub gzipclose { + if ($gzip_open) { + select(STDOUT); + close(GZIP); + untie *GZIP; + $gzip_open = 0; + } +} + +# implement a gzipped file handle via the Compress:Zlib compression +# library. + +sub MAGIC1() { 0x1f } +sub MAGIC2() { 0x8b } +sub OSCODE() { 3 } + +sub TIEHANDLE { + my ($class, $out) = @_; + my ($d) = Compress::Zlib::deflateInit(-Level => 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); }

"; - print "$backicon"; + print &link($backicon, "$swhere$query#rev$rev"); print " Return to ", &link("$filename","$swhere$query#rev$rev")," CVS log"; print " $fileicon