=================================================================== RCS file: /cvs/cvsweb/cvsweb.cgi,v retrieving revision 1.1.1.28 retrieving revision 1.1.1.32 diff -u -p -r1.1.1.28 -r1.1.1.32 --- cvsweb/cvsweb.cgi 2001/08/01 10:24:01 1.1.1.28 +++ cvsweb/cvsweb.cgi 2002/07/07 04:31:41 1.1.1.32 @@ -10,6 +10,7 @@ # Dick Balaska # Akinori MUSHA # Jens-Uwe Mager +# Ville Skyttä # # Based on: # * Bill Fenners cvsweb.cgi revision 1.28 available from: @@ -17,8 +18,9 @@ # # Copyright (c) 1996-1998 Bill Fenner # (c) 1998-1999 Henner Zeller -# (c) 1999 Henrik Nordstrom -# (c) 2000-2001 Akinori MUSHA +# (c) 1999 Henrik Nordstrom +# (c) 2000-2002 Akinori MUSHA +# (c) 2002 Ville Skyttä # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -42,8 +44,9 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # +# $FreeBSD: projects/cvsweb/cvsweb.cgi,v 1.112 2002/07/06 18:15:19 scop Exp $ # $zId: cvsweb.cgi,v 1.112 2001/07/24 13:03:16 hzeller Exp $ -# $Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.82 2001/08/01 09:54:52 knu Exp $ +# $Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.84 2001/10/07 20:50:10 knu Exp $ # ### @@ -62,12 +65,13 @@ use vars qw ( @revisions %state %difflines %log %branchpoint @revorder $prcgi @prcategories $re_prcategories $prkeyword $re_prkeyword $mancgi $checkoutMagic $doCheckout $scriptname $scriptwhere - $where $pathinfo $Browser $nofilelinks $maycompress @stickyvars + $where $pathinfo $Browser $nofilelinks $maycompress + @stickyvars @unsafevars %funcline_regexp $is_mod_perl $is_links $is_lynx $is_w3m $is_msie $is_mozilla3 $is_textbased %input $query $barequery $sortby $bydate $byrev $byauthor $bylog $byfile $defaultDiffType $logsort $cvstree $cvsroot - $mimetype $charset $defaultTextPlain $defaultViewable + $mimetype $charset $output_filter $defaultTextPlain $defaultViewable $command_path %CMD $allow_compress $backicon $diricon $fileicon $fullname $newname $cvstreedefault @@ -77,8 +81,10 @@ use vars qw ( $columnHeaderColorSorted $hr_breakable $showfunc $hr_ignwhite $hr_ignkeysubst $diffcolorHeading $diffcolorEmpty $diffcolorRemove $diffcolorChange $diffcolorAdd $diffcolorDarkChange $difffontface - $difffontsize $inputTextSize $mime_types $allow_annotate - $allow_markup $use_java_script $open_extern_window + $difffontsize $inputTextSize $mime_types + $allow_annotate $allow_markup + $allow_log_extra $allow_dir_extra $allow_source_extra + $use_java_script $open_extern_window $extern_window_width $extern_window_height $edit_option_form $show_subdir_lastmod $show_log_in_markup $preformat_in_markup $v $navigationHeaderColor $tableBorderColor $markupLogColor @@ -87,7 +93,7 @@ use vars qw ( $use_moddate $has_zlib $gzip_open $allow_tar @tar_options @gzip_options @zip_options @cvs_options $LOG_FILESEPARATOR $LOG_REVSEPARATOR - $tmpdir + $tmpdir $HTML_DOCTYPE $HTML_META ); sub printDiffSelect($); @@ -99,13 +105,14 @@ sub htmlify($;$); sub spacedHtmlText($;$); sub link($$); sub revcmp($$); -sub fatal($$); +sub fatal($$@); sub redirect($); sub safeglob($); sub search_path($); sub getMimeTypeFromSuffix($); sub head($;$); sub scan_directives(@); +sub openOutputFilter(); sub doAnnotate($$); sub doCheckout($$); sub cvswebMarkup($$$); @@ -141,15 +148,11 @@ sub forbidden_module($); ##### Start of Configuration Area ######## delete $ENV{PATH}; -$cvsweb_revision = - '1.112' . '.' . ( - split (/ /, - q$Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.82 2001/08/01 09:54:52 knu Exp $ -))[2]; +$cvsweb_revision = '2.0.4'; -use File::Basename; +use File::Basename (); -($mydir) = (dirname($0) =~ /(.*)/); # untaint +($mydir) = (File::Basename::dirname($0) =~ /(.*)/); # untaint # == EDIT this == # Locations to search for user configuration, in order: @@ -164,6 +167,7 @@ for ("$mydir/cvsweb.conf", '/usr/local/etc/cvsweb/cvsw # Defaults for configuration variables that shouldn't need # to be configured.. $allow_version_select = 1; +$allow_log_extra = 1; ##### End of Configuration Area ######## @@ -182,7 +186,7 @@ $cvstreedefault = $body_tag = $body_tag_for_src = $log $extern_window_width = $extern_window_height = $edit_option_form = $show_subdir_lastmod = $show_log_in_markup = $v = $navigationHeaderColor = $tableBorderColor = $markupLogColor = $tabstop = $use_moddate = $moddate = - $gzip_open = undef; + $gzip_open = $HTML_DOCTYPE = $HTML_META = undef; $tmpdir = defined($ENV{TMPDIR}) ? $ENV{TMPDIR} : "/var/tmp"; $LOG_FILESEPARATOR = q/^={77}$/; @@ -230,10 +234,20 @@ $LOG_REVSEPARATOR = q/^-{28}$/; }, ); +$HTML_DOCTYPE = + ''; + +$HTML_META = < + + + +EOM + ##### End of configuration variables ##### -use Time::Local; -use IPC::Open2; +use Time::Local (); +use IPC::Open2 qw(open2); # Check if the zlib C library interface is installed, and if yes # we can avoid using the extra gzip process. @@ -296,21 +310,16 @@ $maycompress = # their current value) to any link/query string # you construct @stickyvars = qw(cvsroot hideattic sortby logsort f only_with_tag); +@unsafevars = qw(logsort only_with_tag r1 r2 rev sortby tr1 tr2); if (-f $config) { - require $config || &fatal( - "500 Internal Error", - sprintf( - 'Error in loading configuration file: %s

%s
', - $config, - &htmlify($@) - ) - ); + do "$config" or fatal("500 Internal Error", + 'Error in loading configuration file: %s

