=================================================================== RCS file: /cvs/cvsweb/cvsweb.cgi,v retrieving revision 1.1.1.30 retrieving revision 1.1.1.36 diff -u -p -r1.1.1.30 -r1.1.1.36 --- cvsweb/cvsweb.cgi 2002/05/22 07:00:03 1.1.1.30 +++ cvsweb/cvsweb.cgi 2002/09/30 19:48:52 1.1.1.36 @@ -3,14 +3,15 @@ # cvsweb - a CGI interface to CVS trees. # # Written in their spare time by -# Bill Fenner (original work) -# extended by Henner Zeller , -# Henrik Nordstrom -# Ken Coar -# Dick Balaska -# Akinori MUSHA -# Jens-Uwe Mager -# Ville Skyttä (html cleanup) +# Bill Fenner (original work) +# extended by Henner Zeller , +# Henrik Nordstrom +# Ken Coar +# Dick Balaska +# Akinori MUSHA +# Jens-Uwe Mager +# Ville Skyttä +# Vassilii Khachaturov # # Based on: # * Bill Fenners cvsweb.cgi revision 1.28 available from: @@ -18,8 +19,9 @@ # # Copyright (c) 1996-1998 Bill Fenner # (c) 1998-1999 Henner Zeller -# (c) 1999 Henrik Nordstrom -# (c) 2000-2002 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 @@ -43,7 +45,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $FreeBSD: projects/cvsweb/cvsweb.cgi,v 1.102 2002/05/22 06:51:59 knu Exp $ +# $FreeBSD: projects/cvsweb/cvsweb.cgi,v 1.119.2.6 2002/09/26 20:56:05 scop Exp $ # $zId: cvsweb.cgi,v 1.112 2001/07/24 13:03:16 hzeller Exp $ # $Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.84 2001/10/07 20:50:10 knu Exp $ # @@ -91,8 +93,8 @@ use vars qw ( $module $use_descriptions %descriptions @mytz $dwhere $moddate $use_moddate $has_zlib $gzip_open $allow_tar @tar_options @gzip_options @zip_options @cvs_options - $LOG_FILESEPARATOR $LOG_REVSEPARATOR - $tmpdir $HTML_DOCTYPE + @annotate_options $LOG_FILESEPARATOR $LOG_REVSEPARATOR + $tmpdir $HTML_DOCTYPE $HTML_META ); sub printDiffSelect($); @@ -104,7 +106,7 @@ sub htmlify($;$); sub spacedHtmlText($;$); sub link($$); sub revcmp($$); -sub fatal($$); +sub fatal($$@); sub redirect($); sub safeglob($); sub search_path($); @@ -147,7 +149,7 @@ sub forbidden_module($); ##### Start of Configuration Area ######## delete $ENV{PATH}; -$cvsweb_revision = '2.0.2'; +$cvsweb_revision = '2.0.6'; use File::Basename (); @@ -185,7 +187,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 = $HTML_DOCTYPE = undef; + $gzip_open = $HTML_DOCTYPE = $HTML_META = undef; $tmpdir = defined($ENV{TMPDIR}) ? $ENV{TMPDIR} : "/var/tmp"; $LOG_FILESEPARATOR = q/^={77}$/; @@ -236,6 +238,13 @@ $LOG_REVSEPARATOR = q/^-{28}$/; $HTML_DOCTYPE = ''; +$HTML_META = < + + + +EOM + ##### End of configuration variables ##### use Time::Local (); @@ -305,19 +314,13 @@ $maycompress = @unsafevars = qw(logsort only_with_tag r1 r2 rev sortby tr1 tr2); if (-f $config) { - do "$config" or &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; @@ -341,9 +344,12 @@ $input{only_with_tag} = $input{only_on_branch} # Prevent cross-site scripting foreach (@unsafevars) { - if (defined($input{$_}) && $input{$_} =~ /[^\w\-.]/) { - fatal("500 Internal Error", "Malformed query string ($_)"); - } + # Colons are needed in diffs between tags. + if (defined($input{$_}) && $input{$_} =~ /[^\w\-.:]/) { + fatal("500 Internal Error", + 'Malformed query (%s=%s)', + $_, $input{$_}); + } } if (defined($input{"content-type"})) { @@ -447,10 +453,9 @@ $logsort = $input{'logsort'}; ## 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 @@ -463,8 +468,7 @@ if ($input{'cvsroot'} && $CVSROOT{$input{'cvsroot'}}) $cvsroot = $CVSROOT{$cvstree}; # create icons out of description -my $k; -foreach $k (keys %ICONS) { +foreach my $k (keys %ICONS) { no strict 'refs'; my ($itxt, $ipath, $iwidth, $iheight) = @{$ICONS{$k}}; if ($ipath) { @@ -476,20 +480,15 @@ foreach $k (keys %ICONS) { ${"${k}icon"} = $itxt; } } -undef $k; my $config_cvstree = "$config-$cvstree"; # Do some special configuration for cvstrees if (-f $config_cvstree) { - do "$config_cvstree" or &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; @@ -526,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.'); } # @@ -537,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,/([^/]*)$,,; @@ -552,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 $tmpexportdir = "$tmpdir/.cvsweb.$$." . int(time); mkdir($tmpexportdir, 0700) - or &fatal("500 Internal Error", - "Unable to make temporary directory: $!"); + or fatal("500 Internal Error", + 'Unable to make temporary directory: %s', + $!); my @fatal; @@ -575,7 +577,9 @@ if ($input{tarball}) { if (system $CMD{cvs}, @cvs_options, '-Qd', $cvsroot, 'export', '-r', $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. @@ -585,18 +589,22 @@ if ($input{tarball}) { system "$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"; system "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'); } } @@ -612,7 +620,9 @@ if ($input{tarball}) { ############################### if (-d $fullname) { my $dh = do { local (*DH); }; - opendir($dh, $fullname) or &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) @@ -628,14 +638,14 @@ 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"; @@ -800,39 +810,37 @@ if (-d $fullname) { my $filesexists; my $filesfound; - foreach (sort { &fileSortCmp } @dir) { - if ($_ eq '.') { - next; - } + foreach my $file (sort { &fileSortCmp } @dir) { + next if ($file eq '.'); + # ignore CVS lock and stale NFS files - next if (/^#cvs\.|^,|^\.nfs/); + next if ($file =~ /^#cvs\.|^,|^\.nfs/); # Check whether to show the CVSROOT path - next if ($input{'hidecvsroot'} && ($_ eq 'CVSROOT')); + next if ($input{'hidecvsroot'} && $file eq 'CVSROOT'); # Check whether the module is in the restricted list - next if ($_ && &forbidden_module($_)); + next if ($file && &forbidden_module($file)); # Ignore non-readable files - next if ($input{'hidenonreadable'} && !(-r "$fullname/$_")); + next if ($input{'hidenonreadable'} && !(-r "$fullname/$file")); - if (s|^Attic/||) { + if ($file =~ s|^Attic/||) { $attic = " (in the Attic) " . $hideAtticToggleLink; } else { $attic = ""; } - if ($_ eq '..' || -d "$fullname/$_") { - next if ($_ eq '..' && $where eq '/'); - my ($rev, $date, $log, $author, $filename); - ($rev, $date, $log, $author, $filename) = - @{$fileinfo{$_}} - if (defined($fileinfo{$_})); + if ($file eq '..' || -d "$fullname/$file") { + next if ($file eq '..' && $where eq '/'); + my ($rev, $date, $log, $author, $filename) = + @{$fileinfo{$file}} + if (defined($fileinfo{$file})); printf "\n", $tabcolors[$dirrow % 2] if $dirtable; - if ($_ eq '..') { + if ($file eq '..') { $url = "../$query"; if ($nofilelinks) { print $backicon; @@ -841,17 +849,17 @@ if (-d $fullname) { } print ' ', &link("Parent Directory", $url); } else { - $url = './' . urlencode($_) . "/$query"; - print ""; + $url = './' . urlencode($file) . "/$query"; + print ""; if ($nofilelinks) { print $diricon; } else { print &link($diricon, $url); } - print ' ', &link("$_/", $url), $attic; + print ' ', &link("$file/", $url), $attic; - if ($_ eq "Attic") { + if ($file eq "Attic") { print "  "; print &link( "[Don't hide]", @@ -894,7 +902,7 @@ if (-d $fullname) { } } else { my ($dwhere) = - ($where ne "/" ? $where : "") . $_; + ($where ne "/" ? $where : "") . $file; if ($use_descriptions && defined $descriptions{$dwhere}) @@ -921,27 +929,29 @@ if (-d $fullname) { print "
\n"; } $dirrow++; - } elsif (s/,v$//) { - $fileurl = ($attic ? "Attic/" : "") . urlencode($_); + } elsif ($file =~ s/,v$//) { + + # Skip forbidden files now so we'll give no hint + # about their existence. This should probably have + # been done earlier, but it's straightforward here. + next if forbidden_file("$fullname/$file"); + + $fileurl = ($attic ? "Attic/" : "") . urlencode($file); $url = './' . $fileurl . $query; - my $rev = ''; - my $date = ''; - my $log = ''; - my $author = ''; $filesexists++; - next if (!defined($fileinfo{$_})); - ($rev, $date, $log, $author) = @{$fileinfo{$_}}; + next if (!defined($fileinfo{$file})); + my ($rev, $date, $log, $author) = @{$fileinfo{$file}}; $filesfound++; printf "\n", $tabcolors[$dirrow % 2] if $dirtable; - print ""; + print ""; if ($nofilelinks) { print $fileicon; } else { print &link($fileicon, $url); } - print ' ', &link($_, $url), $attic; + print ' ', &link(htmlquote($file), $url), $attic; print "\n " if ($dirtable); download_link($fileurl, $rev, $rev, $defaultViewable ? "text/x-cvsweb-markup" : @@ -1000,8 +1010,9 @@ if (-d $fullname) { || $input{$var} ne $DEFAULTVALUE{$var}) && $input{$var} ne "" && $var ne "only_with_tag"); } - print "

