[BACK]Return to cvsweb.cgi CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / cvsweb

Diff for /cvsweb/cvsweb.cgi between version 1.2 and 1.10

version 1.2, 1996/09/29 02:19:30 version 1.10, 1997/11/14 17:36:47
Line 31  require 'ctime.pl';
Line 31  require 'ctime.pl';
 $hsty_base = "";  $hsty_base = "";
 require 'cgi-style.pl';  require 'cgi-style.pl';
   
 $cvsroot = '/home/ncvs';  %CVSROOT = (
               'freebsd', '/home/ncvs',
               'openbsd', '/home/OpenBSD/cvs',
               'learn', '/c/learncvs',
               );
   
   $cvstreedefault = 'freebsd';
   $cvstree = $cvstreedefault;
   $cvsroot = $CVSROOT{"$cvstree"} || "/home/ncvs";
   
   
 $intro = "  $intro = "
 This is a WWW interface to the FreeBSD CVS tree.  This is a WWW interface to the FreeBSD CVS tree.
 You can browse the file hierarchy by picking directories  You can browse the file hierarchy by picking directories
Line 44  diffs between that revision and the previous one, and
Line 54  diffs between that revision and the previous one, and
 a form at the bottom of the page that allows you to  a form at the bottom of the page that allows you to
 display diffs between arbitrary revisions.  display diffs between arbitrary revisions.
 <p>  <p>
   If you would like to use this CGI script on your own web server and
   CVS tree, see <A HREF=\"http://www.freebsd.org/~fenner/cvsweb/\">
   the CVSWeb distribution site</A>.
   <p>
 Please send any suggestions, comments, etc. to  Please send any suggestions, comments, etc. to
 <A HREF=\"mailto:fenner@freebsd.org\">Bill Fenner &lt;fenner@freebsd.org&gt;</A>  <A HREF=\"mailto:fenner\@freebsd.org\">Bill Fenner &lt;fenner\@freebsd.org&gt;</A>
 ";  ";
 $shortinstr = "  $shortinstr = "
 Click on a directory to enter that directory. Click on a file to display  Click on a directory to enter that directory. Click on a file to display