%s
', + $config, $@); } else { - &fatal("500 Internal Error", - 'Configuration not found. Set the variable $config ' - . 'in cvsweb.cgi to your cvsweb.conf configuration file first.' - ); + fatal("500 Internal Error", + 'Configuration not found. Set the variable $config in cvsweb.cgi to your cvsweb.conf configuration file first.' + ); } undef %input; @@ -332,6 +341,20 @@ if (defined($query) && $query ne '') { $input{only_with_tag} = $input{only_on_branch} if (defined($input{only_on_branch})); +# Prevent cross-site scripting +foreach (@unsafevars) { + if (defined($input{$_}) && $input{$_} =~ /[^\w\-.]/) { + fatal("500 Internal Error", + 'Malformed query (%s=%s)', + $_, $input{$_}); + } +} + +if (defined($input{"content-type"})) { + fatal("500 Internal Error", "Unsupported content-type") + if ($input{"content-type"} !~ /^[-0-9A-Za-z]+\/[-0-9A-Za-z]+$/); +} + $DEFAULTVALUE{'cvsroot'} = $cvstreedefault; foreach (keys %DEFAULTVALUE) { @@ -410,28 +433,27 @@ $defaultDiffType = $input{'f'}; $logsort = $input{'logsort'}; -my @tmp = @CVSrepositories; -my @pair; +{ + my @tmp = @CVSrepositories; + my @pair; -while (@pair = splice(@tmp, 0, 2)) { - my ($key, $val) = @pair; - my ($descr, $cvsroot) = @$val; + while (@pair = splice(@tmp, 0, 2)) { + my ($key, $val) = @pair; + my ($descr, $cvsroot) = @$val; - next if !-d $cvsroot; + next if !-d $cvsroot; - $CVSROOTdescr{$key} = $descr; - $CVSROOT{$key} = $cvsroot; - push @CVSROOT, $key; + $CVSROOTdescr{$key} = $descr; + $CVSROOT{$key} = $cvsroot; + push @CVSROOT, $key; + } } -undef @tmp; -undef @pair; ## Default CVS-Tree if (!defined($CVSROOT{$cvstreedefault})) { - &fatal("500 Internal Error", - "\$cvstreedefault points to a repository ($cvstreedefault) " - . "not defined in %CVSROOT " - . "(edit your configuration file $config)"); + fatal("500 Internal Error", + '$cvstreedefault points to a repository (%s) not defined in %%CVSROOT (edit your configuration file %s)', + $cvstreedefault, $config); } # alternate CVS-Tree, configured in cvsweb.conf @@ -451,7 +473,7 @@ foreach $k (keys %ICONS) { if ($ipath) { ${"${k}icon"} = sprintf( - '%s', + '%s', hrefquote($ipath), htmlquote($itxt), $iwidth, $iheight) } else { ${"${k}icon"} = $itxt; @@ -463,14 +485,10 @@ my $config_cvstree = "$config-$cvstree"; # Do some special configuration for cvstrees if (-f $config_cvstree) { - require $config_cvstree || &fatal( - "500 Internal Error", - sprintf( - 'Error in loading configuration file: %s

%s
', - $config_cvstree, - &htmlify($@) - ) - ); + do "$config_cvstree" or + fatal("500 Internal Error", + 'Error in loading configuration file: %s

%s
', + $config_cvstree, $@); } undef $config_cvstree; @@ -507,9 +525,8 @@ if ($rewrite) { undef $rewrite; if (!-d $cvsroot) { - &fatal("500 Internal Error", - '$CVSROOT not found!

The server on which the CVS tree lives is probably down. Please try again in a few minutes.' - ); + fatal("500 Internal Error", + '$CVSROOT not found!

The server on which the CVS tree lives is probably down. Please try again in a few minutes.'); } # @@ -518,14 +535,17 @@ if (!-d $cvsroot) { $where =~ m:([^/]*):; $module = $1; if ($module && &forbidden_module($module)) { - &fatal("403 Forbidden", "Access to $where forbidden."); + fatal("403 Forbidden", + 'Access to %s forbidden.', + $where); } # # Handle tarball downloads before any headers are output. # if ($input{tarball}) { - &fatal("403 Forbidden", "Downloading tarballs is prohibited.") + fatal("403 Forbidden", + 'Downloading tarballs is prohibited.') unless $allow_tar; my ($module) = ($where =~ m,^/?(.*),); # untaint $module =~ s,/([^/]*)$,,; @@ -533,15 +553,16 @@ if ($input{tarball}) { my ($basedir) = ($module =~ m,([^/]+)$,); if ($basedir eq '' || $module eq '') { - &fatal("500 Internal Error", - "You cannot download the top level directory."); + fatal("500 Internal Error", + 'You cannot download the top level directory.'); } - my $tmpdir = "/tmp/.cvsweb.$$." . int(time); + my $tmpexportdir = "$tmpdir/.cvsweb.$$." . int(time); - mkdir($tmpdir, 0700) - or &fatal("500 Internal Error", - "Unable to make temporary directory: $!"); + mkdir($tmpexportdir, 0700) + or fatal("500 Internal Error", + 'Unable to make temporary directory: %s', + $!); my @fatal; @@ -549,35 +570,45 @@ if ($input{tarball}) { (exists $input{only_with_tag} && length $input{only_with_tag}) ? $input{only_with_tag} : "HEAD"; + if ($tag eq 'MAIN') { + $tag = 'HEAD'; + } + if (system $CMD{cvs}, @cvs_options, '-Qd', $cvsroot, 'export', '-r', - $tag, '-d', "$tmpdir/$basedir", $module) + $tag, '-d', "$tmpexportdir/$basedir", $module) { - @fatal = ("500 Internal Error", "cvs co failure: $!: $module"); + @fatal = ("500 Internal Error", + 'cvs co failure: %s: %s', + $!, $module); } else { $| = 1; # Essential to get the buffering right. if ($ext eq '.tar.gz') { - print "Content-type: application/x-gzip\r\n\r\n"; + print "Content-Type: application/x-gzip\r\n\r\n"; system - "$CMD{tar} @tar_options -cf - -C $tmpdir $basedir | $CMD{gzip} @gzip_options -c" + "$CMD{tar} @tar_options -cf - -C $tmpexportdir $basedir | $CMD{gzip} @gzip_options -c" and @fatal = - ("500 Internal Error", - "tar zc failure: $!: $basedir"); + ("500 Internal Error", + 'tar zc failure: %s: %s', + $!, $basedir); } elsif ($ext eq '.zip' && $CMD{zip}) { - print "Content-type: application/zip\r\n\r\n"; + print "Content-Type: application/zip\r\n\r\n"; system - "cd $tmpdir && $CMD{zip} @zip_options -r - $basedir" + "cd $tmpexportdir && $CMD{zip} @zip_options -r - $basedir" and @fatal = - ("500 Internal Error", "zip failure: $!: $basedir"); + ("500 Internal Error", + 'zip failure: %s: %s', + $!, $basedir); } else { @fatal = - ("500 Internal Error", "unsupported file type"); + ("500 Internal Error", + 'unsupported file type'); } } - system $CMD{rm}, '-rf', $tmpdir if -d $tmpdir; + system $CMD{rm}, '-rf', $tmpexportdir if -d $tmpexportdir; &fatal(@fatal) if @fatal; @@ -589,7 +620,9 @@ if ($input{tarball}) { ############################### if (-d $fullname) { my $dh = do { local (*DH); }; - opendir($dh, $fullname) || &fatal("404 Not Found", "$where: $!"); + opendir($dh, $fullname) or fatal("404 Not Found", + '%s: %s', + $where, $!); my @dir = readdir($dh); closedir($dh); my @subLevelFiles = findLastModifiedSubdirs(@dir) @@ -605,17 +638,17 @@ if (-d $fullname) { print $short_instruction; } - my $descriptions; - if (($use_descriptions) && open(DESC, "<$cvsroot/CVSROOT/descriptions")) + if ($use_descriptions && open(DESC, "<$cvsroot/CVSROOT/descriptions")) { while () { chomp; my ($dir, $description) = /(\S+)\s+(.*)/; $descriptions{$dir} = $description; } + close(DESC); } - print "