Show only files with tag:\n"; - print ""; print "\n"; @@ -1013,10 +1024,11 @@ if (-d $fullname) { ">$tag\n"; } print "\n"; - print " Module path or alias:\n"; - printf "\n", + print " \n"; + printf "\n", htmlquote($where); - print "

\n"; + print "

\n"; print "\n"; } @@ -1054,7 +1066,9 @@ if (-d $fullname) { print "
\n"; print "\n\n"; print "\n\n"; - print "\n\n\n"; - print "\n\n"; - print "\n\n\n"; - print "\n\n"; + ">\n\n"; print "\n\n\n
Preferences
Sort files by
"; + print "\nSort log by: "; + print ""; printLogSortSelect(0); print "
Diff format: "; + print "
"; printDiffSelect(0); print "
"; - print ""; + print ""; print "
\n
\n\n"; } html_footer(); @@ -1087,6 +1104,13 @@ if (-d $fullname) { # View Files ############################### elsif (-f $fullname . ',v') { + + if (forbidden_file($fullname)) { + fatal('403 Forbidden', + 'Access forbidden. This file is mentioned in @ForbiddenFiles'); + return; + } + if (defined($input{'rev'}) || $doCheckout) { &doCheckout($fullname, $input{'rev'}); gzipclose(); @@ -1169,7 +1193,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(); @@ -1180,7 +1206,7 @@ sub printDiffSelect($) { my ($use_java_script) = @_; my $f = $input{'f'}; - print '\n"; @@ -1232,6 +1258,11 @@ sub findLastModifiedSubdirs(@) { $filename = "$dirname/$filename"; my ($file) = "$fullname/$filename"; next if ($filename !~ /,v$/ || !-f $file); + + # Skip forbidden files. + (my $f = $file) =~ s/,v$//; + next if forbidden_file($f); + $filename =~ s/,v$//; my $modtime = -M $file; @@ -1374,6 +1405,7 @@ sub spacedHtmlText($;$) { return $_; } +# Note that this doesn't htmlquote the first argument... sub link($$) { my ($name, $url) = @_; @@ -1403,15 +1435,17 @@ 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: ", htmlquote($errmsg), "

\n"; + print "

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

\n"; html_footer(); exit(1); } @@ -1561,17 +1595,11 @@ 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" - ); - return; - } - ($pathname = $where) =~ s/(Attic\/)?[^\/]*$//; ($filename = $where) =~ s/^.*\///; @@ -1579,16 +1607,27 @@ sub doAnnotate($$) { $| = 1; $| = 0; # Flush + # Work around a mod_perl bug (?) in order to make open2() work. + # Search for "untie STDIN" in mod_perl mailing list archives. + my $old_stdin; + if ($is_mod_perl && ($old_stdin = tied *STDIN)) { + local $^W = undef; + untie *STDIN; + } + # this annotate version is based on the # cvs annotate-demo Perl script by Cyclic Software # It was written by Cyclic Software, http://www.cyclic.com/, and is in # 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, $CMD{cvs}, @cvs_options, "server") + $pid = open2($reader, $writer, $CMD{cvs}, @annotate_options, 'server') or fatal("500 Internal Error", - "Fatal Error - unable to open cvs for annotation"); + 'Fatal Error - unable to open cvs for annotation'); + # Re-tie STDIN if we fiddled around with it earlier, just to be sure. + tie(*STDIN, ref($old_stdin), $old_stdin) if ($old_stdin && !tied(*STDIN)); + # OK, first send the request to the server. A simplified example is: # Root /home/kingdon/zwork/cvsroot # Argument foo/xx @@ -1722,7 +1761,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', + $_); } } @@ -1731,6 +1771,8 @@ sub doAnnotate($$) { } else { print ""; } + html_footer(); + close($reader) or warn "cannot close: $!"; wait; } @@ -1750,17 +1792,11 @@ 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" - ); - return; - } - # get mimetype if (defined($input{"content-type"}) && ($input{"content-type"} =~ /\S\/\S/)) @@ -1805,7 +1841,9 @@ sub doCheckout($$) { } if (eof($fh)) { - &fatal("404 Not Found", "$where is not (any longer) pertinent"); + fatal("404 Not Found", + '%s is not (any longer) pertinent', + $where); } #=================================================================== @@ -1829,8 +1867,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; @@ -1924,9 +1963,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; } @@ -1951,8 +1989,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}); } # @@ -1967,7 +2006,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'}}; @@ -2074,7 +2115,7 @@ sub getDirLogs($$@) { push (@files, &safeglob("$DirName/*,v")); push (@files, &safeglob("$DirName/Attic/*,v")) if (!$input{'hideattic'}); - foreach $file (@otherFiles) { + foreach my $file (@otherFiles) { push (@files, "$DirName/$file"); } @@ -2261,10 +2302,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); } @@ -2352,8 +2392,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); @@ -2373,8 +2411,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: @@ -2481,7 +2520,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'}); } } @@ -2752,7 +2792,6 @@ sub printLog($;$) { printDiffLinks($input{'r1'}, $url); } - print '
' if $diff; } print "\n

