#! /usr/bin/perl -w # # Copyright (C) 2001 Richard Kettlewell # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA #/ use strict; use integer; use IO::File; use IO::Handle; # configurable items: # root of SCCS files my $root = "/cdrom"; # allowed filters my @allowed_filters = qw(raw diff); # add "man2html" if you trust groff my $tmproot; my $tmpcount = 0; my %allowed_filters = map(($_ => 1), @allowed_filters); sub decode( $ ); sub quote( $ ); sub directory( $ ); sub regfile( $ ); sub dirent( $$ ); sub tempfile(); sub filter( $$$ ); sub save( $ ); sub copy( $$ ); my @query = split(/\&/, $ENV{'QUERY_STRING'}); my %q = (); for(@query) { if(/^([^=]+)=(.*)$/) { $q{decode($1)} = decode($2); } } my $path = $ENV{'PATH_INFO'} || ""; error("invalid path \"$path\"") if $path =~ /\.\./; if(-d "$root/$path" && $path !~ /\/$/) { # make sure directory URLs always end in / my $url = "$ENV{'REQUEST_URI'}/"; # REQUEST_URI might or might not include http://.... if($url !~ /^http:/) { if($ENV{'SERVER_PORT'} eq "80") { $url = "http://$ENV{'SERVER_NAME'}$url"; } else { $url = "http://$ENV{'SERVER_NAME'}:$ENV{'SERVER_PORT'}$url"; } } output("Location: $url\n"); html("Redirect", "
redirect to ", quote($url), "
\n"); } else { stat "$root/$path"; if (-d _) { directory($path); } elsif (-f _) { regfile($path); } else { error("\"$path\" is not a valid path"); } } (close STDOUT) || die "$0: stdout: $!"; exit 0; sub directory( $ ) { opendir(D, "$root/$path") || error("opening $path: $!"); my @files = readdir D; closedir D; my @bgcolors = ("#ffffff", "#c0ffc0"); my $n = 0; html("SCCS: $path", "Filename | \n", "Type | \n", "User | \n", "Rev | \n", "Date | \n", "Comment | \n", "
---|---|---|---|---|---|
Cannot get any SCCS information for ", quote($path), "
\n"); return; } my @revs = (); my %when = (); my %who = (); my %comments = (); my $rev; my $incomment = 0; for(@prs) { if(/^D ([0-9\.]+) (\d+\/\d+\/\d+ \d+:\d+:\d+) (\S+)/) { $rev = $1; push(@revs, $rev); $when{$rev} = quote($2); $who{$rev} = quote($3); $incomment = 0; } elsif(/^COMMENTS:/) { $incomment = 1; } elsif($incomment) { if(exists $comments{$rev}) { $comments{$rev} .= "Rev | \n", "\n", " | User | \n", "When | \n", "Comments | \n", "
---|---|---|---|---|
", "$revs[$_]", " | \n", "", $_ != $#revs ? (" (diff)", ) : " ", $path =~ /\.\d+$/ && exists $allowed_filters{'man2html'} ? (" (format)", ) : (), " | \n", "$who{$revs[$_]} | \n", "$when{$revs[$_]} | \n", "$comments{$revs[$_]} | \n", "
", map(quote($_), @_), "
\n"); } sub html { my $title = quote(shift); output("Content-Type: text/html\n", "\n", "\n", "\n", " \n", "", quote($_), "=", quote($ENV{$_}), "
\n"), # sort keys %ENV), @_, " \n", "\n", "\n", "\n", ); } sub quote( $ ) { local $_ = shift; s/[\&<>\"]/sprintf("%d;", ord($&))/ge; return $_; } sub output { (print @_) || die "$0: stdout: $!"; } sub tempfile() { ++$tmpcount; if(!defined $tmproot) { my $tmpdir = $ENV{'TMPDIR'} || "/tmp"; for(my $n = 0; $n < 32; ++$n) { my $t = "$tmpdir/sccs.$$.$n"; if(mkdir($t, 0700)) { $tmproot = $t; return "$tmproot/$tmpcount"; } } die "$0: cannot create a temporary directory"; } return "$tmproot/$tmpcount"; } # filter(TYPE, IN, OUT) # # Read data from IN, apply filter TYPE, write to OUT sub filter( $$$ ) { my ($type, $in, $out) = @_; $type = "\L$type\E"; if(!exists $allowed_filters{$type}) { $type = "raw"; } if($type eq "man2html") { my $path = save($in); my $command = `grog -Thtml \Q$path\E`; die "$0: grog failed" if $?; output("Content-Type: text/html\n", "\n", ); command($command, $out); return; } if($type eq "diff") { local $_; output("Content-Type: text/html\n", "\n", "\n", " \n", "", ); while(defined($_ = $in->getline())) { my $color; chomp; if(/^\+/) { $color = "#0000ff"; } elsif(/^-/) { $color = "#ff0000"; } elsif(/^[^ ]/) { $color = "#00ff00"; } if(defined $color) { output("", quote($_), "\n"); } else { output(quote($_), "\n"); } } return; } # raw output("Content-Type: text/plain\n", "\n"); copy($in, $out); } # save(HANDLE) # # read from HANDLE and save to a temporary file. Return name of temporary # file. sub save( $ ) { my $in = shift; my $tmpfile = tempfile; (my $o = new IO::File($tmpfile, "w")) || die "$0: opening $tmpfile: $!"; copy($in, $o); $o->close() || die "$0: writing $tmpfile: $!"; return $tmpfile; } # command(COMMAND, OUT) # # Execute COMMAND and send the output to OUT sub command( $$ ) { my ($command, $out) = @_; (my $i = new IO::File("$command|")) || die "$0: executing $command: $!"; copy($i, $out); $i->close() || die "$0: read error: $!/$?"; } # copy(IN, OUT) # # copy data from IN to OUT sub copy( $$ ) { my ($in, $out) = @_; my $b; my $n; while(($n = $in->read($b, 1024))) { $out->print($b) || die "$0: write error: $!"; } die "$0: read error: $!" if ! defined $n; } END { if(defined $tmproot) { system("rm -rf $tmproot"); } }