\n"; + print "

\n"; # give direct access to dirs if ($where eq '/') { @@ -623,31 +656,27 @@ if (-d $fullname) { chooseCVSRoot (); } else { print "

Current directory: ", &clickablePath($where, 0), - "\n"; + "

\n"; - print "

Current tag: ", $input{only_with_tag}, "\n" + print "

Current tag: ", $input{only_with_tag},"

\n" if $input{only_with_tag}; } - print "
\n"; + print "
\n"; - # Using in this manner violates the HTML2.0 spec but + # Using in this manner violates the HTML2.0 spec but # provides the results that I want in most browsers. Another # case of layout spooging up HTML. my $infocols = 0; if ($dirtable) { - if (defined($tableBorderColor)) { - - # Can't this be done by defining the border for the inner table? - print - "
"; - } - print - "\n"; + print "
\n"; $infocols++; - printf '\n"; + print "\n"; # do not display the other column-headers, if we do not have any files # with revision information: if (scalar(%fileinfo)) { $infocols++; - printf '"; + print "\n"; $infocols++; - printf '"; + print "\n"; if ($show_author) { $infocols++; - printf '"; + print "\n"; } $infocols++; - printf '"; + print "\n"; } elsif ($use_descriptions) { - printf '\n"; $infocols++; } print "\n"; @@ -810,8 +839,8 @@ if (-d $fullname) { ($rev, $date, $log, $author, $filename) = @{$fileinfo{$_}} if (defined($fileinfo{$_})); - printf '\n\n\n\n\n\n\n"; + print "\n\n"; } else { print "
\n"; } @@ -912,55 +942,52 @@ if (-d $fullname) { next if (!defined($fileinfo{$_})); ($rev, $date, $log, $author) = @{$fileinfo{$_}}; $filesfound++; - printf '\n\n\n\n\n" if ($dirtable); + print "\n" if ($dirtable); print(($dirtable) ? "" : "
"); $dirrow++; } print "\n"; } - if ($dirtable && defined($tableBorderColor)) { - print "
', + printf "
", $byfile ? $columnHeaderColorSorted : $columnHeaderColorDefault; @@ -662,13 +691,13 @@ if (-d $fullname) { ) ); } - print "', + printf '', $byrev ? $columnHeaderColorSorted : $columnHeaderColorDefault; @@ -683,9 +712,9 @@ if (-d $fullname) { ) ); } - print "', + printf '', $bydate ? $columnHeaderColorSorted : $columnHeaderColorDefault; @@ -700,11 +729,11 @@ if (-d $fullname) { ) ); } - print "', + printf '', $byauthor ? $columnHeaderColorSorted : $columnHeaderColorDefault; @@ -722,10 +751,10 @@ if (-d $fullname) { ) ); } - print "', + printf '', $bylog ? $columnHeaderColorSorted : $columnHeaderColorDefault; @@ -740,11 +769,11 @@ if (-d $fullname) { ) ); } - print "', + printf '', $columnHeaderColorDefault; - print "Description"; + print "Description
', $tabcolors[$dirrow % 2] - if $dirtable; + printf "
", + $tabcolors[$dirrow % 2] if $dirtable; if ($_ eq '..') { $url = "../$query"; @@ -820,17 +849,17 @@ if (-d $fullname) { } else { print &link($backicon, $url); } - print " ", &link("Parent Directory", $url); + print ' ', &link("Parent Directory", $url); } else { $url = './' . urlencode($_) . "/$query"; - print ""; + print ""; if ($nofilelinks) { print $diricon; } else { print &link($diricon, $url); } - print " ", &link("$_/", $url), $attic; + print ' ', &link("$_/", $url), $attic; if ($_ eq "Attic") { print "  "; @@ -847,7 +876,7 @@ if (-d $fullname) { # Show last change in dir if ($filename) { - print "  " + print "  " if ($dirtable); if ($date) { print " ", @@ -856,21 +885,22 @@ if (-d $fullname) { } if ($show_author) { - print " " if ($dirtable); + print " " if ($dirtable); print $author; } - print " " if ($dirtable); + print " " if ($dirtable); $filename =~ s%^[^/]+/%%; print "$filename/$rev"; - print "
" if ($dirtable); + print "
" if ($dirtable); if ($log) { - print " ", &htmlify( - substr($log, 0, $shortLogLen)); + print " ", + &htmlify( + substr($log, 0, $shortLogLen), $allow_dir_extra); if (length $log > 80) { print "..."; } - print ""; + print ""; } } else { my ($dwhere) = @@ -879,8 +909,8 @@ if (-d $fullname) { if ($use_descriptions && defined $descriptions{$dwhere}) { - print "
 " + print " " if $dirtable; print $descriptions{$dwhere}; } elsif ($dirtable && $infocols > 1) { @@ -889,14 +919,14 @@ if (-d $fullname) { # columns, so that the vertical seperators are visible my ($cols) = $infocols; while ($cols > 1) { - print " "; + print " "; $cols--; } } } if ($dirtable) { - print "
', $tabcolors[$dirrow % 2] - if $dirtable; - print ""; + printf "
", + $tabcolors[$dirrow % 2] if $dirtable; + print ""; if ($nofilelinks) { print $fileicon; } else { print &link($fileicon, $url); } - print " ", &link($_, $url), $attic; - print " " if ($dirtable); + print ' ', &link($_, $url), $attic; + print " " if ($dirtable); download_link($fileurl, $rev, $rev, $defaultViewable ? "text/x-cvsweb-markup" : undef); - print " " if ($dirtable); + print " " if ($dirtable); if ($date) { print " ", readableTime(time() - $date, 0), ""; } if ($show_author) { - print " " if ($dirtable); + print " " if ($dirtable); print $author; } - print " " if ($dirtable); + print " " if ($dirtable); if ($log) { - print " ", - &htmlify(substr($log, 0, $shortLogLen)); + print " ", + &htmlify(substr($log, 0, $shortLogLen), $allow_dir_extra); if (length $log > 80) { print "..."; } - print ""; + print ""; } - print "
"; - } - print($dirtable == 1 ? "
\n" : "
\n"); + print($dirtable ? "\n" : "
\n"); if ($filesexists && !$filesfound) { print - "

NOTE: There are $filesexists files, but none matches the current tag ($input{only_with_tag})\n"; + "

NOTE: There are $filesexists files, but none matches the current tag ($input{only_with_tag}).

