=================================================================== RCS file: /cvs/cvsweb/cvsweb.cgi,v retrieving revision 1.9 retrieving revision 1.14 diff -u -p -r1.9 -r1.14 --- cvsweb/cvsweb.cgi 1997/07/19 00:54:40 1.9 +++ cvsweb/cvsweb.cgi 1998/01/12 16:27:14 1.14 @@ -30,8 +30,19 @@ require 'ctime.pl'; $hsty_base = ""; require 'cgi-style.pl'; +#&get_the_source; -$cvsroot = '/home/ncvs'; +%CVSROOT = ( + 'freebsd', '/home/ncvs', + 'openbsd', '/home/OpenBSD/cvs', + 'learn', '/c/learncvs', + ); + +$cvstreedefault = 'freebsd'; +$cvstree = $cvstreedefault; +$cvsroot = $CVSROOT{"$cvstree"} || "/home/ncvs"; + + $intro = " This is a WWW interface to the FreeBSD CVS tree. You can browse the file hierarchy by picking directories @@ -49,7 +60,7 @@ CVS tree, see .

Please send any suggestions, comments, etc. to -Bill Fenner <fenner@freebsd.org> +Bill Fenner <fenner\@freebsd.org> "; $shortinstr = " Click on a directory to enter that directory. Click on a file to display @@ -60,16 +71,11 @@ chance to display diffs between revisions. $verbose = $v; ($where = $ENV{'PATH_INFO'}) =~ s|^/||; $where =~ s|/$||; -$fullname = $cvsroot . '/' . $where; ($scriptname = $ENV{'SCRIPT_NAME'}) =~ s|^/?|/|; $scriptname =~ s|/$||; $scriptwhere = $scriptname . '/' . $where; $scriptwhere =~ s|/$||; -if (!-d $cvsroot) { - &fatal("500 Internal Error",'$CVSROOT not found!'); -} - if ($query = $ENV{'QUERY_STRING'}) { foreach (split(/&/, $query)) { s/%(..)/sprintf("%c", hex($1))/ge; # unquote %-quoted @@ -81,6 +87,26 @@ if ($query = $ENV{'QUERY_STRING'}) { } $query = "?" . $query; } + + +$config = '/usr/local/etc/cvsweb'; +do "$config" if -f $config; + +if ($input{'cvsroot'}) { + if ($CVSROOT{$input{'cvsroot'}}) { + $cvstree = $input{'cvsroot'}; + $cvsroot = $CVSROOT{"$cvstree"}; + } +} +do "$config-$cvstree" if -f "$config-$cvstree"; + +$fullname = $cvsroot . '/' . $where; + +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.'); +} + + if (-d $fullname) { opendir(DIR, $fullname) || &fatal("404 Not Found","$where: $!"); @dir = readdir(DIR); @@ -104,6 +130,7 @@ if (-d $fullname) { last lookingforattic; } } + $haveattic = 1 if ($i <= $#dir); if (!$input{"showattic"} && ($i <= $#dir) && opendir(DIR, $fullname . "/Attic")) { splice(@dir, $i, 1, @@ -129,13 +156,14 @@ if (-d $fullname) { # &link("Directory-wide diffs", $scriptwhere . '/*'), "
"; } elsif (-d $fullname . "/" . $_) { print " ", - &link($_ . "/", $scriptwhere . '/' . $_ . '/' . $query), $attic, "
"; + &link($_ . "/", $scriptwhere . '/' . $_ . '/' . $query), + $attic, "
"; } elsif (s/,v$//) { # TODO: add date/time? How about sorting? print " ", &link($_, $scriptwhere . '/' . ($attic ? "Attic/" : "") . $_ . $query), - $attic, "
"; + $attic, "
"; } } print "\n"; @@ -151,15 +179,17 @@ if (-d $fullname) { } $formwhere = $scriptwhere; $formwhere =~ s|Attic/?$|| if ($input{"showattic"}); - print "


\n"; - $input{"showattic"}=!$input{"showattic"}; - foreach $k (keys %input) { - print "\n" if $input{$k}; + if ($haveattic) { + print "
\n"; + $input{"showattic"}=!$input{"showattic"}; + foreach $k (keys %input) { + print "\n" if $input{$k}; + } + print "\n"; + print "
\n"; } - print "\n"; - print "\n"; print &html_footer; print "\n"; } elsif (-f $fullname . ',v') { @@ -172,6 +202,260 @@ if (-d $fullname) { $input{'r2'}, $input{'tr2'}, $input{'f'}); exit; } +print("going to dolog($fullname)\n") if ($verbose); + &dolog($fullname); +} elsif ($fullname =~ s/\.diff$// && -f $fullname . ",v" && + $input{'r1'} && $input{'r2'}) { + # Allow diffs using the ".diff" extension + # so that browsers that default to the URL + # for a save filename don't save diff's as + # e.g. foo.c + &dodiff($fullname, $input{'r1'}, $input{'tr1'}, + $input{'r2'}, $input{'tr2'}, $input{'f'}); + exit; +} elsif (($newname = $fullname) =~ s|/([^/]+)$|/Attic/$1| && + -f $newname . ",v") { + # The file has been removed and is in the Attic. + # Send a redirect pointing to the file in the Attic. + ($newplace = $scriptwhere) =~ s|/([^/]+)$|/Attic/$1|; + &redirect($newplace); + exit; +} elsif (0 && (@files = &safeglob($fullname . ",v"))) { + print "Content-type: text/plain\n\n"; + print "You matched the following files:\n"; + print join("\n", @files); + # Find the tags from each file + # Display a form offering diffs between said tags +} else { + # Assume it's a module name with a potential path following it. + $xtra = $& if (($module = $where) =~ s|/.*||); + # Is there an indexed version of modules? + if (open(MODULES, "$cvsroot/CVSROOT/modules")) { + while () { + if (/^(\S+)\s+(\S+)/o && $module eq $1 + && -d "${cvsroot}/$2" && $module ne $2) { + &redirect($scriptname . '/' . $2 . $xtra); + } + } + } + &fatal("404 Not Found","$where: no such file or directory"); +} + +sub htmlify { + local($string, $pr) = @_; + + $string =~ s/&/&/g; + $string =~ s//>/g; + + if ($pr) { + $string =~ s|\bpr(\W+[a-z]+/\W*)(\d+)|$&|ig; + } + + $string; +} + +sub link { + local($name, $where) = @_; + + "$name\n"; +} + +sub revcmp { + local($rev1, $rev2) = @_; + local(@r1) = split(/\./, $rev1); + local(@r2) = split(/\./, $rev2); + local($a,$b); + + while (($a = shift(@r1)) && ($b = shift(@r2))) { + if ($a != $b) { + return $a <=> $b; + } + } + if (@r1) { return 1; } + if (@r2) { return -1; } + return 0; +} + +sub fatal { + local($errcode, $errmsg) = @_; + print "Status: $errcode\n"; + print &html_header("Error"); +# print "Content-type: text/html\n"; +# print "\n"; +# print "Error\n"; +# print "Error: $errmsg\n"; + print "Error: $errmsg\n"; + print &html_footer; + exit(1); +} + +sub redirect { + local($url) = @_; + print "Status: 301 Moved\n"; + print "Location: $url\n"; + print &html_header("Moved"); +# print "Content-type: text/html\n"; +# print "\n"; +# print "Moved\n"; +# print "This document is located here.\n"; + print "This document is located here.\n"; + print &html_footer; + exit(1); +} + +sub safeglob { + local($filename) = @_; + local($dirname); + local(@results); + + ($dirname = $filename) =~ s|/[^/]+$||; + $filename =~ s|.*/||; + + if (opendir(DIR, $dirname)) { + $glob = $filename; + # transform filename from glob to regex. Deal with: + # [, {, ?, * as glob chars + # make sure to escape all other regex chars + $glob =~ s/([\.\(\)\|\+])/\\$1/g; + $glob =~ s/\*/.*/g; + $glob =~ s/\?/./g; + $glob =~ s/{([^}]+)}/($t = $1) =~ s-,-|-g; "($t)"/eg; + foreach (readdir(DIR)) { + if (/^${glob}$/) { + push(@results, $dirname . "/" .$_); + } + } + } + + @results; +} + +sub checkout { + local($fullname, $rev) = @_; + + open(RCS, "co -p$rev '$fullname' 2>&1 |") || + &fail("500 Internal Error", "Couldn't co: $!"); +# /home/ncvs/src/sys/netinet/igmp.c,v --> standard output +# or +# /home/ncvs/src/sys/netinet/igmp.c,v --> stdout +# revision 1.1.1.2 +# /* + $_ = ; + if (/^(\S+),v\s+-->\s+st(andar)?d ?out(put)?\s*$/o && $1 eq $fullname) { + # As expected + } else { + &fatal("500 Internal Error", + "Unexpected output from co: $_"); + } + $_ = ; + if (/^revision\s+$rev\s*$/) { + # As expected + } else { + &fatal("500 Internal Error", + "Unexpected output from co: $_"); + } + $| = 1; + print "Content-type: text/plain\n\n"; + print ; + close(RCS); +} + +sub dodiff { + local($fullname, $r1, $tr1, $r2, $tr2, $f) = @_; + + if ($r1 =~ /([^:]+)(:(.+))?/) { + $rev1 = $1; + $sym1 = $3; + } + if ($rev1 eq 'text') { + $rev1 = $tr1; + } + if ($r2 =~ /([^:]+)(:(.+))?/) { + $rev2 = $1; + $sym2 = $3; + } + if ($rev2 eq 'text') { + $rev2 = $tr2; + } + if (!($rev1 =~ /^[\d\.]+$/) || !($rev2 =~ /^[\d\.]+$/)) { + &fatal("404 Not Found", + "Malformed query \"$ENV{'QUERY_STRING'}\""); + } +# +# rev1 and rev2 are now both numeric revisions. +# Thus we do a DWIM here and swap them if rev1 is after rev2. +# XXX should we warn about the fact that we do this? + if (&revcmp($rev1,$rev2) > 0) { + ($tmp1, $tmp2) = ($rev1, $sym1); + ($rev1, $sym1) = ($rev2, $sym2); + ($rev2, $sym2) = ($tmp1, $tmp2); + } +# +# XXX Putting '-p' here is a personal preference + if ($f eq 'c') { + $difftype = '-p -c'; + $diffname = "Context diff"; + } elsif ($f eq 's') { + $difftype = '--side-by-side --width=164'; + $diffname = "Side by Side"; + } else { + $difftype = '-p -u'; + $diffname = "Unidiff"; + } +# XXX should this just be text/plain +# or should it have an HTML header and then a
+	print "Content-type: text/plain\n\n";
+	open(RCSDIFF, "rcsdiff $difftype -r$rev1 -r$rev2 '$fullname' 2>&1 |") ||
+	    &fail("500 Internal Error", "Couldn't rcsdiff: $!");
+#
+#===================================================================
+#RCS file: /home/ncvs/src/sys/netinet/tcp_output.c,v
+#retrieving revision 1.16
+#retrieving revision 1.17
+#diff -c -r1.16 -r1.17
+#*** /home/ncvs/src/sys/netinet/tcp_output.c     1995/11/03 22:08:08     1.16
+#--- /home/ncvs/src/sys/netinet/tcp_output.c     1995/12/05 17:46:35     1.17
+#
+# Ideas:
+# - nuke the stderr output if it's what we expect it to be
+# - Add "no differences found" if the diff command supplied no output.
+#
+#*** src/sys/netinet/tcp_output.c     1995/11/03 22:08:08     1.16
+#--- src/sys/netinet/tcp_output.c     1995/12/05 17:46:35     1.17 RELENG_2_1_0
+# (bogus example, but...)
+#
+	if ($difftype eq '-u') {
+	    $f1 = '---';
+	    $f2 = '\+\+\+';
+	} else {
+	    $f1 = '\*\*\*';
+	    $f2 = '---';
+	}
+	while () {
+	    if (m|^$f1 $cvsroot|o) {
+		s|$cvsroot/||o;
+		if ($sym1) {
+		    chop;
+		    $_ .= " " . $sym1 . "\n";
+		}
+	    } elsif (m|^$f2 $cvsroot|o) {
+		s|$cvsroot/||o;
+		if ($sym2) {
+		    chop;
+		    $_ .= " " . $sym2 . "\n";
+		}
+	    }
+	    print $_;
+	}
+	close(RCSDIFF);
+}
+
+sub dolog {
+	local($fullname) = @_;
+	local($curbranch,$symnames);	#...
+
+	print("Going to rlog '$fullname'\n") if ($verbose);
 	open(RCS, "rlog '$fullname'|") || &fatal("500 Internal Error",
 						"Failed to spawn rlog");
 	while () {
@@ -210,13 +494,22 @@ if (-d $fullname) {
 	logentry:
 	while (!/^=========/) {
 	    $_ = ;
+	    last logentry if (!defined($_));	# EOF
 	    print "R:", $_ if ($verbose);
 	    if (/^revision ([\d\.]+)/) {
 		$rev = $1;
 	    } elsif (/^========/ || /^----------------------------$/) {
 		next logentry;
 	    } else {
-		&fatal("500 Internal Error","Error parsing RCS output: $_");
+		# The rlog output is syntactically ambiguous.  We must
+		# have guessed wrong about where the end of the last log
+		# message was.
+		# Since this is likely to happen when people put rlog output
+		# in their commit messages, don't even bother keeping
+		# these lines since we don't know what revision they go with
+		# any more.
+		next logentry;
+#		&fatal("500 Internal Error","Error parsing RCS output: $_");
 	    }
 	    $_ = ;
 	    print "D:", $_ if ($verbose);
@@ -344,11 +637,12 @@ if (-d $fullname) {
 		$nameprinted{$br}++;
 	    }
 	    print "\n";
-	    print "$_";
+	    print "$_";
 	    if (/^1\.1\.1\.\d+$/) {
 		print " (vendor branch)";
 	    }
-	    print " " . &ctime($date{$_}) . " by ";
+	    print " " . &ctime($date{$_}) . " UTC by ";
 	    print "" . $author{$_} . "\n";
 	    if ($revsym{$_}) {
 		print "
CVS Tags: $revsym{$_}"; @@ -387,7 +681,7 @@ if (-d $fullname) { if ($prevrev[$#prevrev] != 0) { $prev = join(".", @prevrev); print "
Diffs to $prev\n"; + print "&r2=$_" . &cvsroot . "\">Diffs to $prev\n"; # # Plus, if it's on a branch, and it's not a vendor branch, # offer to diff with the immediately-preceding commit if it @@ -401,7 +695,8 @@ if (-d $fullname) { @tmp2 = split(/\./, $_); if ($#tmp1 < $#tmp2) { print "; Diffs to $revorder[$i+1]\n"; + print "&r2=$_" . &cvsroot . + "\">Diffs to $revorder[$i+1]\n"; } } } @@ -419,6 +714,8 @@ if (-d $fullname) { print "name using the type-in text box.\n"; print "

\n"; print "

\n"; + print "\n" + if &cvsroot; print "Diffs between \n"; print "\n} + if &cvsroot; print "Branch: \n"; print "