Blame manweb

Packit 78deda
#!/usr/bin/perl -w
Packit 78deda
Packit 78deda
use strict;
Packit 78deda
use English;
Packit 78deda
#use File::stat;
Packit 78deda
use Errno;
Packit 78deda
use Fcntl ':mode';
Packit 78deda
use Getopt::Long;
Packit 78deda
Packit 78deda
my $FALSE = 0;
Packit 78deda
my $TRUE = !$FALSE;
Packit 78deda
Packit 78deda
our $debug;
Packit 78deda
    
Packit 78deda
Packit 78deda
sub giveHelp() {
Packit 78deda
Packit 78deda
    print("Manweb is a replacement for Man.  It gets reference \n");
Packit 78deda
    print("documentation from the Worldwide Web or a private web. \n");
Packit 78deda
    print("Manweb is distributed with the Netpbm package \n");
Packit 78deda
    print("(http://netpbm.sourceforge.net).\n");
Packit 78deda
    print("\n");
Packit 78deda
    print("Documentation of Manweb is at \n");
Packit 78deda
    print("\n");
Packit 78deda
    print("        http://netpbm.sourceforge.net/doc/manweb.html\n");
Packit 78deda
    print("\n");
Packit 78deda
    print("Or if you have it properly installed, just use the command \n");
Packit 78deda
    print("\n");
Packit 78deda
    print("        manweb manweb \n");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
sub debug(@) {
Packit 78deda
    if ($debug) {
Packit 78deda
        print(STDERR @_, "\n");
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
sub findUrl($@);  # findUrl() is recursive.
Packit 78deda
Packit 78deda
sub findUrl($@) {
Packit 78deda
    my ($webdir, @topicList) = @_;
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
#  Starting in the directory $webdir, find the URL for the documentation
Packit 78deda
#  of the topic identified by @topicList.  @topicList is a main topic
Packit 78deda
#  followed by a subtopic of that topic, and so on.
Packit 78deda
#
Packit 78deda
#  If @topicList is an empty list, return the url that refers to the 
Packit 78deda
#  directory $webdir itself.
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
    my $url;
Packit 78deda
Packit 78deda
    if (@topicList == 0) {
Packit 78deda
        # He's not specifying a topic; that means he just wants the index
Packit 78deda
        # of the specified directory -- but only if it exists.
Packit 78deda
Packit 78deda
        if (-d($webdir)) {
Packit 78deda
            $url = directoryUrl($webdir);
Packit 78deda
        } 
Packit 78deda
    } else {
Packit 78deda
        my $topic0 = shift(@topicList);
Packit 78deda
Packit 78deda
        # First look for a .url file 
Packit 78deda
Packit 78deda
        $url = doturl($webdir, $topic0, @topicList);
Packit 78deda
        if (!defined($url)) {
Packit 78deda
            # No .url file.  Look for directory.
Packit 78deda
            
Packit 78deda
            my $subwebdir = "$webdir/$topic0";
Packit 78deda
            if (-d($subwebdir)) {
Packit 78deda
                $url = findUrl($subwebdir, @topicList);
Packit 78deda
            } else {
Packit 78deda
                # No directory.  Look for html file.
Packit 78deda
                my $htmlfilename = "$webdir/$topic0.html";
Packit 78deda
            
Packit 78deda
                if (-f($htmlfilename)) {
Packit 78deda
                    if (@topicList > 0) {
Packit 78deda
                        print(STDERR 
Packit 78deda
                              "Ignoring subtopic chain '@topicList' because " .
Packit 78deda
                              "There is an html file named " .
Packit 78deda
                              "'$htmlfilename'.\n");
Packit 78deda
                    } 
Packit 78deda
                    $url = "file://$htmlfilename";
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    return($url);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub findUrlInPath($@) {
Packit 78deda
    my ($webdirR, @topicList) = @_;
Packit 78deda
Packit 78deda
    my @webdirLeft = @$webdirR;
Packit 78deda
Packit 78deda
    my $url;
Packit 78deda
Packit 78deda
    for (my $webdir = shift(@webdirLeft);
Packit 78deda
         defined($webdir) && !defined($url);
Packit 78deda
         $webdir = shift(@webdirLeft)) {
Packit 78deda
Packit 78deda
        $url = findUrl($webdir, @topicList);
Packit 78deda
    }
Packit 78deda
    return $url;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub directoryUrl($$) {
Packit 78deda
    # If this directory has an index file, that's the URL.  Otherwise
Packit 78deda
    # it's just the directory itself.  Too bad the browser doesn't do
Packit 78deda
    # this for us, like it does for HTTP URLs.
Packit 78deda
Packit 78deda
    my ($webdir) = @_;
Packit 78deda
    my ($dev, $ino, $mode, $rest) = stat("$webdir/index.html");
Packit 78deda
Packit 78deda
    my $url;
Packit 78deda
Packit 78deda
    if (defined($mode) && S_ISREG($mode)) {
Packit 78deda
        $url = "file://$webdir/index.html";
Packit 78deda
    } else {
Packit 78deda
        my ($dev, $ino, $mode, $rest) = stat("$webdir/index.htm");
Packit 78deda
        if (defined($mode) && S_ISREG($mode)) {
Packit 78deda
            $url = "file://$webdir/index.htm";
Packit 78deda
        } else {
Packit 78deda
            $url = "file://$webdir";
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    return($url);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub doturl($$) {
Packit 78deda
    my ($webdir, $topic0, @topicList) = @_;
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
#  Handle a .url file.
Packit 78deda
#
Packit 78deda
#  If there is a file named "$topic0.url" in the directory $webdir,
Packit 78deda
#  return the URL that gets to the proper web page for subtopic list
Packit 78deda
#  @topiclist with respect to the URL in that .url file.
Packit 78deda
#
Packit 78deda
#  If there's no such .url file, though, return an undefined value.
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
    my $url;
Packit 78deda
Packit 78deda
    my $urlfilename = "$webdir/$topic0.url";
Packit 78deda
Packit 78deda
    my $openworked = open(URLFILE, "<$urlfilename");
Packit 78deda
        
Packit 78deda
    if ($openworked) {
Packit 78deda
        my @url = <URLFILE>;
Packit 78deda
        if (@url == 0) {
Packit 78deda
            die("URL file '$urlfilename' is empty.");
Packit 78deda
        } elsif (@url > 1) {
Packit 78deda
            die("URL file '$urlfilename' contains more than one line.");
Packit 78deda
        } else {
Packit 78deda
            my $topUrl = $url[0];
Packit 78deda
            chomp($topUrl);
Packit 78deda
            if (@topicList > 0) {
Packit 78deda
                if ($topUrl =~ m|.*[^/]$|) {
Packit 78deda
                    print(STDERR 
Packit 78deda
                          "Ignoring subtopic chain '@topicList' because " .
Packit 78deda
                          "URL '$topUrl' is not a directory URL.\n");
Packit 78deda
                }
Packit 78deda
                $url = $topUrl . join("/", @topicList) . ".html";
Packit 78deda
            } else {
Packit 78deda
                $url = $topUrl;
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    return($url);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub executablePathUrl($) {
Packit 78deda
    my ($progName) = @_;
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
#  If $progName is the name of a program that would be found in the
Packit 78deda
#  program search path (as defined by the PATH environment variable),
Packit 78deda
#  and the directory in which the program resides contains a file
Packit 78deda
#  .docurl, return the first line of that file, appended with
Packit 78deda
#  "$progName.html" as the URL.  If the line from the file doesn't end
Packit 78deda
#  with a slash, though, just return the line itself.
Packit 78deda
#
Packit 78deda
#  If $progName is not such a program name, or there is no .docurl,
Packit 78deda
#  return undefined. 
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
    my $url;
Packit 78deda
Packit 78deda
    my @path = split(/:/,$ENV{"PATH"});
Packit 78deda
    
Packit 78deda
    my $i;
Packit 78deda
    my $progDir;
Packit 78deda
    for ($i = 0; $i < @path && !$progDir; ++$i) {
Packit 78deda
        my $testProgName = $path[$i] . "/" . $progName;
Packit 78deda
        if (-x($testProgName) && -f($testProgName)) {
Packit 78deda
            $progDir = $path[$i];
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if ($progDir) {
Packit 78deda
        debug("Found program '$progName' in directory '$progDir'");
Packit 78deda
        my $urlfilename = "$progDir/doc.url";
Packit 78deda
        if (-f($urlfilename)) {
Packit 78deda
            debug("Looking at file '$urlfilename'");
Packit 78deda
            my $openworked = open(URLFILE, "<$urlfilename");
Packit 78deda
        
Packit 78deda
            if ($openworked) {
Packit 78deda
                my @url = <URLFILE>;
Packit 78deda
                if (@url == 0) {
Packit 78deda
                    die("URL file '$urlfilename' is empty.");
Packit 78deda
                } elsif (@url > 1) {
Packit 78deda
                    die("URL file '$urlfilename' contains more " .
Packit 78deda
                        "than one line.");
Packit 78deda
                } else {
Packit 78deda
                    my $topUrl = $url[0];
Packit 78deda
                    chomp($topUrl);
Packit 78deda
                    debug("doc.url file contains URL '$topUrl'");
Packit 78deda
                    if ($topUrl =~ m|.*[^/]$|) {
Packit 78deda
                        $url = $topUrl;
Packit 78deda
                    } else {
Packit 78deda
                        $url = "$topUrl/$progName.html";
Packit 78deda
                    }
Packit 78deda
                }
Packit 78deda
            } else {
Packit 78deda
                die("Unable to open file '$urlfilename'.");
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
Packit 78deda
    return($url);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub infoTopicExists($) {
Packit 78deda
    my ($searchtopic) = @_;
Packit 78deda
Packit 78deda
    if (!defined($searchtopic)) {
Packit 78deda
        die("no topic passed to infoTopicExists");
Packit 78deda
    }
Packit 78deda
    
Packit 78deda
    my $infopath = ($ENV{"INFOPATH"} or "/usr/info");
Packit 78deda
    
Packit 78deda
    my @infopath = split(/:/, $infopath);
Packit 78deda
    
Packit 78deda
    my $found;
Packit 78deda
    
Packit 78deda
    $found = $FALSE;
Packit 78deda
Packit 78deda
    for (my $infodir = shift(@infopath);
Packit 78deda
         defined($infodir) && !$found; 
Packit 78deda
         $infodir = shift(@infopath)) {
Packit 78deda
Packit 78deda
        my $opened = open(my $dirfile, "<$infodir/dir");
Packit 78deda
Packit 78deda
        if ($opened) {
Packit 78deda
            while ((defined(my $dirfileline = <$dirfile>)) && !$found) {
Packit 78deda
                if ($dirfileline =~ m{^\* (.*):}) {
Packit 78deda
                    my $topic = $1;
Packit 78deda
                    
Packit 78deda
                    if (lc($topic) eq lc($searchtopic)) {
Packit 78deda
                        $found = $TRUE;
Packit 78deda
                    }
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            close($dirfile);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    return $found;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
sub validateWebdir($@) {
Packit 78deda
    my ($confFile, @webdir) = @_;
Packit 78deda
Packit 78deda
    foreach my $webdir (@webdir) {
Packit 78deda
Packit 78deda
        if ($webdir =~ m{^[^/]}) {
Packit 78deda
            die("webdir component '$webdir' " .
Packit 78deda
                "in configuration file '$confFile' " .
Packit 78deda
                "is not valid.  It must be an absolute path, and " .
Packit 78deda
                "therefore start with a slash.");
Packit 78deda
        } elsif ($webdir =~ m{^//}) {
Packit 78deda
            # Two slashes would cause a unique problem when we try
Packit 78deda
            # to make a file: URL out of it.
Packit 78deda
            die("webdir component '$webdir' " .
Packit 78deda
                "in configuration file '$confFile' " .
Packit 78deda
                "is not valid.  It starts with two slashes.");
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
sub readConfFile($) {
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
#  Read the configuration file (/etc/manweb.conf or value of
Packit 78deda
#  MANWEB_CONF_FILE or named by our argument).  Return values set in
Packit 78deda
#  it, or defaults.
Packit 78deda
#-----------------------------------------------------------------------------
Packit 78deda
    my ($fileArg) = @_;
Packit 78deda
    
Packit 78deda
    my $confFile;
Packit 78deda
Packit 78deda
    if (defined($fileArg)) {
Packit 78deda
        $confFile = $fileArg;
Packit 78deda
    } else {
Packit 78deda
        my $envVblValue = $ENV{"MANWEB_CONF_FILE"};
Packit 78deda
        if (defined($envVblValue)) {
Packit 78deda
            $confFile = $envVblValue;
Packit 78deda
        } else {
Packit 78deda
            $confFile = "/etc/manweb.conf";
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
Packit 78deda
    open(CONF, "<$confFile") or die("Can't open configuration file " .
Packit 78deda
                                    "'$confFile'.  $ERRNO");
Packit 78deda
    
Packit 78deda
    my (@webdir, $browser);
Packit 78deda
Packit 78deda
    while(<CONF>) {
Packit 78deda
        chomp();
Packit 78deda
        if (/^\s*#/) {
Packit 78deda
            #It's comment - ignore
Packit 78deda
        } elsif (/^\s*$/) {
Packit 78deda
            #It's a blank line - ignore
Packit 78deda
        } elsif (/\s*(\S+)\s*=\s*(\S+)/) {
Packit 78deda
            #It looks like "keyword=value"
Packit 78deda
            my ($keyword, $value) = ($1, $2);
Packit 78deda
            if ($keyword eq "webdir") {
Packit 78deda
                @webdir = split(/:/, $value);
Packit 78deda
                validateWebdir($confFile, @webdir);
Packit 78deda
            } elsif ($keyword eq "browser") {
Packit 78deda
                $browser = $value;
Packit 78deda
            } else {
Packit 78deda
                die("Unrecognized keyword in configuration file '$confFile': " 
Packit 78deda
                    . "'$keyword'");
Packit 78deda
            }
Packit 78deda
        } else {
Packit 78deda
            die("Invalid syntax in configuration file line '$_'.  " .
Packit 78deda
                "Must be keyword=value, #comment, or blank line");
Packit 78deda
            }
Packit 78deda
    }              
Packit 78deda
    close(CONF);
Packit 78deda
Packit 78deda
    if (!@webdir) {
Packit 78deda
        @webdir = ("/usr/man/web");
Packit 78deda
    }
Packit 78deda
    if (!defined($browser)) {
Packit 78deda
        $browser = $ENV{"BROWSER"} ? $ENV{"BROWSER"} : "lynx";
Packit 78deda
    }
Packit 78deda
    
Packit 78deda
    return(\@webdir, $browser);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
##############################################################################
Packit 78deda
#                               MAINLINE
Packit 78deda
##############################################################################
Packit 78deda
Packit 78deda
my ($optConfig, $optHelp, $optDebug);
Packit 78deda
Packit 78deda
my $validOptions = GetOptions("config=s" => \$optConfig,
Packit 78deda
                              "help" => \$optHelp,
Packit 78deda
                              "debug" => \$optDebug,
Packit 78deda
                              );
Packit 78deda
Packit 78deda
if (!$validOptions) { print(STDERR "Invalid syntax.\n"); exit(1); }
Packit 78deda
Packit 78deda
if ($optHelp) { 
Packit 78deda
    giveHelp(); 
Packit 78deda
    exit(0);
Packit 78deda
}
Packit 78deda
Packit 78deda
$debug = $optDebug;
Packit 78deda
Packit 78deda
my ($webdirR, $browser) = readConfFile($optConfig);
Packit 78deda
Packit 78deda
my $url;
Packit 78deda
Packit 78deda
my $directUrl = findUrlInPath($webdirR, @ARGV);
Packit 78deda
Packit 78deda
if (defined($directUrl)) {
Packit 78deda
    $url = $directUrl;
Packit 78deda
    debug("Found URL in doc search path");
Packit 78deda
} else {
Packit 78deda
    if (@ARGV == 1) {
Packit 78deda
        $url = executablePathUrl($ARGV[0]);
Packit 78deda
        if (defined($url)) {debug("Found URL via executable path");}
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
if (defined($url)) {
Packit 78deda
    print(STDERR "Browsing URL '$url'...\n");
Packit 78deda
    system($browser, $url);
Packit 78deda
} else {
Packit 78deda
    if (@ARGV == 1) {
Packit 78deda
        if (infoTopicExists($ARGV[0])) {
Packit 78deda
            print(STDERR 
Packit 78deda
                  "No web doc, but 'info' topic found.  Running 'info'...\n");
Packit 78deda
            system("info", $ARGV[0]);
Packit 78deda
        } else {
Packit 78deda
            my $mantopic = $ARGV[0];
Packit 78deda
            print(STDERR 
Packit 78deda
                  "No web doc.  Running 'man' on topic '$mantopic'...\n");
Packit 78deda
            system("man", $mantopic);
Packit 78deda
        }
Packit 78deda
    } elsif (@ARGV == 2 && $ARGV[0] =~ m{\d+}) {
Packit 78deda
        my ($mansection, $mantopic) = @ARGV;
Packit 78deda
        print(STDERR
Packit 78deda
              "No web doc.  Running 'man ' on Section $mansection, " .
Packit 78deda
              "Topic '$mantopic'...\n");
Packit 78deda
        system("man", $mansection, $mantopic);
Packit 78deda
    } else {
Packit 78deda
        print(STDERR "No web documentation found for topic chain @ARGV " .
Packit 78deda
              "and it isn't in the right form to try a man page\n");
Packit 78deda
        exit(1);
Packit 78deda
    }
Packit 78deda
}