\n"; } if ($input{only_with_tag} && (!%tags || !$tags{$input{only_with_tag}})) { @@ -970,45 +997,47 @@ if (-d $fullname) { if (scalar %tags || $input{only_with_tag} || $edit_option_form || defined($input{"options"})) { - print "
"; + print "
\n"; } if (scalar %tags || $input{only_with_tag}) { - print "
\n"; + print "\n"; foreach my $var (@stickyvars) { print - "\n" + "\n" if (defined($input{$var}) && (!defined($DEFAULTVALUE{$var}) || $input{$var} ne $DEFAULTVALUE{$var}) && $input{$var} ne "" && $var ne "only_with_tag"); } - print "Show only files with tag:\n"; - print ""; - print "\n"; foreach my $tag (reverse sort { lc $a cmp lc $b } keys %tags) { - print "$tag\n"; + && $input{only_with_tag} eq $tag ? " selected" : "", + ">$tag\n"; } - print "\n"; - print " Module path or alias:\n"; - printf "\n", + print "\n"; + print " \n"; + printf "\n", htmlquote($where); - print "\n"; - print "\n"; + print "

\n"; + print "\n"; } if ($allow_tar) { my ($basefile) = ($where =~ m,(?:.*/)?([^/]+),); if (defined($basefile) && $basefile ne '') { - print "
\n", - "
Download this directory in "; + print "
\n", + "
Download this directory in "; # Mangle the filename so browsers show a reasonable # filename to download. @@ -1019,49 +1048,56 @@ if (-d $fullname) { &link("zip archive", "./$basefile.zip$query" . ($query ? "&" : "?") . "tarball=1"); } - print "
"; + print "
\n"; } } - my $formwhere = $scriptwhere; - $formwhere =~ s|Attic/?$|| if ($input{'hideattic'}); - if ($edit_option_form || defined($input{"options"})) { - print "
\n"; - print "\n"; + + my $formwhere = $scriptwhere; + $formwhere =~ s|Attic/?$|| if ($input{'hideattic'}); + + print "\n"; + print "\n"; if ($cvstree ne $cvstreedefault) { print - "\n"; + "\n"; } - print "
"; - print - ""; - print "\n"; + print "\n\n"; + print "\n\n\n
Preferences
Sort files by "; + print "\n\n"; + print "\n\n"; + print "\n"; - print "\n"; + print ""; - print "\n\n"; + print "\n"; - print "\n"; - print - "
Preferences
"; + print "Sort log by: "; + print "Revision\n"; + print "Log message\n"; + print "\n"; printLogSortSelect(0); - print "
Diff format: "; + print "
"; printDiffSelect(0); - print "Show Attic files: "; - print "
"; - print "
\n"; + print "
"; + print "
"; + print ""; + print "
\n
\n\n"; } - print &html_footer; - print "\n"; + html_footer(); } ############################### @@ -1120,7 +1156,11 @@ elsif (-f $fullname . ',v') { # The file has been removed and is in the Attic. # Send a redirect pointing to the file in the Attic. (my $newplace = $scriptwhere) =~ s|/([^/]+)$|/Attic/$1|; - redirect("$newplace$query"); + if ($ENV{QUERY_STRING} ne "") { + redirect("${newplace}?$ENV{QUERY_STRING}"); + } else { + redirect($newplace); + } exit; } elsif (0 && (my @files = &safeglob($fullname . ",v"))) { http_header("text/plain"); @@ -1146,7 +1186,9 @@ elsif (-f $fullname . ',v') { } } } - &fatal("404 Not Found", "$where: no such file or directory"); + fatal("404 Not Found", + '%s: no such file or directory', + $where); } gzipclose(); @@ -1157,34 +1199,34 @@ sub printDiffSelect($) { my ($use_java_script) = @_; my $f = $input{'f'}; - print '\n"; local $_; for (@DIFFTYPES) { - printf('\n", $_, + $f eq $_ ? ' selected' : '', "\u$DIFFTYPES{$_}{'descr'}"); } - print ""; + print ""; } sub printLogSortSelect($) { my ($use_java_script) = @_; - print '\n"; local $_; for (@LOGSORTKEYS) { - printf('\n", $_, + $logsort eq $_ ? ' selected' : '', "\u$LOGSORTKEYS{$_}{'descr'}"); } - print ""; + print ""; } sub findLastModifiedSubdirs(@) { @@ -1201,7 +1243,7 @@ sub findLastModifiedSubdirs(@) { my ($lastmodtime) = undef; my $dh = do { local (*DH); }; - opendir($dh, $dir) || next; + opendir($dh, $dir) or next; my (@filenames) = readdir($dh); closedir($dh); @@ -1262,8 +1304,7 @@ sub htmlify($;$) { if ($extra) { # get PR #'s as link: "PR#nnnn" "PR: nnnn, ..." "PR nnnn, ..." "bin/nnnn" - if (defined($prcgi) && defined($re_prcategories) - && defined($re_prkeyword)) + if (defined($prcgi) && defined($re_prkeyword)) { my $prev; @@ -1286,14 +1327,16 @@ sub htmlify($;$) { $_; } while ($_ ne $prev); - $_ = htmlify_sub { - s{ - (\b$re_prcategories/(\d+)\b) - }{ - &link($1, sprintf($prcgi, $2)) - }egox; - } - $_; + if (defined($re_prcategories)) { + $_ = htmlify_sub { + s{ + (\b$re_prcategories/(\d+)\b) + }{ + &link($1, sprintf($prcgi, $2)) + }egox; + } + $_; + } } # get manpage specs as link: "foo.1" "foo(1)" @@ -1342,7 +1385,7 @@ sub spacedHtmlText($;$) { s/ /\001nbsp;/g; } - $_ = htmlify($_); + $_ = htmlify($_, $allow_source_extra); # unescape y/\001/&/; @@ -1356,7 +1399,7 @@ sub link($$) { $url =~ s/:/sprintf("%%%02x", ord($&))/eg if $url =~ /^[^a-z]/; # relative - sprintf '%s', hrefquote($url), $name; + sprintf '%s', hrefquote($url), $name; } sub revcmp($$) { @@ -1379,16 +1422,18 @@ sub revcmp($$) { return 0; } -sub fatal($$) { - my ($errcode, $errmsg) = @_; +sub fatal($$@) { + my ($errcode, $format, @args) = @_; if ($is_mod_perl) { Apache->request->status((split (/ /, $errcode))[0]); } else { print "Status: $errcode\r\n"; } html_header("Error"); - print "Error: $errmsg\n"; - print &html_footer; + print "

Error: ", + sprintf($format, map(htmlquote($_), @args)), + "

\n"; + html_footer(); exit(1); } @@ -1402,8 +1447,8 @@ sub redirect($) { print "Location: $url\r\n"; } html_header("Moved"); - print "This document is located ", &link('here', $url), "\n"; - print &html_footer; + print "

This document is located ", &link('here', $url), "

\n"; + html_footer(); exit(1); } @@ -1514,6 +1559,16 @@ sub scan_directives(@) { ('tabstop' => $ts); } +sub openOutputFilter() { + return if !defined($output_filter) || $output_filter eq ''; + + open(STDOUT, "|-") and return; + + # child of child + open(STDERR, '>/dev/null'); + exec($output_filter) or exit -1; +} + ############################### # show Annotation ############################### @@ -1527,14 +1582,14 @@ sub doAnnotate($$) { # make sure the revisions are wellformed, for security # reasons .. if ($rev =~ /[^\w.]/) { - &fatal("404 Not Found", - "Malformed query \"$ENV{QUERY_STRING}\""); + fatal("404 Not Found", + 'Malformed query "%s"', + $ENV{QUERY_STRING}); } if (&forbidden_file($fullname)) { - &fatal("403 Forbidden", - "Access forbidden. This file is mentioned in \@ForbiddenFiles" - ); + fatal("403 Forbidden", + 'Access forbidden. This file is mentioned in @ForbiddenFiles'); return; } @@ -1552,8 +1607,8 @@ sub doAnnotate($$) { # 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, $CMD{cvs}, @cvs_options, "server") - || fatal("500 Internal Error", - "Fatal Error - unable to open cvs for annotation"); + or fatal("500 Internal Error", + 'Fatal Error - unable to open cvs for annotation'); # OK, first send the request to the server. A simplified example is: # Root /home/kingdon/zwork/cvsroot @@ -1608,13 +1663,13 @@ sub doAnnotate($$) { # OK, we've sent our command to the server. Thing to do is to # close the writer side and get all the responses. If "cvs server" # were nicer about buffering, then we could just leave it open, I think. - close($writer) || die "cannot close: $!"; + close($writer) or die "cannot close: $!"; http_header(); navigateHeader($scriptwhere, $pathname, $filename, $rev, "annotate"); print - "

Annotation of $pathname$filename, Revision $rev

\n"; + "

Annotation of $pathname$filename, Revision $rev

\n"; # Ready to get the responses from the server. # For example: @@ -1627,7 +1682,7 @@ sub doAnnotate($$) { my ($revprint, $usrprint); if ($annTable) { - print "\n"; + print "
\n"; } else { print "
";
 	}
@@ -1688,7 +1743,8 @@ sub doAnnotate($$) {
 			# CVS command line client.  But for simplicity, we don't.
 		} elsif ($words[0] eq "error") {
 			fatal("500 Internal Error",
-				"Error occured during annotate: $_");
+			      'Error occured during annotate: %s',
+			      $_);
 		}
 	}
 