Line 56  chance to display diffs between revisions. 
Line 70  chance to display diffs between revisions. 
 $verbose = $v;  $verbose = $v;
 ($where = $ENV{'PATH_INFO'}) =~ s|^/||;  ($where = $ENV{'PATH_INFO'}) =~ s|^/||;
 $where =~ s|/$||;  $where =~ s|/$||;
 $fullname = $cvsroot . '/' . $where;  
 ($scriptname = $ENV{'SCRIPT_NAME'}) =~ s|^/?|/|;  ($scriptname = $ENV{'SCRIPT_NAME'}) =~ s|^/?|/|;
 $scriptname =~ s|/$||;  $scriptname =~ s|/$||;
 $scriptwhere = $scriptname . '/' . $where;  $scriptwhere = $scriptname . '/' . $where;
 $scriptwhere =~ s|/$||;  $scriptwhere =~ s|/$||;
   
   
   if ($query = $ENV{'QUERY_STRING'}) {
       foreach (split(/&/, $query)) {
           s/%(..)/sprintf("%c", hex($1))/ge;      # unquote %-quoted
           if (/(\S+)=(.*)/) {
               $input{$1} = $2;
           } else {
               $input{$_}++;
           }
       }
       $query = "?" . $query;
   }
   
   
   
   if ($input{'cvsroot'}) {
       if ($CVSROOT{$input{'cvsroot'}}) {
           $cvstree = $input{'cvsroot'};
           $cvsroot = $CVSROOT{"$cvstree"};
       }
   }
   
   $fullname = $cvsroot . '/' . $where;
 if (!-d $cvsroot) {  if (!-d $cvsroot) {
         &fatal("500 Internal Error",'$CVSROOT not found!');          &fatal("500 Internal Error",'$CVSROOT not found!');
 }  }
   
   
 if (-d $fullname) {  if (-d $fullname) {
 # Something that would be nice to support, although I have no real  
 # good idea of how, would be to get full directory diff's, using  
 # symbolic names (revision numbers would be meaningless).  
 # The problem is finding a list of symbolic names that is common  
 # to all the files in the directory.  
 #  
         opendir(DIR, $fullname) || &fatal("404 Not Found","$where: $!");          opendir(DIR, $fullname) || &fatal("404 Not Found","$where: $!");
         @dir = readdir(DIR);          @dir = readdir(DIR);
         closedir(DIR);          closedir(DIR);
Line 88  if (-d $fullname) {
Line 120  if (-d $fullname) {
         # provides the results that I want in most browsers.  Another          # provides the results that I want in most browsers.  Another
         # case of layout spooging up HTML.          # case of layout spooging up HTML.
         print "<MENU>\n";          print "<MENU>\n";
         foreach (sort @dir) {          lookingforattic:
           for ($i = 0; $i <= $#dir; $i++) {
                   if ($dir[$i] eq "Attic") {
                           last lookingforattic;
                   }
           }
           if (!$input{"showattic"} && ($i <= $#dir) &&
                                   opendir(DIR, $fullname . "/Attic")) {
                   splice(@dir, $i, 1,
                           grep((s|^|Attic/|,!m|/\.|), readdir(DIR)));
                   closedir(DIR);
           }
           # Sort without the Attic/ pathname.
           foreach (sort {($c=$a)=~s|.*/||;($d=$b)=~s|.*/||;($c cmp $d)} @dir) {
             if ($_ eq '.') {              if ($_ eq '.') {
                 next;                  next;
             }              }
               if (s|^Attic/||) {
                   $attic = " (in the Attic)";
               } else {
                   $attic = "";
               }
             if ($_ eq '..') {              if ($_ eq '..') {
                 next if ($where eq '');                  next if ($where eq '');
                 ($updir = $scriptwhere) =~ s|[^/]+$||;                  ($updir = $scriptwhere) =~ s|[^/]+$||;
                 print "<IMG SRC=\"/icons/back.gif\"> ",                  print "<IMG SRC=\"/icons/back.gif\"> ",
                     &link("Previous Directory",$updir), "<BR>";                      &link("Previous Directory",$updir . $query), "<BR>";
   #               print "<IMG SRC=???> ",
   #                   &link("Directory-wide diffs", $scriptwhere . '/*'), "<BR>";
             } elsif (-d $fullname . "/" . $_) {              } elsif (-d $fullname . "/" . $_) {
                 print "<IMG SRC=\"/icons/dir.gif\"> ",                  print "<IMG SRC=\"/icons/dir.gif\"> ",
                     &link($_ . "/", $scriptwhere . '/' . $_ . '/'), "<BR>";                      &link($_ . "/", $scriptwhere . '/' . $_ . '/' . $query), $attic, "<BR>";
             } elsif (s/,v$//) {              } elsif (s/,v$//) {
   # TODO: add date/time?  How about sorting?
                 print "<IMG SRC=\"/icons/text.gif\"> ",                  print "<IMG SRC=\"/icons/text.gif\"> ",
                     &link($_, $scriptwhere . '/' . $_), "<BR>";                      &link($_, $scriptwhere . '/' .
                               ($attic ? "Attic/" : "") . $_ . $query),
                       $attic, "<BR>";
             }              }
         }          }
         print "</MENU>\n";          print "</MENU>\n";
           if ($input{"only_on_branch"}) {
               print "<HR><FORM METHOD=\"GET\" ACTION=\"${scriptwhere}\">\n";
               print "Currently showing only branch $input{'only_on_branch'}.\n";
               $input{"only_on_branch"}="";
               foreach $k (keys %input) {
                   print "<INPUT TYPE=hidden NAME=$k VALUE=$input{$k}>\n" if $input{$k};
               }
               print "<INPUT TYPE=SUBMIT VALUE=\"Show all branches\">\n";
               print "</FORM>\n";
           }
           $formwhere = $scriptwhere;
           $formwhere =~ s|Attic/?$|| if ($input{"showattic"});
           print "<HR><FORM METHOD=\"GET\" ACTION=\"${formwhere}\">\n";
           $input{"showattic"}=!$input{"showattic"};
           foreach $k (keys %input) {
               print "<INPUT TYPE=hidden NAME=$k VALUE=$input{$k}>\n" if $input{$k};
           }
           print "<INPUT TYPE=SUBMIT VALUE=\"";
           print ($input{"showattic"} ? "Show" : "Hide");
           print " attic directories\">\n";
           print "</FORM>\n";
         print &html_footer;          print &html_footer;
         print "</BODY></HTML>\n";          print "</BODY></HTML>\n";
 } elsif (-f $fullname . ',v') {  } elsif (-f $fullname . ',v') {
         if ($_ = $ENV{'QUERY_STRING'}) {          if ($input{'rev'} =~ /^[\d\.]+$/) {
             s/%(..)/sprintf("%c", hex($1))/ge;  # unquote %-quoted                  &checkout($fullname, $input{'rev'});
             if (/rev=([\d\.]+)/) {  
                 $rev = $1;  
                 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  
 # revision 1.1.1.2  
 # /*  
                 $_ = <RCS>;  
                 if (/^$fullname,v\s+-->\s+standard output\s*$/o) {  
                     # As expected  
                 } else {  
                     &fatal("500 Internal Error",  
                         "Unexpected output from co: $_");  
                 }  
                 $_ = <RCS>;  
                 if (/^revision\s+$rev\s*$/) {  
                     # As expected  
                 } else {  
                     &fatal("500 Internal Error",  
                         "Unexpected output from co: $_");  
                 }  
                 $| = 1;  
                 print "Content-type: text/plain\n";  
                 print "Content-encoding: x-gzip\n\n";  
                 open(GZIP, "|gzip -1 -c");      # need lightweight compression  
                 print GZIP <RCS>;  
                 close(GZIP);  
                 close(RCS);  
                 exit;                  exit;
             }  
             if (/r1=([^&:]+)(:([^&]+))?/) {  
                 $rev1 = $1;  
                 $sym1 = $3;  
             }  
             if ($rev1 eq 'text') {  
                 if (/tr1=([^&]+)/) {  
                     $rev1 = $1;  
                 }  
             }  
             if (/r2=([^&:]+)(:([^&]+))?/) {  
                 $rev2 = $1;  
                 $sym2 = $3;  
             }  
             if ($rev2 eq 'text') {  
                 if (/tr2=([^&]+)/) {  
                     $rev2 = $1;  
                 }  
             }  
             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);  
             }  
 #  
             $difftype = "-u";  
             $diffname = "Unidiff";  
             if (/f=([^&]+)/) {  
                 if ($1 eq 'c') {  
                     $difftype = '-c';  
                     $diffname = "Context diff";  
                 }  
             }  
 # XXX should this just be text/plain  
 # or should it have an HTML header and then a <pre>  
             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 (<RCSDIFF>) {  
                 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);  
             exit;  
         }          }
           if ($input{'r1'} && $input{'r2'}) {
                   &dodiff($fullname, $input{'r1'}, $input{'tr1'},
                           $input{'r2'}, $input{'tr2'}, $input{'f'});
                   exit;
           }
         open(RCS, "rlog '$fullname'|") || &fatal("500 Internal Error",          open(RCS, "rlog '$fullname'|") || &fatal("500 Internal Error",
                                                 "Failed to spawn rlog");                                                  "Failed to spawn rlog");
         while (<RCS>) {          while (<RCS>) {
             print if ($verbose);              print if ($verbose);
               if (/^branch:\s+([\d\.]+)/) {
                   $curbranch = $1;
               }
             if ($symnames) {              if ($symnames) {
                 if (/^\s+([^:]+):\s+([\d\.]+)/) {                  if (/^\s+([^:]+):\s+([\d\.]+)/) {
                     $symrev{$1} = $2;                      $symrev{$1} = $2;
Line 249  if (-d $fullname) {
Line 217  if (-d $fullname) {
                 last;                  last;
             }              }
         }          }
   
           if ($onlyonbranch = $input{'only_on_branch'}) {
               ($onlyonbranch = $symrev{$onlyonbranch}) =~ s/\.0\././;
               ($onlybranchpoint = $onlyonbranch) =~ s/\.\d+$//;
           }
   
 # each log entry is of the form:  # each log entry is of the form:
 # ----------------------------  # ----------------------------
 # revision 3.7.1.1  # revision 3.7.1.1
Line 268  if (-d $fullname) {
Line 242  if (-d $fullname) {
             }              }
             $_ = <RCS>;              $_ = <RCS>;
             print "D:", $_ if ($verbose);              print "D:", $_ if ($verbose);
             if (m|^date:\s+(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+(\S+);|) {              if (m|^date:\s+(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+(\S+);\s+state:\s+(\S+);|) {
                 $yr = $1;                  $yr = $1;
                 # damn 2-digit year routines                  # damn 2-digit year routines
                 if ($yr > 100) {                  if ($yr > 100) {
Line 276  if (-d $fullname) {
Line 250  if (-d $fullname) {
                 }                  }
                 $date{$rev} = &timelocal($6,$5,$4,$3,$2 - 1,$yr);                  $date{$rev} = &timelocal($6,$5,$4,$3,$2 - 1,$yr);
                 $author{$rev} = $7;                  $author{$rev} = $7;
                   $state{$rev} = $8;
             } else {              } else {
                 &fatal("500 Internal Error", "Error parsing RCS output: $_");                  &fatal("500 Internal Error", "Error parsing RCS output: $_");
             }              }
Line 296  if (-d $fullname) {
Line 271  if (-d $fullname) {
         print "Done sorting revisions\n" if ($verbose);          print "Done sorting revisions\n" if ($verbose);
 #  #
 # HEAD is an artificial tag which is simply the highest tag number on the main  # HEAD is an artificial tag which is simply the highest tag number on the main
 # branch (I think!).  Find it by looking through @revorder; it should at least  # branch, unless there is a branch tag in the RCS file in which case it's the
 # be near the beginning (In fact, it *should* be the first commit listed on  # highest revision on that branch.  Find it by looking through @revorder; it
 # the main branch.)  # is the first commit listed on the appropriate branch.
           $headrev = $curbranch || "1";
         revision:          revision:
         for ($i = 0; $i <= $#revorder; $i++) {          for ($i = 0; $i <= $#revorder; $i++) {
             if ($revorder[$i] =~ /^\d+\.\d+$/) {              if ($revorder[$i] =~ /^(\S*)\.\d+$/ && $headrev eq $1) {
                 if ($revsym{$revorder[$i]}) {                  if ($revsym{$revorder[$i]}) {
                     $revsym{$revorder[$i]} .= ", ";                      $revsym{$revorder[$i]} .= ", ";
                 }                  }
Line 321  if (-d $fullname) {
Line 297  if (-d $fullname) {
         foreach (sort keys %symrev) {          foreach (sort keys %symrev) {
             $rev = $symrev{$_};              $rev = $symrev{$_};
             if ($rev =~ /^(\d+(\.\d+)+)\.0\.(\d+)$/) {              if ($rev =~ /^(\d+(\.\d+)+)\.0\.(\d+)$/) {
                   push(@branchnames, $_);
                 #                  #
                 # A revision number of A.B.0.D really translates into                  # A revision number of A.B.0.D really translates into
                 # "the highest current revision on branch A.B.D".                  # "the highest current revision on branch A.B.D".
Line 328  if (-d $fullname) {
Line 305  if (-d $fullname) {
                 # If there is no branch A.B.D, then it translates into                  # If there is no branch A.B.D, then it translates into
                 # the head A.B .                  # the head A.B .
                 #                  #
                 # This is pure speculation.  
                 #  
                 $head = $1;                  $head = $1;
                 $branch = $3;                  $branch = $3;
                 $regex = $head . "." . $branch;                  $regex = $head . "." . $branch;
Line 347  if (-d $fullname) {
Line 322  if (-d $fullname) {
                 }                  }
                 $revsym{$rev} .= ", " if ($revsym{$rev});                  $revsym{$rev} .= ", " if ($revsym{$rev});
                 $revsym{$rev} .= $_;                  $revsym{$rev} .= $_;
                   if ($rev ne $head) {
                       $branchpoint{$head} .= ", " if ($branchpoint{$head});
                       $branchpoint{$head} .= $_;
                   }
             }              }
             $sel .= "<OPTION VALUE=\"${rev}:${_}\">$_\n";              $sel .= "<OPTION VALUE=\"${rev}:${_}\">$_\n";
         }          }
         print "Done associating revisions with branches\n" if ($verbose);          print "Done associating revisions with branches\n" if ($verbose);
         print &html_header("CVS log for $where");          print &html_header("CVS log for $where");
         ($upwhere = $where) =~ s|[^/]+$||;          ($upwhere = $where) =~ s|(Attic/)?[^/]+$||;
         print "Up to ", &link($upwhere,$scriptname . "/" . $upwhere);          print "Up to ", &link($upwhere,$scriptname . "/" . $upwhere . $query);
         print "<BR>\n";          print "<BR>\n";
         print "<A HREF=\"#diff\">Request diff between arbitrary revisions</A>\n";          print "<A HREF=\"#diff\">Request diff between arbitrary revisions</A>\n";
         print "<HR NOSHADE>\n";          print "<HR NOSHADE>\n";
           if ($curbranch) {
               print "Default branch is ";
               print ($revsym{$curbranch} || $curbranch);
           } else {
               print "No default branch";
           }
           print "<BR><HR NOSHADE>\n";
 # The other possible U.I. I can see is to have each revision be hot  # The other possible U.I. I can see is to have each revision be hot
 # and have the first one you click do ?r1=foo  # and have the first one you click do ?r1=foo
 # and since there's no r2 it keeps going & the next one you click  # and since there's no r2 it keeps going & the next one you click
Line 366  if (-d $fullname) {
Line 352  if (-d $fullname) {
   
         for ($i = 0; $i <= $#revorder; $i++) {          for ($i = 0; $i <= $#revorder; $i++) {
             $_ = $revorder[$i];              $_ = $revorder[$i];
 #           print "RCS revision <b>$_</b>\n";              ($br = $_) =~ s/\.\d+$//;
             print "<A HREF=\"$scriptwhere?rev=$_\"><b>$_</b></A>";              next if ($onlyonbranch && $br ne $onlyonbranch &&
                                               $_ ne $onlybranchpoint);
               print "<a NAME=\"rev$_\"></a>";
               foreach $sym (split(", ", $revsym{$_})) {
                   print "<a NAME=\"$sym\"></a>";
               }
               if ($revsym{$br} && !$nameprinted{$br}) {
                   foreach $sym (split(", ", $revsym{$br})) {
                       print "<a NAME=\"$sym\"></a>";
                   }
                   $nameprinted{$br}++;
               }
               print "\n";
               print "<A HREF=\"$scriptwhere?rev=$_" .
                   &cvsroot . qq{"><b>$_</b></A>};
             if (/^1\.1\.1\.\d+$/) {              if (/^1\.1\.1\.\d+$/) {
                 print " <i>(vendor branch)</i>";                  print " <i>(vendor branch)</i>";
             }              }
 #           print "<BR>\n";  
 #           print "Checked in on <i>" . &ctime($date{$_}) . "</i> by ";  
 #           print "<i>" . $author{$_} . "</i><BR>\n";  
             print " <i>" . &ctime($date{$_}) . "</i> by ";              print " <i>" . &ctime($date{$_}) . "</i> by ";
             print "<i>" . $author{$_} . "</i>\n";              print "<i>" . $author{$_} . "</i>\n";
             if ($revsym{$_}) {              if ($revsym{$_}) {
 #               print "CVS Tags: <b>$revsym{$_}</b><BR>\n";  
                 print "<BR>CVS Tags: <b>$revsym{$_}</b>";                  print "<BR>CVS Tags: <b>$revsym{$_}</b>";
             }              }
             if (($br = $_) =~ s/\.\d+$// && $revsym{$br})  {              if ($revsym{$br})  {
 #               print "Branch: <b>$revsym{$br}</b><BR>\n";  
                 if ($revsym{$_}) {                  if ($revsym{$_}) {
                     print "; ";                      print "; ";
                 } else {                  } else {
                     print "<BR>";                      print "<BR>";
                 }                  }
                 print "Branch: <b>$revsym{$br}</b>";                  print "Branch: <b>$revsym{$br}</b>\n";
             }              }
               if ($branchpoint{$_}) {
                   if ($revsym{$br} || $revsym{$_}) {
                       print "; ";
                   } else {
                       print "<BR>";
                   }
                   print "Branch point for: <b>$branchpoint{$_}</b>\n";
               }
             # Find the previous revision on this branch.              # Find the previous revision on this branch.
             # I think this can be done algorithmically.  
             @prevrev = split(/\./, $_);              @prevrev = split(/\./, $_);
             if (--$prevrev[$#prevrev] == 0) {              if (--$prevrev[$#prevrev] == 0) {
                 # If it was X.Y.Z.1, just make it X.Y                  # If it was X.Y.Z.1, just make it X.Y
Line 407  if (-d $fullname) {
Line 409  if (-d $fullname) {
             }              }
             if ($prevrev[$#prevrev] != 0) {              if ($prevrev[$#prevrev] != 0) {
                 $prev = join(".", @prevrev);                  $prev = join(".", @prevrev);
                 print "<BR><A HREF=\"$scriptwhere?r1=$prev";                  print "<BR><A HREF=\"${scriptwhere}.diff?r1=$prev";
                 print "&r2=$_\">Diffs to $prev</A>\n";                  print "&r2=$_" . &cvsroot . qq{">Diffs to $prev</A>\n};
                 #                  #
                 # Plus, if it's on a branch, and it's not a vendor branch,                  # Plus, if it's on a branch, and it's not a vendor branch,
                 # offer to diff with the immediately-preceding commit if it                  # offer to diff with the immediately-preceding commit if it
Line 421  if (-d $fullname) {
Line 423  if (-d $fullname) {
                     @tmp1 = split(/\./, $revorder[$i+1]);                      @tmp1 = split(/\./, $revorder[$i+1]);
                     @tmp2 = split(/\./, $_);                      @tmp2 = split(/\./, $_);
                     if ($#tmp1 < $#tmp2) {                      if ($#tmp1 < $#tmp2) {
                         print "; <A HREF=\"$scriptwhere?r1=$revorder[$i+1]";                          print "; <A HREF=\"${scriptwhere}.diff?r1=$revorder[$i+1]";
                         print "&r2=$_\">Diffs to $revorder[$i+1]</A>\n";                          print "&r2=$_" . &cvsroot .
                               qq{">Diffs to $revorder[$i+1]</A>\n};
                     }                      }
                 }                  }
             }              }
 #           print "Log message:<BR>\n";              if ($state{$_} eq "dead") {
                   print "<BR><B><I>FILE REMOVED</I></B>\n";
               }
             print "<PRE>\n";              print "<PRE>\n";
             print &htmlify($log{$_});              print &htmlify($log{$_}, 1);
             print "</PRE><HR NOSHADE>\n";              print "</PRE><HR NOSHADE>\n";
         }          }
         print "<A NAME=diff>\n";          print "<A NAME=diff>\n";
Line 437  if (-d $fullname) {
Line 442  if (-d $fullname) {
         print "name using the selection box or you may type in a numeric\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 "name using the type-in text box.\n";
         print "</A><P>\n";          print "</A><P>\n";
         print "<FORM METHOD=\"GET\" ACTION=\"$scriptwhere\">\n";          print "<FORM METHOD=\"GET\" ACTION=\"${scriptwhere}.diff\">\n";
           print qq{<input type=hidden name=cvsroot value=$cvstree>\n}
                if &cvsroot;
         print "Diffs between \n";          print "Diffs between \n";
         print "<SELECT NAME=\"r1\">\n";          print "<SELECT NAME=\"r1\">\n";
         print "<OPTION VALUE=\"text\" SELECTED>Use Text Field\n";          print "<OPTION VALUE=\"text\" SELECTED>Use Text Field\n";
Line 452  if (-d $fullname) {
Line 459  if (-d $fullname) {
         print "<INPUT TYPE=\"TEXT\" NAME=\"tr2\" VALUE=\"$revorder[0]\">\n";          print "<INPUT TYPE=\"TEXT\" NAME=\"tr2\" VALUE=\"$revorder[0]\">\n";
         print "<BR><INPUT TYPE=RADIO NAME=\"f\" VALUE=u CHECKED>Unidiff<br>\n";          print "<BR><INPUT TYPE=RADIO NAME=\"f\" VALUE=u CHECKED>Unidiff<br>\n";
         print "<INPUT TYPE=RADIO NAME=\"f\" VALUE=c>Context diff<br>\n";          print "<INPUT TYPE=RADIO NAME=\"f\" VALUE=c>Context diff<br>\n";
           print "<INPUT TYPE=RADIO NAME=\"f\" VALUE=s>Side-by-Side<br>\n";
         print "<INPUT TYPE=SUBMIT VALUE=\"Get Diffs\">\n";          print "<INPUT TYPE=SUBMIT VALUE=\"Get Diffs\">\n";
         print "</FORM>\n";          print "</FORM>\n";
           print "<HR noshade>\n";
           print "<A name=branch>\n";
           print "You may select to see revision information from only\n";
           print "a single branch.\n";
           print "</A><P>\n";
           print "<FORM METHOD=\"GET\" ACTION=\"$scriptwhere\">\n";
           print qq{<input type=hidden name=cvsroot value=$cvstree>\n}
                if &cvsroot;
           print "Branch: \n";
           print "<SELECT NAME=\"only_on_branch\">\n";
           print "<OPTION VALUE=\"\"";
           print " SELECTED" if ($input{"only_on_branch"} eq "");
           print ">Show all branches\n";
           foreach (sort @branchnames) {
                   print "<OPTION";
                   print " SELECTED" if ($input{"only_on_branch"} eq $_);
                   print ">${_}\n";
           }
           print "</SELECT>\n";
           print "<INPUT TYPE=SUBMIT VALUE=\"View Branch\">\n";
           print "</FORM>\n";
         print &html_footer;          print &html_footer;
         print "</BODY></HTML>\n";          print "</BODY></HTML>\n";
   } 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 {  } else {
           # Assume it's a module name with a potential path following it.
           ($module = $where) =~ s|/.*||;
           $xtra = $&;
           # Is there an indexed version of modules?
           if (open(MODULES, "$cvsroot/CVSROOT/modules")) {
                   while (<MODULES>) {
                           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");          &fatal("404 Not Found","$where: no such file or directory");
 }  }
   
 sub htmlify {  sub htmlify {
         local($string) = @_;          local($string, $pr) = @_;
   
         $string =~ s/&/&amp;/g;          $string =~ s/&/&amp;/g;
         $string =~ s/</&lt;/g;          $string =~ s/</&lt;/g;
         $string =~ s/>/&gt;/g;          $string =~ s/>/&gt;/g;
   
           if ($pr) {
                   $string =~ s|\bpr(\W+[a-z]+/\W*)(\d+)|<A HREF=/cgi/query-pr.cgi?pr=$2>$&</A>|ig;
           }
   
         $string;          $string;
 }  }
   
Line 482  sub revcmp {
Line 549  sub revcmp {
         local(@r2) = split(/\./, $rev2);          local(@r2) = split(/\./, $rev2);
         local($a,$b);          local($a,$b);
   
         while (($a = pop(@r1)) && ($b = pop(@r2))) {          while (($a = shift(@r1)) && ($b = shift(@r2))) {
             if ($a != $b) {              if ($a != $b) {
                 return $a <=> $b;                  return $a <=> $b;
             }              }
Line 495  sub revcmp {
Line 562  sub revcmp {
 sub fatal {  sub fatal {
         local($errcode, $errmsg) = @_;          local($errcode, $errmsg) = @_;
         print "Status: $errcode\n";          print "Status: $errcode\n";
         print "Content-type: text/html\n";          print &html_header("Error");
         print "\n";  #       print "Content-type: text/html\n";
         print "<HTML><HEAD><TITLE>Error</TITLE></HEAD>\n";  #       print "\n";
         print "<BODY>Error: $errmsg</BODY></HTML>\n";  #       print "<HTML><HEAD><TITLE>Error</TITLE></HEAD>\n";
   #       print "<BODY>Error: $errmsg</BODY></HTML>\n";
           print "Error: $errmsg\n";
           print &html_footer;
         exit(1);          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 "<HTML><HEAD><TITLE>Moved</TITLE></HEAD>\n";
   #       print "<BODY>This document is located <A HREF=$url>here</A>.</BODY></HTML>\n";
           print "This document is located <A HREF=$url>here</A>.\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
   # /*
           $_ = <RCS>;
           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: $_");
           }
           $_ = <RCS>;
           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 <RCS>;
           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 <pre>
           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 (<RCSDIFF>) {
               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 cvsroot {
       return '' if $cvstree eq $cvstreedefault;
       return "&cvsroot=" . $cvstree;
 }  }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.10

CVSweb