#!/usr/local/bin/perl5
#
# info2www - Gateway between GNU Info nodes and WWW
# $Id: info2www,v 1.1.1.8 1994/07/21 20:35:32 lmdrsm Exp $
#
# This is a script conforming to the CGI - Common Gateway Interface
#
# Created: 1994-03-24 by LMD/T/AD Roar Smith (lmdrsm@lmd.ericsson.se)
#
# Copyright: This program is in the Public Domain.
#
# The original code (most of &info2html) was written by
# Eelco van Asperen (evas@cs.few.eur.nl).
#
# Local History:
#
# 2002-06-10: Stewart Clamen (smc@cs.cmu.edu)
# Adapted to perl5 by changing s/@@@NOTE@@@/ marker to s/~~~NOTE~~~/
#
# $Log: info2www,v $
#
# Revision 1.1.1.8 1994/07/21 20:35:32 lmdrsm
# Implemented cacheing of lookup information. See the $CACHE variable.
# Bug fixes.
#
# Revision 1.1.1.7 1994/07/20 11:49:00 lmdrsm
# Absolute path-names handled; Only pathnames corresponding to entries
# in @INFOPATH are allowed unless $ALLOWPATH is true.
# No warnings are issued unless $debug is true.
#
# Revision 1.1.1.6 1994/04/06 20:10:14 lmdrsm
# Fixed bug in hyperlinks spanning a newline or containg % chars.
# Alternative image strings provided for non-graphic browsers.
#
# Revision 1.1.1.5 1994/04/06 19:28:57 lmdrsm
# Fixed bug in searches for Info files with regexp meta-chars.
# Hyperlinks to Nodes within same file now uses real filename.
#
# Revision 1.1.1.4 1994/04/06 18:53:37 lmdrsm
# Implemented handling of non-exact matches for a requested Info file
# in a much better way. To see the algorithm "Use the source Luke..." .
#
# Revision 1.1.1.3 1994/03/30 16:36:14 lmdrsm
# Re-introduced bug-fixes from 1.1.1.1 which had disappeared in 1.1.1.2
#
# Revision 1.1.1.2 1994/03/30 14:55:17 lmdrsm
# TODO comment introduced.
#
# Revision 1.1.1.1 1994/03/30 14:43:54 lmdrsm
# First bug fixed version.
#
# Revision 1.1 1994/03/24 19:15:32 lmdrsm
# Included automatic reference to the info2www documentation.
#
# Revision 1.0 1994/03/24 17:49:15 lmdrsm
# Initial revision
#
# TODO:
# -----
# * Present a list of choices when there is no exact match for the requested
# Info file but multiple non-exact matches exist.
#
#
#
#----------------- CONFIGURATION -----------------------------------------------
#
# Set $debug = 1; to debug what's happening
#
$DEBUG = 0;
unshift(@INC, '/afs/cs.cmu.edu/user/clamen/www/info2www');
#
# INFOPATH is the path of direcories in which to search for Info node files.
#
@INFOPATH =
(
"/usr/local/info/",
"/usr/local/lib/info/",
"/afs/cs/local/gnu-emacs/common-depot/info-files/info/",
"/afs/cs/project/edrc-ndim4/local/common/info/",
"/afs/cs/local/gnu-others/sun4_413/omega/info/",
);
#
# ALLOWPATH specifies whether info files with may be specified with path-names
# outside of those directories included in INFOPATH .
# It is a possible security hole to set this variable to a true value,
# because *any* file on the system could then be accessed through this gateway.
$ALLOWPATH = 0;
#
# ALIAS is a map of aliases - look for the alias if the node itself isn't found.
# The key (first entry) is the node filename, the value (second entry) is the
# alias. Both are basenames (i.e. no path!) with no capital letters.
# Note that the keys *must* be unique!
#
%ALIAS =
(
'emacs', 'lemacs',
'g++', 'gcc',
'c++', 'gcc',
'gunzip', 'gzip',
'zcat' , 'gzip'
);
#
# Location of the icons used for indicating references and stuff:
# $INFO_ICON - Icon at the top left of each document
# $UP_ICON - Icon used in an "Up:" hyperlink at the top
# $NEXT_ICON - Icon used in a "Next:" hyperlink at the top
# $PREV_ICON - Icon used in a "Prev:" hyperlink at the top
# $MENU_ICON - Icon used in front of each menu label
#
# Set these to "" if you don't want them used.
#
$INFO_ICON = "/afs/cs.cmu.edu/user/clamen/www/info2www/infodoc.gif";
#$UP_ICON = "/afs/cs.cmu.edu/user/clamen/www/info2www/up.gif";
$UP_ICON = "";
#$NEXT_ICON = "/afs/cs.cmu.edu/user/clamen/www/info2www/next.gif";
$NEXT_ICON = "";
#$PREV_ICON = "/afs/cs.cmu.edu/user/clamen/www/info2www/prev.gif";
$PREV_ICON = "";
$MENU_ICON = "/afs/cs.cmu.edu/user/clamen/www/info2www/menu.gif";
#
# URL for documentation on info2www
#
# Set this to "" if you don't want it used.
#
$DOCREF = "/afs/cs.cmu.edu/user/clamen/www/info2www/info2www.html";
#
# CACHE is the dbm(3) or ndbm(3) file for cacheing lookup information.
# Set this to "" if you don't want it used.
# The effective user of this script should have write permissions to
# the directory in which the dbm files reside.
#
$CACHE = "/usr/tmp/info2www-cache";
#
# These are the defines for file-locking with flock(2)
#
$LOCK_SH = 1;
$LOCK_EX = 2;
$LOCK_NB = 4;
$LOCK_UN = 8;
#----------------- MAIN --------------------------------------------------------
print "Content-type: text/html\n"; #-- Mime header for NCSA httpd
print "\n";
$pg = $0; $pg =~ s,^.*/([^/]*)$,$1,;
$options = "";
#$script_name = $ENV{'SCRIPT_NAME'};
$script_name = "info2www";
$server_name = $ENV{'SERVER_NAME'};
$request_method = $ENV{'REQUEST_METHOD'};
$prefix = $script_name . "?"; # prefix for HREF= entries
if ($request_method ne 'GET') {
die "REQUEST_MODE 'GET' expected - got '$request_method'\n";
}
print "ARGV: ", join('+', @ARGV), "
\n" if $DEBUG;
if ($#ARGV == -1) {
$nodename = "(DIR)";
} else {
$nodename = join('+', @ARGV);
$nodename = &DeEscape($nodename);
}
print "nodename: ", $nodename, "
\n" if $DEBUG;
&info2html($nodename);
if ($DOCREF) {
print
"
\n" if $DEBUG; $n = 0; if ($h_node =~ m/^$target$/i) { $active = 1; $matches++; if ($CACHE && !$cachefound) { &UpdateCache("($file)$target", $pos, $realfile{$handle}); } print "
\n" if $DEBUG; # should save: $inentry $indirect $save_inentry[$nfiles] = $inentry; $save_indirect[$nfiles] = $indirect; $inentry = 0; $indirect = 0; &OpenFile($F[0]) || return(0); next FileLoop; }; next if $active == 0; if (($end) = /^\*\s+Menu:(.*)$/) { # start of a menu: $seenMenu = 1; &EndListing(); print "$end"; &StartMenu(); next; }; /^\*/ && do { #---- SAMPLE LINES: ----------------------------------------- # * Sample::. Sample info. # # * Info: (info). Documentation browsing system. # # * Bison: (bison/bison) # A Parser generator in the same style as yacc. # * Random: (Random) Random Random Number Generator #------------------------------------------------------------ if ($menu == 0 && $seenMenu) { &EndListing(); &StartMenu(); }; # * foo:: /^\*\s+([^:]+)::/ && do { $rest_of_line = $'; print "
\n" if $DEBUG;
close($handle);
print "
Closed file $handle\n" if $DEBUG;
$nfiles--;
$inentry = $save_inentry[$nfiles];
$indirect = $save_indirect[$nfiles];
print "--inentry: $inentry--indirect: $indirect--
\n" if $DEBUG;
last if $matches;
}
if (!$matches) {
&error("Couldn't find target: \"$target\" in file \"$file\".");
if ($cachefound) {
&UpdateCache("($file)$target");
}
}
return $matches;
}
#---------------------------------------------------------------------------
sub make_anchor {
local($ref, $label, $icon) = @_;
local($node_file, $node_name, $img, $href);
print "--make_anchor($ref, $label)
\n" if $DEBUG;
# (foo)bar
if ($ref =~ m/\(([^\)]+)\)\s*([^\t\n,\.]*)/) {
$node_file = $1;
$node_name = $2;
} elsif ($file =~ /^dir$/i) {
print "--(DIR) node - Menu \"@_\" means \"($ref)\"
\n" if $DEBUG;
$node_file = $ref;
$node_name = "";
} else {
$node_file = $h_file;
$node_name = $ref;
}
$node_name =~ s/[ ]*$//;
if ($node_name ne "") {
$href = &Escape("$prefix($node_file)$node_name");
} else {
$href = &Escape("$prefix($node_file)");
}
if ($icon) {
$img = " ";
}
return "$img$label";
}
sub StartMenu {
print "\n
\n" if $active;
$listing++;
}
sub EndListing {
if ($listing) {
print "\n" if $active;
$listing--;
}
}
sub FindFile {
local($filename) = @_;
local($dir, $fil);
print "Trying to open file ", "\"$filename\" in directory \"$directory\" ...\n" if $DEBUG; if (open($handle, "$directory/$filename")) { print "
Opened file \"$directory/$filename\"\n" if $DEBUG; return(1); } else { print "
Could not open file",
"\"$filename\" in directory \"$directory\".\n" if "$DEBUG";
return(0);
}
}
sub TryCache {
local($cachekey) = @_;
local($handle, $line, $h_node);
local($cachevalue, $cachepos, $cachefile, $cachedir, $newkey);
print "
Trying cached entry for \"$cachekey\"...\n" if $DEBUG;
if ($CACHE && &LockCache()) {
if (dbmopen(%cache, $CACHE, 0644)) {
$cachevalue = $cache{$cachekey};
dbmclose(%cache);
&UnLockCache();
} else {
$CACHE = "";
&UnLockCache();
return(0);
}
} else {
$CACHE = "";
return(0);
}
if (!$cachevalue) {
if ($cachekey =~ m,\(.*/.*\).*,) {
$newkey = $cachekey;
$newkey =~ s,^\(.*/([^/\)]*)\),($1),;
return(&TryCache($newkey));
} else {
return(0);
}
}
print "
Cached entry found: " if $DEBUG;
($cachepos, $cachefile) = split("\0", $cachevalue);
print "$cachepos in \"$cachefile\"\n" if $DEBUG;
if ($cachefile =~ /\//) {
$cachedir = $cachefile;
$cachedir =~ s,(.*)/[^/]*$,$1,;
if (!$ALLOWPATH && !grep($_ eq $cachedir, @INFOPATH)) {
print "
Warning: Absolute path-names not allowed!\n" if $DEBUG;
&UpdateCache($cachekey);
return(0);
}
}
if (!&OpenFile($cachefile)) {
&UpdateCache($cachekey);
return(0);
}
$handle = "FH_$nfiles";
print "
--now reading from $handle--\n" if $DEBUG;
if (!seek($handle, $cachepos, 0)) {
close($handle);
&UpdateCache($cachekey);
return(0);
}
print "
Position: $cachepos\n" if $DEBUG;
if ($line = <$handle>) {
chop($line);
$line =~ s/&/&\;/g;
$line =~ s/<\;/g;
$line =~ s/>/>\;/g;
print("
line: <", $line, ">\n") if $DEBUG;
if ($line =~ /^[\037\f]/) {
print "
Found node-start\n" if $DEBUG;
if ($line = <$handle>) {
chop($line);
$line =~ s/&/&\;/g;
$line =~ s/<\;/g;
$line =~ s/>/>\;/g;
print("
line: <", $line, ">\n") if $DEBUG;
if ($line =~ /\bnode: *([^,\t]*)/i) {
$h_node = $1;
$h_node =~ s/\s+$//; # delete trailing spaces
if ($h_node =~ m/^$target$/i) {
print "
Found the node!\n" if $DEBUG;
seek($handle, $cachepos, 0);
print("
", tell, "\n") if $DEBUG;
return(1);
}
}
}
}
}
&UpdateCache($cachekey);
close($handle);
return(0);
}
sub UpdateCache {
local($key, $pos, $file) = @_;
local($value);
if ($CACHE && &LockCache()) {
if (dbmopen(%cache, $CACHE, 0644)) {
if ($pos && $file) {
$cache{$key} = join("\0", $pos, $file);
print "
cache{$key} set to: $pos in \"$file\"\n" if $DEBUG;
} else {
delete $cache{$key};
print "
cache{$key} deleted\n" if $DEBUG;
}
dbmclose(%cache);
&UnLockCache();
return(1);
} else {
$CACHE = "";
&UnLockCache();
return(0);
}
} else {
$CACHE = "";
return(0);
}
}
sub LockCache {
local($file) = $CACHE . ".lock";
if (!open(LOCKFILE, ">$file")) {
print "
Couldn't open CACHE lockfile \"$file\"\n" if $DEBUG;
print "
Reason: $!\n" if $DEBUG;
return(0);
}
if (!flock(LOCKFILE, $LOCK_EX)) {
print "
Couldn't lock CACHE lockfile \"$file\"\n" if $DEBUG;
print "
Reason: $!\n" if $DEBUG;
close(LOCKFILE);
return(0);
}
print "
Locked CACHE lockfile \"$file\"\n" if $DEBUG;
return(1);
}
sub UnLockCache {
local($file) = $CACHE . ".lock";
if (!flock(LOCKFILE, $LOCK_UN)) {
print "
Couldn't unlock CACHE lockfile \"$file\"\n" if $DEBUG;
print "
Reason: $!\n" if $DEBUG;
close(LOCKFILE);
return(0);
}
close(LOCKFILE);
print "
Unlocked CACHE lockfile \"$file\"\n" if $DEBUG;
return(1);
}
sub error {
local($reason) = @_;
print
"