@@ -1697,7 +1753,7 @@ sub doAnnotate($$) {
 	} else {
 		print "
"; } - close($reader) || warn "cannot close: $!"; + close($reader) or warn "cannot close: $!"; wait; } @@ -1716,14 +1772,14 @@ sub doCheckout($$) { # make sure the revisions a wellformed, for security # reasons .. if (defined($rev) && $rev =~ /[^\w.]/) { - &fatal("404 Not Found", - "Malformed query \"$ENV{QUERY_STRING}\""); + fatal("404 Not Found", + 'Malformed query "%s"', + $ENV{QUERY_STRING}); } if (&forbidden_file($fullname)) { - &fatal("403 Forbidden", - "Access forbidden. This file is mentioned in \@ForbiddenFiles" - ); + fatal("403 Forbidden", + 'Access forbidden. This file is mentioned in @ForbiddenFiles'); return; } @@ -1761,12 +1817,19 @@ sub doCheckout($$) { # chdir to $tmpdir before to avoid non-readable cgi-bin directories chdir($tmpdir); open(STDERR, ">&STDOUT"); # Redirect stderr to stdout - exec($CMD{cvs}, @cvs_options, '-d', $cvsroot, 'co', '-p', - $revopt, $where); + + # work around a bug of cvs -p; expand symlinks + use Cwd 'abs_path'; + exec($CMD{cvs}, @cvs_options, + '-d', abs_path($cvsroot), + 'co', '-p', + $revopt, $where) or exit -1; } if (eof($fh)) { - &fatal("404 Not Found", "$where is not (any longer) pertinent"); + fatal("404 Not Found", + '%s is not (any longer) pertinent', + $where); } #=================================================================== @@ -1790,8 +1853,9 @@ sub doCheckout($$) { } if ($filename ne $where) { - &fatal("500 Internal Error", - "Unexpected output from cvs co: $cvsheader"); + fatal("500 Internal Error", + 'Unexpected output from cvs co: %s', + $cvsheader); } $| = 1; @@ -1815,8 +1879,8 @@ sub cvswebMarkup($$$) { http_header(); navigateHeader($scriptwhere, $pathname, $filename, $revision, "view"); - print "
"; - print "
\n\n
"; + print "
"; + print "\n\n
"; print "File: ", &clickablePath($where, 1); print " ("; &download_link($fileurl, $revision, "download"); @@ -1827,27 +1891,27 @@ sub cvswebMarkup($$$) { &download_link($fileurl, $revision, "as text", "text/plain"); print ")"; } - print "
\n"; + print "
\n"; if ($show_log_in_markup) { readLog($fullname); #,$revision); printLog($revision, 0); } else { - print "Version: $revision
\n"; - print "Tag: ", $input{only_with_tag}, "
\n" + print "Version: $revision
\n"; + print "Tag: ", $input{only_with_tag}, "
\n" if $input{only_with_tag}; } - print "
"; + print "
"; my $url = download_url($fileurl, $revision, $mimetype); - print "
"; + print "
"; if ($mimetype =~ /^image/) { - printf '
', hrefquote("$url$barequery"); + printf '
', hrefquote("$url$barequery"); } elsif ($mimetype =~ m%^application/pdf%) { - printf '
', + printf '
', hrefquote("$url$barequery"); } elsif ($preformat_in_markup) { - print "
";
+		print "
";
 
 		# prefetch several lines
 		my @buf = head($filehandle);
@@ -1859,14 +1923,14 @@ sub cvswebMarkup($$$) {
 
 			print spacedHtmlText($_, $d{'tabstop'});
 		}
-		print "
"; + print "
"; } else { - print "
";
+		print "
";
 
 		while (<$filehandle>) {
 			print htmlquote($_);
 		}
-		print "
"; + print "
"; } } @@ -1885,9 +1949,8 @@ sub doDiff($$$$$$) { my ($rev1, $rev2, $sym1, $sym2, $f1, $f2); if (&forbidden_file($fullname)) { - &fatal("403 Forbidden", - "Access forbidden. This file is mentioned in \@ForbiddenFiles" - ); + fatal("403 Forbidden", + 'Access forbidden. This file is mentioned in @ForbiddenFiles'); return; } @@ -1912,8 +1975,9 @@ sub doDiff($$$$$$) { # make sure the revisions a wellformed, for security # reasons .. if ($rev1 =~ /[^\w.]/ || $rev2 =~ /[^\w.]/) { - &fatal("404 Not Found", - "Malformed query \"$ENV{QUERY_STRING}\""); + fatal("404 Not Found", + 'Malformed query "%s"', + $ENV{QUERY_STRING}); } # @@ -1928,7 +1992,9 @@ sub doDiff($$$$$$) { my $difftype = $DIFFTYPES{$f}; if (!$difftype) { - fatal("400 Bad arguments", "Diff format $f not understood"); + fatal("400 Bad arguments", + 'Diff format %s not understood', + $f); } my @difftype = @{$difftype->{'opts'}}; @@ -1959,11 +2025,13 @@ sub doDiff($$$$$$) { if (!open($fh, "-|")) { # child open(STDERR, ">&STDOUT"); # Redirect stderr to stdout - exec($CMD{rcsdiff}, @difftype, "-r$rev1", "-r$rev2", $fullname); + openOutputFilter(); + exec($CMD{rcsdiff}, @difftype, "-r$rev1", "-r$rev2", $fullname) or exit -1; } if ($human_readable) { http_header(); &human_readable_diff($fh, $rev2); + html_footer(); gzipclose(); exit; } else { @@ -2045,15 +2113,17 @@ sub getDirLogs($$@) { if (defined($tag)) { #can't use -r as - is allowed in tagnames, but misinterpreated by rlog.. - if (!open($fh, "-|")) { + if (!open($fh, "-|")) { # child open(STDERR, '>/dev/null'); # rlog may complain; ignore. - exec($CMD{rlog}, @files); + openOutputFilter(); + exec($CMD{rlog}, @files) or exit -1; } } else { - if (!open($fh, "-|")) { + if (!open($fh, "-|")) { # child open(STDERR, '>/dev/null'); # rlog may complain; ignore. - exec($CMD{rlog}, '-r', @files); + openOutputFilter(); + exec($CMD{rlog}, '-r', @files) or exit -1; } } $state = "start"; @@ -2111,7 +2181,7 @@ sub getDirLogs($$@) { } if ($state eq "tags") { - if (/^\s+(.+):\s+([\d\.]+)\s+$/) { + if (/^\s+([^:]+):\s+([\d\.]+)\s*$/) { push (@filetags, $1); $symrev{$1} = $2; $alltags{$1} = 1; @@ -2203,8 +2273,8 @@ sub getDirLogs($$@) { $state = "log"; $log = ''; next; - } elsif ($rev eq '' && /^revision (.*)$/) { - $rev = $1; + } elsif ($rev eq '' && /^revision (\d+(?:\.\d+)+).*$/) { + $rev = $1; # .*$ eats up the locker(lockers?) info, if any next; } else { $log .= $_; @@ -2218,10 +2288,9 @@ sub getDirLogs($$@) { } if ($. == 0) { - fatal("500 Internal Error", "Failed to spawn GNU rlog on '" - . join (", ", @files) - . "'