\n
\n";
 	print &htmlify($log{$_}, $allow_log_extra);
@@ -2814,41 +2853,47 @@ sub doLog($) {
 		    || $input{$_} ne $DEFAULTVALUE{$_}) && $input{$_} ne ""));
 	}
 	print "\n\n";
-	print "\n";
+	    "\n";
 	print "\n\n";
-	print "\n\n\n";
-	print "\n";
+	    "\n";
+	print "\n";
 	print "\n
Diffs between \n"; - print ""; + print "\n"; + print "\n"; $diffrev = $revdisplayorder[$#revdisplayorder]; $diffrev = $input{"r1"} if (defined($input{"r1"})); print - "
and \n"; - print "
"; + print "\n"; + print "\n"; $diffrev = $revdisplayorder[0]; $diffrev = $input{"r2"} if (defined($input{"r2"})); print - "
\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; - print "\n\n"; + print "\n\n"; print "\n\n\n"; if (@branchnames) { - print "\n\n"; + print "\n\n"; print "\n"; - print "\n\n"; - print "\n"; + print "\n"; print "\n
Preferred Diff type:
"; + print ""; printDiffSelect($use_java_script); print "
View only Branch:
"; + print ""; print "\n"; - print ""; print "\n"; - print "Sort log by:"; + print ""; printLogSortSelect($use_java_script); print "
\n"; print "
\n"; html_footer(); @@ -3135,12 +3180,8 @@ sub navigateHeader($$$$$) { $HTML_DOCTYPE - - - - $path$filename - $title - $rev$css - +$HTML_META $body_tag_for_src
@@ -3270,8 +3311,8 @@ sub chooseCVSRoot() { # isn't gray and the form elements are not placed # within a table ... print "\n\n"; - print "\n"; - print "\n"; + print "\n\n
CVS Root:\n\n\n"; - print ""; + print " \n"; + print "\n"; + print ""; if (2 <= @CVSROOT) { print "
"; @@ -3303,24 +3345,24 @@ sub chooseCVSRoot() { } sub chooseMirror() { - my ($mirror, $moremirrors); - $moremirrors = 0; # This code comes from the original BSD-cvsweb # and may not be useful for your site; If you don't - # set %MIRRORS this won't show up, anyway - # - # Should perhaps exlude the current site somehow.. - if (keys %MIRRORS) { - print "\nThis cvsweb is mirrored in:\n"; + # set %MIRRORS this won't show up, anyway. + scalar(%MIRRORS) or return; - foreach $mirror (keys %MIRRORS) { - print ", " if ($moremirrors); - print &link(htmlquote($mirror), $MIRRORS{$mirror}); - $moremirrors = 1; - } - print "

\n"; + # Should perhaps exclude the current site somehow... + print "\n

\nThis CVSweb is mirrored in\n"; + + my @tmp = map(&link(htmlquote($_), $MIRRORS{$_}), + sort keys %MIRRORS); + my $tmp = pop(@tmp); + + if (scalar(@tmp)) { + print join(', ', @tmp), ' and '; } + + print "$tmp.\n

\n"; } sub fileSortCmp() { @@ -3348,10 +3390,14 @@ sub fileSortCmp() { if ($comp == 0) { - # Directories first, then sorted on name if no other sort critera - # available. - my $ad = ((-d "$fullname/$a") ? "D" : "F"); - my $bd = ((-d "$fullname/$b") ? "D" : "F"); + # Directories first, then files under version control, + # then other, "rogue" files. + # Sort by filename if no other criteria available. + + my $ad = ((-d "$fullname/$a") ? 'D' + : (defined($fileinfo{$af}) ? 'F' : 'R')); + my $bd = ((-d "$fullname/$b") ? 'D' + : (defined($fileinfo{$bf}) ? 'F' : 'R')); ($c = $a) =~ s|.*/||; ($d = $b) =~ s|.*/||; $comp = ("$ad$c" cmp "$bd$d"); @@ -3411,7 +3457,7 @@ sub download_link($$$;$) { # currently, the best way is to comment out the size parameters # ($extern_window...) in cvsweb.conf. if ($use_java_script) { - my @attr = qw(resizeable scrollbars); + my @attr = qw(resizable scrollbars); push @attr, qw(status toolbar) if (defined($mimetype) && $mimetype eq "text/html"); @@ -3428,7 +3474,7 @@ sub download_link($$$;$) { # the same window *twice*. printf q` onclick="window.open('%s','cvs_checkout','%s');return false"`, - hrefquote($fullurl), join (',', @attr); + hrefquote("$fullurl$barequery"), join (',', @attr); } } print ">$textlink"; @@ -3583,19 +3629,16 @@ sub html_header($) { $HTML_DOCTYPE - - - $title - - +$HTML_META $body_tag $logo

$title

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