Did you set the \$command_path in your configuration file correctly ? (Currently '$command_path'" - ); + fatal("500 Internal Error", + 'Failed to spawn GNU rlog on "%s".

Did you set the $command_path in your configuration file correctly ? (Currently "%s"', + join (", ", @files), $command_path); } close($fh); } @@ -2249,9 +2318,11 @@ sub readLog($;$) { print("Going to rlog '$fullname'\n") if ($verbose); if (!open($fh, "-|")) { # child if ($revision ne '') { - exec($CMD{rlog}, $revision, $fullname); + openOutputFilter(); + exec($CMD{rlog}, $revision, $fullname) or exit -1; } else { - exec($CMD{rlog}, $fullname); + openOutputFilter(); + exec($CMD{rlog}, $fullname) or exit -1; } } @@ -2281,13 +2352,18 @@ sub readLog($;$) { # date: 1995/11/29 22:15:52; author: fenner; state: Exp; lines: +5 -3 # log info # ---------------------------- + + # For a locked revision, the first line after the separator + # becomes smth like + # revision 9.19 locked by: vassilii; + logentry: while (!/$LOG_FILESEPARATOR/o) { $_ = <$fh>; last logentry if (!defined($_)); # EOF print "R:", $_ if ($verbose); - if (/^revision ([\d\.]+)/) { + if (/^revision (\d+(?:\.\d+)+)/) { $rev = $1; unshift (@allrevisions, $rev); } elsif (/$LOG_FILESEPARATOR/o || /$LOG_REVSEPARATOR/o) { @@ -2302,8 +2378,6 @@ sub readLog($;$) { # these lines since we don't know what revision they go with # any more. next logentry; - - # &fatal("500 Internal Error","Error parsing RCS output: $_"); } $_ = <$fh>; print "D:", $_ if ($verbose); @@ -2323,8 +2397,9 @@ sub readLog($;$) { $state{$rev} = $8; $difflines{$rev} = $10; } else { - &fatal("500 Internal Error", - "Error parsing RCS output: $_"); + fatal("500 Internal Error", + 'Error parsing RCS output: %s', + $_); } line: @@ -2416,7 +2491,7 @@ sub readLog($;$) { } $revsym{$rev} .= ", " if ($revsym{$rev}); $revsym{$rev} .= $_; - $sel .= "\n"; } print "Done associating revisions with branches\n" if ($verbose); @@ -2431,7 +2506,8 @@ sub readLog($;$) { if (!defined($onlyonbranch) || $onlybranchpoint eq "") { fatal("404 Tag not found", - "Tag $input{'only_with_tag'} not defined"); + 'Tag %s not defined', + $input{'only_with_tag'}); } } @@ -2490,15 +2566,16 @@ sub printLog($;$) { $link = 1 if (!defined($link)); $isDead = ($state{$_} eq "dead"); + print "

\n"; if ($link && !$isDead) { my ($filename); ($filename = $where) =~ s/^.*\///; my ($fileurl) = urlencode($filename); - print ""; + print ""; if (defined($revsym{$_})) { foreach my $sym (split (", ", $revsym{$_})) { - print ""; + print ""; } } @@ -2506,7 +2583,7 @@ sub printLog($;$) { && !defined($nameprinted{$br})) { foreach my $sym (split (", ", $revsym{$br})) { - print ""; + print ""; } $nameprinted{$br} = 1; } @@ -2561,7 +2638,7 @@ sub printLog($;$) { } } } else { - print "Revision $_"; + print "Revision $_"; } if (/^1\.1\.1\.\d+$/) { @@ -2576,13 +2653,13 @@ sub printLog($;$) { print readableTime(time() - $date{$_}, 1), " ago)"; print " by "; print "", $author{$_}, "\n"; - print "
Branch: ", $link ? link_tags($revsym{$br}) : $revsym{$br}, + print "
Branch: ", $link ? link_tags($revsym{$br}) : $revsym{$br}, "\n" if ($revsym{$br}); - print "
CVS Tags: ", $link ? link_tags($revsym{$_}) : $revsym{$_}, + print "
CVS Tags: ", $link ? link_tags($revsym{$_}) : $revsym{$_}, "" if ($revsym{$_}); - print "
Branch point for: ", + print "
Branch point for: ", $link ? link_tags($branchpoint{$_}) : $branchpoint{$_}, "\n" if ($branchpoint{$_}); @@ -2601,17 +2678,18 @@ sub printLog($;$) { if ($prev ne "") { if ($difflines{$_}) { print - "
Changes since $prev: $difflines{$_} lines"; + "
Changes since $prev: $difflines{$_} lines"; } } if ($isDead) { - print "
FILE REMOVED\n"; + print "
FILE REMOVED\n"; } elsif ($link) { my %diffrev = (); $diffrev{$_} = 1; $diffrev{""} = 1; - print "
Diff"; + print '
'; + my $diff = 'Diff'; # # Offer diff to previous revision @@ -2622,7 +2700,8 @@ sub printLog($;$) { sprintf('%s.diff?r1=%s&r2=%s%s', $scriptwhere, $prev, $_, $barequery); - print " to previous "; + print $diff, " to previous "; + $diff = ''; printDiffLinks($prev, $url); } @@ -2636,7 +2715,8 @@ sub printLog($;$) { sprintf('%s.diff?r1=%s&r2=%s%s', $scriptwhere, $brp, $_, $barequery); - print " to branchpoint "; + print $diff, " to branchpoint "; + $diff = ''; printDiffLinks($brp, $url); } @@ -2678,7 +2758,8 @@ sub printLog($;$) { $scriptwhere, $nextmain, $_, $barequery); - print " next main "; + print $diff, " next main "; + $diff = ''; printDiffLinks($nextmain, $url); } } @@ -2692,13 +2773,15 @@ sub printLog($;$) { sprintf('%s.diff?r1=%s&r2=%s%s', $scriptwhere, $input{'r1'}, $_, $barequery); - print " to selected "; + print $diff, " to selected "; + $diff = ''; printDiffLinks($input{'r1'}, $url); } + } - print "

\n";
-	print &htmlify($log{$_}, 1);
-	print "
\n"; + print "\n

\n
\n";
+	print &htmlify($log{$_}, $allow_log_extra);
+	print "
\n"; } sub doLog($) { @@ -2711,120 +2794,129 @@ sub doLog($) { ($upwhere = $where) =~ s|(Attic/)?[^/]+$||; ($filename = $where) =~ s|^.*/||; $backurl = $scriptname . "/" . urlencode($upwhere) . $query; + print "

\n "; print &link($backicon, "$backurl#$filename"), " Up to ", - &clickablePath($upwhere, 1), "

\n"; + &clickablePath($upwhere, 1), "\n

\n"; + print "

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


'; + print "\n

\n
\n"; + print "

\n"; if ($curbranch) { print "Default branch: ", ($revsym{$curbranch} || $curbranch); } else { print "No default branch"; } - print "
\n"; + print "
\n"; if ($input{only_with_tag}) { - print "Current tag: $input{only_with_tag}
\n"; + print "Current tag: $input{only_with_tag}
\n"; } + print "

\n"; undef %nameprinted; for (my $i = 0 ; $i <= $#revdisplayorder ; $i++) { - print "
"; + print "
\n"; printLog($revdisplayorder[$i]); } - print "
"; - print "\n"; + print "
\n

\n"; + print "\n"; print "This form allows you to request diff's between any two\n"; print "revisions of a file. You may select a symbolic revision\n"; print "name using the selection box or you may type in a numeric\n"; print "name using the type-in text box.\n"; - print "

\n"; + print "\n

\n"; print - "
\n"; + "\n"; foreach (@stickyvars) { - printf('', $_, + printf('', $_, $input{$_}) if (defined($input{$_}) && ((!defined($DEFAULTVALUE{$_}) || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne "")); } - print "\n"; - print "\n"; + print "\n"; + print "\n
Diffs between \n"; - print "\n\n"; + print ""; - print "\n"; - print "\n"; + print "\n\n"; + print "\n"; - print "\n"; - print "\n"; - print "
"; + print "\n"; + print "\n"; + print "\n"; $diffrev = $revdisplayorder[$#revdisplayorder]; $diffrev = $input{"r1"} if (defined($input{"r1"})); print - "
and \n"; - print "
"; + print "\n"; + print "\n"; + print "\n"; $diffrev = $revdisplayorder[0]; $diffrev = $input{"r2"} if (defined($input{"r2"})); print - "
\n"; - print "
\n"; - print ""; - print "\n"; - print ""; - print "\n"; + print "\n"; + print "\n
Preferred Diff type:"; + "
\n"; + print "\n"; + print "
\n"; + print "
\n"; + print "\n"; + print "\n\n"; + print "\n"; + print "\n\n\n"; if (@branchnames) { - print ""; - print "\n"; + print "\n"; + print "\n\n\n"; } foreach (@stickyvars) { next if ($_ eq "f"); next if ($_ eq "only_with_tag"); next if ($_ eq "logsort"); - print "\n" + print "\n" if (defined($input{$_}) && (!defined($DEFAULTVALUE{$_}) || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne ""); } - print ""; - print "\n\n"; - print ""; - print "\n"; - print "
"; + print ""; printDiffSelect($use_java_script); - print "
View only Branch:"; - print "\n"; - print ""; + print ""; + print "\n"; + print "
"; - print "\n"; - print "Sort log by:"; + print "
"; + print "\n"; + print ""; printLogSortSelect($use_java_script); - print "
"; - print &html_footer; - print "\n"; + print "
\n"; + print "\n"; + html_footer(); } sub flush_diff_rows($$$$) { @@ -2838,32 +2930,33 @@ sub flush_diff_rows($$$$) { if ($state eq "PreChangeRemove") { # we just got remove-lines before for ($j = 0 ; $j < $leftRow ; $j++) { print - "@$leftColRef[$j]"; + "\n @$leftColRef[$j]\n"; print - " \n"; + " \n\n"; } } elsif ($state eq "PreChange") { # state eq "PreChange" # we got removes with subsequent adds for ($j = 0 ; $j < $leftRow || $j < $rightRow ; $j++) { # dump out both cols - print ""; + print "\n"; if ($j < $leftRow) { print - "@$leftColRef[$j]"; + " @$leftColRef[$j]"; } else { print - " "; + " "; } + print "\n"; if ($j < $rightRow) { print - "@$rightColRef[$j]"; + " @$rightColRef[$j]"; } else { print - " "; + " "; } - print "\n"; + print "\n\n"; } } } @@ -2902,29 +2995,23 @@ sub human_readable_diff($) { } print - "

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

\n", - "\n", - "\n", "
", + "

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

\n", + # Using style=\"border: none\" here breaks NS 4.x badly... + "\n", + "\n", "\n", "\n", "\n"; - my $fs = ""; - my $fe = ""; - my $leftRow = 0; my $rightRow = 0; my ($oldline, $newline, $funname, $diffcode, $rest); # Process diff text - # The diffrows are could make excellent use of - # cascading style sheets because we've to set the - # font and color for each row. anyone ...? - #### # prefetch several lines my @buf = head($fh); @@ -2938,17 +3025,18 @@ sub human_readable_diff($) { ($oldline, $newline, $funname) = $difftxt =~ /@@ \-([0-9]+).*\+([0-9]+).*@@(.*)/; $funname = htmlquote($funname); + $funname =~ s/\s/ /go; print - "\n\n\n"; $state = "dump"; $leftRow = 0; @@ -2957,9 +3045,6 @@ sub human_readable_diff($) { ($diffcode, $rest) = $difftxt =~ /^([-+ ])(.*)/; $_ = spacedHtmlText($rest, $d{'tabstop'}); - # Add fontface, size - $_ = "$fs $_$fe"; - ######### # little state machine to parse unified-diff output (Hen, zeller@think.de) # in order to get some nice 'ediff'-mode output @@ -2973,7 +3058,7 @@ sub human_readable_diff($) { if ($state eq "dump") { # 'change' never begins with '+': just dump out value print - "\n"; + "\n\n\n\n"; } else { # we got minus before $state = "PreChange"; $rightCol[$rightRow++] = $_; @@ -2984,60 +3069,56 @@ sub human_readable_diff($) { } else { # empty diffcode flush_diff_rows \@leftCol, \@rightCol, $leftRow, $rightRow; - print "\n"; + print "\n\n\n\n"; $state = "dump"; $leftRow = 0; $rightRow = 0; } } } + close($fh); + flush_diff_rows \@leftCol, \@rightCol, $leftRow, $rightRow; # state is empty if we didn't have any change if (!$state) { - print ""; - print ""; + print "\n\n\n"; + print "\n"; print - ""; + "\n\n"; } - print "
", "version $rev1"; print ", $date1" if (defined($date1)); print "
Tag: $sym1\n" if ($sym1); - print "
", "version $rev2"; + print "", "version $rev2"; print ", $date2" if (defined($date2)); print "
Tag: $sym2\n" if ($sym1); print "
"; + "
"; print - "\n\n
Line $oldline"; + "\n\n
Line $oldline"; print - " $funname
"; - print "
"; + " $funname
"; + print "
"; print - "\n\n
Line $newline"; + "\n\n
Line $newline"; print - " $funname
"; + " $funname
\n"; print "
 $_
  $_
$_$_
 $_ $_
 
 
- No viewable Change -
- No viewable change -
"; - close($fh); + print "
\n"; - print "

\n"; + print "
\n"; + print "
\n"; + print "\n\n\n"; + print "\n"; + print "\n"; - print "
\n"; - print ""; - - print "\n\n
"; - # print legend - print "\n\n\n\n"; + print "
"; - print "Legend:
\n"; + print "
\n\n
"; + print "Legend:
\n"; print - ""; + "\n\n\n\n"; print - ""; + "\n\n\n"; print - ""; - print "
Removed from v.$rev1 
Removed from v.$rev1 
changed lines
changed lines
 Added in v.$rev2
\n"; + "
 Added in v.$rev2
\n
\n
"; - print ""; - # Print format selector - print "\n"; foreach my $var (keys %input) { next if ($var eq "f"); next if (defined($DEFAULTVALUE{$var}) && $DEFAULTVALUE{$var} eq $input{$var}); - print "\n"; + print "\n"; } printDiffSelect($use_java_script); - print "\n"; - print "\n"; - print "
"; + print "\n\n"; + print "\n"; } sub navigateHeader($$$$$) { @@ -3045,16 +3126,51 @@ sub navigateHeader($$$$$) { $swhere = "" if ($swhere eq $scriptwhere); $swhere = './' . urlencode($filename) if ($swhere eq ""); + # TODO: this should be moved into external CSS file. + my $css = ''; + if ($title eq 'diff') { + $css = " +"; + } + print < - - - - -$path$filename - $title - $rev +$HTML_DOCTYPE + + +$path$filename - $title - $rev$css +$HTML_META $body_tag_for_src - -\n\n
+ +"; - print ""; print "
EOF print &link($backicon, "$swhere$query#rev$rev"); @@ -3062,7 +3178,8 @@ EOF " CVS log"; print " $fileicon$diricon Up to ", &clickablePath($path, 1), + print "$diricon Up to ", + &clickablePath($path, 1), "
"; } @@ -3167,46 +3284,50 @@ sub clickablePath($$) { } sub chooseCVSRoot() { + + print "
\n"; if (2 <= @CVSROOT) { my ($k); - print "\n"; foreach $k (keys %input) { - print "\n" + print "\n" if ($input{$k}) && ($k ne "cvsroot"); } # Form-Elements look wierd in Netscape if the background # isn't gray and the form elements are not placed # within a table ... - print ""; - print ""; - print "\n"; + print "\n"; + print ""; - print "\n
CVS Root:\n
\n\n"; + print "\n"; } else { - # no choice -- but we need the form to select module/path, at least for Netscape - print "\n"; + # no choice -- but we need the form to select module/path, + # at least for Netscape + print "

\n"; print "CVS Root: [$cvstree]"; } - print " Module path or alias:\n"; - print "\n"; - print ""; + print " \n"; + print "\n"; + print ""; if (2 <= @CVSROOT) { - print "

"; + print "
"; + } else { + print "

"; } - print ""; + print "\n"; } sub chooseMirror() { @@ -3219,7 +3340,7 @@ sub chooseMirror() { # # Should perhaps exlude the current site somehow.. if (keys %MIRRORS) { - print "\nThis cvsweb is mirrored in:\n"; + print "\nThis CVSweb is mirrored in:\n"; foreach $mirror (keys %MIRRORS) { print ", " if ($moremirrors); @@ -3276,7 +3397,7 @@ sub download_url($$;$) { && (!defined($mimetype) || $mimetype ne "text/x-cvsweb-markup")) { my $path = $where; - $path =~ s|/[^/]*$|/|; + $path =~ s|[^/]+$||; $url = "$scriptname/$checkoutMagic/${path}$url"; } $url .= "?rev=$revision"; @@ -3293,7 +3414,7 @@ sub download_link($$$;$) { $fullurl =~ s/:/sprintf("%%%02x", ord($&))/eg; - printf '$textlink"; + print ">$textlink"; } # Returns a Query string with the @@ -3430,7 +3555,7 @@ sub http_header(;$) { if ($is_mod_perl) { Apache->request->content_type($content_type); } else { - print "Content-type: $content_type\r\n"; + print "Content-Type: $content_type\r\n"; } if ($allow_compress && $maycompress) { @@ -3445,7 +3570,7 @@ sub http_header(;$) { Vary => "Accept-Encoding"); Apache->request->send_http_header; } else { - print "Content-encoding: x-gzip\r\n"; + print "Content-Encoding: x-gzip\r\n"; print "Vary: Accept-Encoding\r\n" ; #RFC 2068, 14.43 print "\r\n"; # Close headers @@ -3467,7 +3592,7 @@ sub http_header(;$) { print "\r\n"; # Close headers } print - "Unable to find gzip binary in the \$command_path ($command_path) to compress output
"; + "Unable to find gzip binary in the \$command_path ($command_path) to compress output
"; } } else { @@ -3483,21 +3608,18 @@ sub html_header($) { my ($title) = @_; http_header("text/html"); print < +$HTML_DOCTYPE - $title - - +$HTML_META $body_tag $logo

$title

EOH } sub html_footer() { - return "
$address
\n"; + print "
\n
$address
\n\n\n"; } sub link_tags($) {