aboutsummaryrefslogtreecommitdiffstats
path: root/dist-tools/manServer.pl
diff options
context:
space:
mode:
authorMatthias Andree <matthias.andree@gmx.de>2022-07-16 13:46:08 +0200
committerMatthias Andree <matthias.andree@gmx.de>2022-07-16 13:56:56 +0200
commit14a2cd2881e86752fc517d031aa0e05be9abdaf1 (patch)
tree4abdc371d48f8c0e3f90319ab92293f094b409b7 /dist-tools/manServer.pl
parent9c9b249d1886f0e51fd17fe5a85ef5c23ad65a32 (diff)
downloadfetchmail-14a2cd2881e86752fc517d031aa0e05be9abdaf1.tar.gz
fetchmail-14a2cd2881e86752fc517d031aa0e05be9abdaf1.tar.bz2
fetchmail-14a2cd2881e86752fc517d031aa0e05be9abdaf1.zip
manpage: switch HTML rendering to pandoc->docutils
remove manServer.pl
Diffstat (limited to 'dist-tools/manServer.pl')
-rwxr-xr-xdist-tools/manServer.pl2939
1 files changed, 0 insertions, 2939 deletions
diff --git a/dist-tools/manServer.pl b/dist-tools/manServer.pl
deleted file mode 100755
index 6573f650..00000000
--- a/dist-tools/manServer.pl
+++ /dev/null
@@ -1,2939 +0,0 @@
-#!/usr/bin/perl -T
-
-# manServer - Unix man page to HTML converter
-# Rolf Howarth, rolf@squarebox.co.uk
-# Version 1.07 16 July 2001
-# Version 1.07+ma1 2006-03-31 Matthias Andree
-# add trailing slash of URLs
-# support https, too
-
-$version = "1.07+ma1";
-$manServerUrl = "<A HREF=\"http://www.squarebox.co.uk/users/rolf/download/manServer.shtml\">manServer $version</A>";
-
-use Socket;
-
-$ENV{'PATH'} = "/bin:/usr/bin";
-
-initialise();
-$request = shift @ARGV;
-# Usage: manServer [-dn] filename | manServer [-s port]
-
-$root = "";
-$cgiMode = 0;
-$bodyTag = "BODY bgcolor=#F0F0F0 text=#000000 link=#0000ff vlink=#C000C0 alink=#ff0000";
-
-if ($ENV{'GATEWAY_INTERFACE'} ne "")
-{
- *OUT = *STDOUT;
- open(LOG, ">>/tmp/manServer.log");
- chmod(0666, '/tmp/manServer.log');
- $root = $ENV{'SCRIPT_NAME'};
- $url = $ENV{'PATH_INFO'};
- if ($ENV{'REQUEST_METHOD'} eq "POST")
- { $args = <STDIN>; chop $args; }
- else
- { $args = $ENV{'QUERY_STRING'}; }
- $url .= "?".$args if ($args);
- $cgiMode = 1;
- $date = &fmtTime(time);
- $remoteHost = $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'};
- $referer = $ENV{'HTTP_REFERER'};
- $userAgent = $ENV{'HTTP_USER_AGENT'};
- print LOG "$date\t$remoteHost\t$url\t$referer\t$userAgent\n";
- processRequest($url);
-}
-elsif ($request eq "-s" || $request eq "")
-{
- *LOG = *STDERR;
- startServer();
-}
-else
-{
- $cmdLineMode = 1;
- if ($request =~ m/^-d(\d)/)
- {
- $debug = $1;
- $request = shift @ARGV;
- }
- *OUT = *STDOUT;
- *LOG = *STDERR;
- $file = findPage($request);
- man2html($file);
-}
-
-exit(0);
-
-
-##### Mini HTTP Server ####
-
-sub startServer
-{
- ($port) = @ARGV;
- $port = 8888 unless $port;
-
- $sockaddr = 'S n a4 x8';
-
- ($name, $aliases, $proto) = getprotobyname('tcp');
- ($name, $aliases, $port) = getservbyname($port, 'tcp')
- unless $port =~ /^\d+$/;
-
- while(1)
- {
- $this = pack($sockaddr, AF_INET, $port, "\0\0\0\0");
-
- select(NS); $| = 1; select(stdout);
-
- socket(S, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
- if (bind(S, $this))
- {
- last;
- }
- else
- {
- print STDERR "Failed to bind to port $port: $!\n";
- ++$port;
- }
- }
-
- listen(S, 5) || die "connect: $!";
-
- select(S); $| = 1; select(stdout);
-
- while(1)
- {
- print LOG "Waiting for connection on port $port\n";
- ($addr = accept(NS,S)) || die $!;
- #print "accept ok\n";
-
- ($af,$rport,$inetaddr) = unpack($sockaddr,$addr);
- @inetaddr = unpack('C4',$inetaddr);
- print LOG "Got connection from ", join(".",@inetaddr), "\n";
-
- while (<NS>)
- {
- if (m/^GET (\S+)/) { $url = $1; }
- last if (m/^\s*$/);
- }
- *OUT = *NS;
- processRequest($url);
- close NS ;
- }
-}
-
-
-sub processRequest
-{
- $url = $_[0];
- print LOG "Request = $url, root = $root\n";
-
- if ( ($url =~ m/^([^?]*)\?(.*)$/) || ($url =~ m/^([^&]*)&(.*)$/) )
- {
- $request = $1;
- $args = $2;
- }
- else
- {
- $request = $url;
- $args = "";
- }
-
- @params = split(/[=&]/, $args);
- for ($i=0; $i<=$#params; ++$i)
- {
- $params[$i] =~ tr/+/ /;
- $params[$i] =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("C",hex($1))/eg;
- }
- %params = @params;
-
- $request = $params{'q'} if ($params{'q'});
- $searchType = $params{'t'};
- $debug = $params{'d'};
-
- $processed = 0;
- $file = "";
-
- if ($searchType)
- {
- print OUT "HTTP/1.0 200 Ok\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- print OUT "<H1>Searching not yet implemented</H1>\n";
- print LOG "Searching not implemented\n";
- $processed = 1;
- }
- elsif ($request eq "/" || $request eq "")
- {
- print OUT "HTTP/1.0 200 Ok\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- print LOG "Home page\n";
- homePage();
- $processed = 1;
- }
- elsif ($request =~ m,^/.*/$,)
- {
- print OUT "HTTP/1.0 200 Ok\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- print LOG "List directory\n";
- listDir($request);
- $processed = 1;
- }
- elsif (-f $request || -f "$request.gz" || -f "$request.bz2")
- {
- # Only allow fully specified files if they're in our manpath
- foreach $md (@manpath)
- {
- $dir = $md;
- if (substr($request,0,length($dir)) eq $dir)
- {
- print OUT "HTTP/1.0 200 Ok\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- man2html($request);
- $processed = 1;
- last;
- }
- }
- }
- else
- {
- $file = findPage($request);
- if (@multipleMatches)
- {
- print OUT "HTTP/1.0 200 Ok\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- print LOG "Multiple matches\n";
- printMatches();
- $processed = 1;
- }
- elsif ($file)
- {
- print OUT "HTTP/1.0 301 Redirected\n" unless ($cgiMode);
- $file .= "&d=$debug" if ($debug);
- print OUT "Location: $root$file\n\n";
- print LOG "Redirect to $root$file\n";
- $processed = 1;
- }
- }
-
- unless ($processed)
- {
- print OUT "HTTP/1.0 404 Not Found\n" unless ($cgiMode);
- print OUT "Content-type: text/html\n\n";
- print OUT "<HTML><HEAD>\n<TITLE>Not Found</TITLE>\n<$bodyTag>\n";
- print OUT "<CENTER><H1><HR>Not Found<HR></H1></CENTER>\nFailed to find man page /$request\n";
- print OUT "<P><HR><P><A HREF=\"$root/\">Main Index</A>\n</HTML>\n";
- print STDERR "Failed to find /$request\n" unless ($cgiMode);
- }
-}
-
-sub homePage
-{
- print OUT "<HTML><HEAD><TITLE>Manual Pages - Main Index</TITLE>
-</HEAD><$bodyTag><CENTER><H1><HR><I>Manual Reference Pages</I> - Main Index<HR></H1></CENTER>
-<FORM ACTION=\"$root/\" METHOD=get>\n";
- $uname = `uname -s -r`;
- if (! $?)
- {
- $hostname = `hostname`;
- print OUT "<B>$uname pages on $hostname</B><P>\n";
- }
- # print OUT "<SELECT name=t> <OPTION selected value=0>Command name
- # <OPTION value=1>Keyword search <OPTION value=2>Full text search</SELECT>\n";
- print OUT "Command name: <INPUT name=q size=20> <INPUT type=submit value=\"Show Page\"> </FORM><P>\n";
- loadManDirs();
- foreach $dir (@mandirs)
- {
- ($section) = ($dir =~ m/man([0-9A-Za-z]+)$/);
- print OUT "<A HREF=\"$root$dir/\">$dir" ;
- print OUT "- <I>$sectionName{$section}</I>" if ($sectionName{$section});
- print OUT "</A><BR>\n";
- }
- print OUT "<P><HR><P><FONT SIZE=-1>Generated by $manServerUrl from local unix man pages.</FONT>\n</BODY></HTML>\n";
-}
-
-sub listDir
-{
- foreach $md (@manpath)
- {
- $dir = $md;
- if (substr($request,0,length($dir)) eq $dir)
- {
- $request =~ s,/$,,;
- ($section) = ($request =~ m/man([0-9A-Za-z]+)$/);
- $sectionName = $sectionName{$section};
- $sectionName = "Manual Reference Pages" unless ($sectionName);
- print OUT "<HTML><HEAD><TITLE>Contents of $request</TITLE></HEAD>\n<$bodyTag>\n";
- print OUT "<CENTER><H1><HR><NOBR><I>$sectionName</I></NOBR> - <NOBR>Index of $request</NOBR><HR></H1></CENTER>\n";
- print OUT "<FORM ACTION=\"$root/\" METHOD=get>\n";
- print OUT "Command name: <INPUT name=q size=20> <INPUT type=submit value=\"Show Page\"> </FORM><P>\n";
-
- if (opendir(DIR, $request))
- {
- @files = sort readdir DIR;
- foreach $f (@files)
- {
- next if ($f eq "." || $f eq ".." || $f !~ m/\./);
- $f =~ s/\.(gz|bz2)$//;
- # ($name) = ($f =~ m,/([^/]*)$,);
- print OUT "<A HREF=\"$root$request/$f\">$f</A>&nbsp;\n";
- }
- closedir DIR;
- }
- print OUT "<P><A HREF=\"$root/\">Main Index</A>\n</HTML>\n";
- print OUT "<P><HR><P><FONT SIZE=-1>Generated by $manServerUrl from local unix man pages.</FONT>\n</BODY></HTML>\n";
- return;
- }
- }
- print OUT "<H1>Directory $request not known</H1>\n";
-}
-
-sub printMatches
-{
- print OUT "<HTML><HEAD><TITLE>Ambiguous Request '$request'</TITLE></HEAD>\n<$bodyTag>\n";
- print OUT "<CENTER><H1><HR>Ambiguous Request '$request'<HR></H1></CENTER>\nPlease select one of the following pages:<P><BLOCKQUOTE>";
- foreach $f (@multipleMatches)
- {
- print OUT "<A HREF=\"$root$f\">$f</A><BR>\n";
- }
- print OUT "</BLOCKQUOTE><HR><P><A HREF=\"$root/\">Main Index</A>\n</HTML>\n";
-}
-
-
-##### Process troff input using man macros into HTML #####
-
-sub man2html
-{
- $file = $_[0];
- $srcfile = $file;
- $zfile = $file;
- if (! -f $file)
- {
- if (-f "$file.gz")
- {
- $zfile = "$file.gz";
- $zcat = "/usr/bin/zcat";
- $zcat = "/bin/zcat" unless (-x $zcat);
- $srcfile = "$zcat $zfile |";
- $srcfile =~ m/^(.*)$/;
- $srcfile = $1; # untaint
- }
- elsif (-f "$file.bz2")
- {
- $zfile = "$file.bz2";
- $srcfile = "/usr/bin/bzcat $zfile |";
- $srcfile =~ m/^(.*)$/;
- $srcfile = $1; # untaint
- }
- }
- print LOG "man2html $file\n";
- $foundNroffTag = 0;
- loadContents($file);
- unless (open(SRC, $srcfile))
- {
- print OUT "<H1>Failed to open $file</H1>\n";
- print STDERR "Failed to open $srcfile\n";
- return;
- }
- ($dir,$page,$sect) = ($file =~ m,^(.*)/([^/]+)\.([^.]+)$,);
- $troffTable = 0;
- %macro = ();
- %renamedMacro = ();
- %deletedMacro = ();
- @indent = ();
- @tabstops = ();
- $indentLevel = 0;
- $prevailingIndent = 6;
- $trapLine = 0;
- $blockquote = 0;
- $noSpace = 0;
- $firstSection = 0;
- $eqnStart = "";
- $eqnEnd = "";
- $eqnMode = 0;
- %eqndefs = ();
- $defaultNm = "";
- $title = $file;
- $title = "Manual Page - $page($sect)" if ($page && $sect);
-
- $_ = getLine();
- if (m/^.so (man.*)$/)
- {
- # An .so include on the first line only is replaced by the referenced page.
- # (See elsewhere for processing of included sections that occur later in document.)
- man2html("$dir/../$1");
- return;
- }
-
- $perlPattern = "";
- if ($file =~ m/perl/)
- {
- &loadPerlPages();
- $perlPattern = join('|', grep($_ ne $page, keys %perlPages));
- }
-
- print OUT "<HTML><HEAD>\n<TITLE>$title</TITLE>\n<$bodyTag><A NAME=top></A>\n";
-
- if ($foundNroffTag)
- {
- do
- {
- preProcessLine();
- processLine();
- }
- while(getLine());
- endNoFill();
- endParagraph();
- }
- else
- {
- # Special case where input is not nroff at all but is preformatted text
- $sectionName = "Manual Reference Pages";
- $sectionNumber = $sect;
- $left = "Manual Page";
- $right = "Manual Page";
- $macroPackage = "(preformatted text)";
- $pageName = "$page($sect)";
- $saveCurrentLine = $_;
- outputPageHead();
- $_ = $saveCurrentLine;
- print OUT "<PRE>\n";
- do
- {
- print OUT $_;
- }
- while(getLine());
- print OUT "</PRE>\n";
- }
- outputPageFooter();
-}
-
-sub outputPageHead
-{
- plainOutput( "<CENTER>\n" );
- outputLine( "<H1><HR><I>$sectionName &nbsp;-&nbsp;</I><NOBR>$pageName</NOBR><HR></H1>\n" );
- plainOutput( "</CENTER>\n" );
-}
-
-sub outputPageFooter
-{
- if ($pageName)
- {
- unless ($cmdLineMode)
- {
- plainOutput( "<FORM ACTION=\"$root/\" METHOD=get>\n" );
- plainOutput( "Jump to page &nbsp;<INPUT name=q size=12>&nbsp; or go to <A HREF=#top>Top of page</A>&nbsp;|&nbsp;\n" );
- plainOutput( "<A HREF=\"$root$dir/\">Section $sectionNumber</A>&nbsp;|&nbsp;\n" );
- plainOutput( "<A HREF=\"$root/\">Main Index</A>.\n" );
- plainOutput( "<FORM>\n" );
- }
- endBlockquote();
- outputLine("<P><HR>\n<TABLE width=100%><TR> <TD width=33%><I>$left</I></TD> <TD width=33% align=center>$pageName</TD> <TD align=right width=33%><I>$right</I></TD> </TR></TABLE>");
- }
- plainOutput("<FONT SIZE=-1>Generated by $manServerUrl from $zfile $macroPackage.</FONT>\n</BODY></HTML>\n");
-}
-
-sub outputContents
-{
- print OUT "<A name=contents></A><H3>CONTENTS</H3></A>\n";
- blockquote();
- for ($id=1; $id<=$#contents; ++$id)
- {
- $name = $contents[$id];
- $pre = "";
- $pre = "&nbsp; &nbsp; &nbsp;" if ($name =~ m/^ /);
- $pre .= "&nbsp; &nbsp; &nbsp;" if ($name =~ m/^ /);
- $name =~ s,^\s+,,;
- next if ($name eq "" || $name =~ m,^/,);
- unless ($name =~ m/[a-z]/)
- {
- $name = "\u\L$name";
- $name =~ s/ (.)/ \u\1/g;
- }
- outputLine("$pre<A HREF=#$id>$name</A><BR>\n");
- }
- endBlockquote();
-}
-
-# First pass to extract table of contents
-sub loadContents
-{
- @contents = ();
- %contents = ();
- # print STDERR "SRCFILE = $srcfile\n";
- open(SRC, $srcfile) || return;
- while (<SRC>)
- {
- preProcessLine();
- $foundNroffTag = $foundNroffTag || (m/^\.(\\\"|TH|so) /);
- if (m/^\.(S[HShs]) ([A-Z].*)\s*$/)
- {
- $foundNroffTag = 1;
- $c = $1;
- $t = $2;
- $t =~ s/"//g;
- $id = @contents;
- if ($c eq "SH" || $c eq "Sh")
- {
- push(@contents, $t);
- }
- elsif ($t =~ m/\\f/)
- {
- $t =~ s/\\f.//g;
- push(@contents, " $t");
- }
- else
- {
- push(@contents, " $t");
- }
- $contents{"\U$t"} = $id;
- }
- }
- close SRC;
-}
-
-# Preprocess $_
-sub preProcessLine
-{
- # Remove spurious white space to canonicise the input
- chop;
- $origLine = $_;
- s, $,,g;
- s,^',.,; # treat non breaking requests as if there was a dot
- s,^\.\s*,\.,;
-
- if ($eqnMode == 1)
- {
- if (m/$eqnEnd/)
- {
- s,^(.*?)$eqnEnd,&processEqnd($1),e;
- $eqnMode = 0;
- }
- else
- {
- &processEqns($_);
- }
- }
- if ($eqnStart && $eqnMode==0)
- {
- s,$eqnStart(.*?)$eqnEnd,&processEqnd($1),ge;
- if (m/$eqnStart/)
- {
- s,$eqnStart(.*)$,&processEqns($1),e;
- $eqnMode = 1;
- }
- }
-
- # XXX Note: multiple levels of escaping aren't handled properly, eg. \\*.. as a macro argument
- # should get interpolated as string but ends up with a literal '\' being copied through to output.
- s,\\\\\*q,&#34;,g; # treat mdoc \\*q as special case
-
- s,\\\\,_DBLSLASH_,g;
- s,\\ ,_SPACE_,g;
- s,\s*\\".*$,,;
- s,\\$,,;
-
- # Then apply any variable substitutions and escape < and >
- # (which has to be done before we start inserting tags...)
- s,\\\*\((..),$vars{$1},ge;
- s/\\\*([*'`,^,:~].)/$vars{$1}||"\\*$1"/ge;
- s,\\\*(.),$vars{$1},ge;
- # Expand special characters for the first time (eg. \(<-
- s,\\\((..),$special{$1}||"\\($1",ge;
- s,<,&lt;,g;
- s,>,&gt;,g;
-
- # Interpolate width and number registers
- s,\\w(.)(.*?)\1,&width($2),ge;
- s,\\n\((..),&numreg($1),ge;
- s,\\n(.),&numreg($1),ge;
-}
-
-# Undo slash escaping, normally done at output stage, also in macro defn
-sub postProcessLine
-{
- s,_DBLSLASH_,\\,g;
- s,_SPACE_, ,g;
-}
-
-# Rewrite the line, expanding escapes such as font styles, and output it.
-# The line may be a plain text troff line, or it might be the expanded output of a
-# macro in which case some HTML tags may already have been inserted into the text.
-sub outputLine
-{
- $_ = $_[0];
-
- print OUT "<!-- Output: \"$_\" -->\n" if ($debug>1);
-
- if ($needBreak)
- {
- plainOutput("<!-- Need break --><BR>\n");
- lineBreak();
- }
- if ($textSinceBreak && !$noFill && $_ =~ m/^\s/)
- {
- plainOutput("<BR>\n");
- lineBreak();
- }
-
- s,\\&\.,&#46;,g; # \&. often used to escape dot at start of line
- s,\\\.,&#46;,g;
- s,\\\^,,g;
- s,\\\|,,g;
- s,\\c,,g;
- s,\\0,&nbsp;,g;
- s,\\t,\t,g;
-
- s,\\%,&nbsp;,g;
- s,\\\{,,g;
- s,\\},,g;
- s,\\$,,g;
-
- s,\\e,&#92;,g;
- s,\\([-+_~#[]),\1,g;
-
- # Can't implement local motion tags
- s,\\[hv](.).*?\1,,g;
- s,\\z,,g;
-
- # Font changes, super/sub-scripts and font size changes
- s,\\(f[^(]|f\(..|u|d|s[-+]?\d),&inlineStyle($1),ge;
-
- # Overstrike
- if (m/\\o/)
- {
- # handle a few special accent cases we know how to deal with
- s,\\o(.)([aouAOU])"\1,\\o\1\2:\1,g;
- s,\\o(.)(.)\\(.)\1,\\o\1\2\3\1,g;
- s;\\o(.)([A-Za-z])(['`:,^~])\1;\\o\1\3\2\1;g;
- #s,\\o(.)(.*?)\1,"<BLINK>".($vars{$2}||$2)."</BLINK>",ge;
- s,\\o(.)(.*?)\1,$vars{$2}||$2,ge;
- }
- # Bracket building (ignore)
- s,\\b(.)(.*?)\1,\2,g;
-
- s,\\`,&#96;,g;
- s,\\',&#39;,g;
- s,',&#146;,g;
- s,`,&#145;,g;
-
- # Expand special characters introduced by eqn
- s,\\\((..),$special{$1}||"\\($1",ge;
- s,\\\((..),<BLINK>\\($1</BLINK>,g unless (m,^\.,);
-
- # Don't know how to handle other escapes
- s,(\\[^&]),<BLINK>\1</BLINK>,g unless (m,^\.,);
-
- postProcessLine();
-
- # Insert links for http, ftp and mailto URLs
- # Recognised URLs are sequence of alphanumerics and special chars like / and ~
- # but must finish with an alphanumeric rather than punctuation like "."
- s,\b(https?://[-\w/~:@.%#+$?=]+[\w/]),<A HREF=\"\1\">\1</A>,g;
- s,\b(ftp://[-\w/~:@.%#+$?=]+),<A HREF=\"\1\">\1</A>,g;
- s,([-_A-Za-z0-9.]+@[A-Za-z][-_A-Za-z0-9]*\.[-_A-Za-z0-9.]+),<A HREF=\"mailto:\1\">\1</A>,g;
-
- # special case for things like 'perlre' as it's so useful but the
- # pod-generated pages aren't very parser friendly...
- if ($perlPattern && ! m/<A HREF/i)
- {
- s,\b($perlPattern)\b,<A HREF=\"$root$perlPages{$1}\">\1</A>,g;
- }
-
- # Do this late so \& can be used to suppress conversion of URLs etc.
- s,\\&,,g;
-
- # replace tabs with spaces to next multiple of 8
- if (m/\t/)
- {
- $tmp = $_;
- $tmp =~ s/<[^>]*>//g;
- $tmp =~ s/&[^;]*;/@/g;
- @tmp = split(/\t/, $tmp);
- $pos = 0;
- for ($i=0; $i<=$#tmp; ++$i)
- {
- $pos += length($tmp[$i]);
- $tab[$i] = 0;
- $tab[$i] = 8 - $pos%8 unless (@tabstops);
- foreach $ts (@tabstops)
- {
- if ($pos < $ts)
- {
- $tab[$i] = $ts-$pos;
- last;
- }
- }
- $pos += $tab[$i];
- }
- while (m/\t/)
- {
- s,\t,"&nbsp;" x (shift @tab),e;
- }
- }
-
- $textSinceBreak = $_ unless ($textSinceBreak);
- print OUT $_;
-}
-
-# Output a line consisting purely of HTML tags which shouldn't be regarded as
-# a troff output line.
-sub plainOutput
-{
- print OUT $_[0];
-}
-
-
-# Output the original line for debugging
-sub outputOrigLine
-{
- print OUT "<!-- $origLine -->\n";
-}
-
-# Use this to read the next input line (buffered to implement lookahead)
-sub getLine
-{
- $lookaheadPtr = 0;
- if (@lookahead)
- {
- $_ = shift @lookahead;
- return $_;
- }
- $_ = <SRC>;
-}
-
-# Look ahead to peek at the next input line
-sub _lookahead
-{
- # set lookaheadPtr to 0 to re-read the lines we've looked ahead at
- if ($lookaheadPtr>=0 && $lookaheadPtr <= $#lookahead)
- {
- return $lookahead[$lookaheadPtr++];
- }
- $lookaheadPtr = -1;
- $ll = <SRC>;
- push(@lookahead, $ll);
- return $ll;
-}
-
-# Consume the last line that was returned by lookahead
-sub consume
-{
- --$lookaheadPtr;
- if ($lookaheadPtr>=0 && $lookaheadPtr <= $#lookahead)
- {
- $removed = $lookahead[$lookaheadPtr];
- @lookahead = (@lookahead[0..$lookaheadPtr-1],@lookahead[$lookaheadPtr+1..$#lookahead]);
- }
- else
- {
- $removed = pop @lookahead;
- }
- chop $removed;
- plainOutput("<!-- Consumed $removed -->\n");
-}
-
-# Look ahead skipping comments and other common non-text tags
-sub lookahead
-{
- $ll = _lookahead();
- while ($ll =~ m/^\.(\\"|PD|IX|ns)/)
- {
- $ll = _lookahead();
- }
- return $ll;
-}
-
-# Process $_, expaning any macros into HTML and calling outputLine().
-# If necessary, this method can read more lines of input from <SRC> (.ig & .de)
-# The following state variables are used:
-# ...
-sub processLine
-{
- $doneLine = 1; # By default, this counts as a line for trap purposes
-
- s,^\.if t ,,;
- s,^\.el ,,; # conditions assumed to evaluate false, so else must be true...
-
- if ($troffTable)
- {
- processTable();
- }
- elsif ($eqnMode == 2)
- {
- plainOutput("<!-- $_ -->\n");
- processEqns($_);
- }
- elsif (m/^\./)
- {
- processMacro();
- }
- else
- {
- processPlainText();
- }
- if ($doneLine)
- {
- # Called after processing (most) input lines to decrement trapLine. This is needed
- # to implement the .it 1 trap after one line for .TP, where the first line is outdented
- if ($trapLine > 0)
- {
- --$trapLine;
- if ($trapLine == 0)
- {
- &$trapAction;
- }
- }
- }
-}
-
-
-# Process plain text lines
-sub processPlainText
-{
- if ($_ eq "")
- {
- lineBreak();
- plainOutput("<P>\n");
- return;
- }
-
- s,(\\f[23BI])([A-Z].*?)(\\f.),$1.($contents{"\U$2"}?"<A HREF=#".$contents{"\U$2"}.">$2</A>":$2).$3,ge;
-
- if ($currentSection eq "SEE ALSO" && ! $cmdLineMode)
- {
- # Some people don't use BR or IR for see also refs
- s,(^|\s)([-.A-Za-z_0-9]+)\s?\(([0-9lL][0-9a-zA-Z]*)\),\1<A HREF=\"$root/$2.$3\">$2($3)</A>,g;
- }
- outputLine("$_\n");
-}
-
-
-# Process macros and built-in directives
-sub processMacro
-{
- outputOrigLine();
-
- # Place macro arguments (space delimited unless within ") into @p
- # Remove " from $_, place command in $c, remainder in $joined
-
- @p = grep($_ !~ m/^\s*$/, split(/("[^"]*"|\s+)/) );
- grep(s/"//g, @p);
- $_ = join(" ", @p);
- $p[0] =~ s/^\.//;
- $c = $p[0];
- $joined = join(" ", @p[1..$#p]);
- $joined2 = join(" ", @p[2..$#p]);
- $joined3 = join(" ", @p[3..$#p]);
-
- if ($macro{$c}) # Expand macro
- {
- # Get full macro text
- $macro = $macro{$c};
- # Interpolate arguments
- $macro =~ s,\\\$(\d),$p[$1],ge;
- #print OUT "<!-- Expanding $c to\n$macro-->\n";
- foreach $_ (split(/\n/, $macro))
- {
- $_ .= "\n";
- preProcessLine();
- processLine();
- }
- $doneLine = 0;
- return;
- }
- elsif ($renamedMacro{$c})
- {
- $c = $renamedMacro{$c};
- }
-
- if ($c eq "ds") # Define string
- {
- $vars{$p[1]} = $joined2;
- $doneLine = 0;
- }
- elsif ($c eq "nr") # Define number register
- {
- $number{$p[1]} = evalnum($joined2);
- $doneLine = 0;
- }
- elsif ($c eq "ti") # Temporary indent
- {
- plainOutput("&nbsp; &nbsp;");
- }
- elsif ($c eq "rm")
- {
- $macroName = $p[1];
- if ($macro{$macroName})
- {
- delete $macro{$macroName};
- }
- else
- {
- $deletedMacro{$macroName} = 1;
- }
- }
- elsif ($c eq "rn")
- {
- $oldName = $p[1];
- $newName = $p[2];
- $macro = $macro{$oldName};
- if ($macro)
- {
- if ($newName =~ $reservedMacros && ! $deletedMacro{$newName})
- {
- plainOutput("<!-- Not overwriting reserved macro '$newName' -->\n");
- }
- else
- {
- $macro{$newName} = $macro;
- delete $deletedMacro{$newName};
- }
- delete $macro{$oldName};
- }
- else
- {
- # Support renaming of reserved macros by mapping occurrences of new name
- # to old name after macro expansion so that built in definition is still
- # available, also mark the name as deleted to override reservedMacro checks.
- plainOutput("<!-- Fake renaming reserved macro '$oldName' -->\n");
- $renamedMacro{$newName} = $oldName;
- $deletedMacro{$oldName} = 1;
- }
- }
- elsif ($c eq "de" || $c eq "ig") # Define macro or ignore
- {
- $macroName = $p[1];
- if ($c eq "ig")
- { $delim = ".$p[1]"; }
- else
- { $delim = ".$p[2]"; }
- $delim = ".." if ($delim eq ".");
- # plainOutput("<!-- Scanning for delimiter $delim -->\n");
-
- $macro = "";
- $_ = getLine();
- preProcessLine();
- while ($_ ne $delim)
- {
- postProcessLine();
- outputOrigLine();
- $macro .= "$_\n";
- $_ = getLine();
- last if ($_ eq "");
- preProcessLine();
- }
- outputOrigLine();
- # plainOutput("<!-- Found delimiter -->\n");
- if ($c eq "de")
- {
- if ($macroName =~ $reservedMacros && ! $deletedMacro{$macroName})
- {
- plainOutput("<!-- Not defining reserved macro '$macroName' ! -->\n");
- }
- else
- {
- $macro{$macroName} = $macro;
- delete $deletedMacro{$macroName};
- }
- }
- }
- elsif ($c eq "so") # Source
- {
- plainOutput("<P>[<A HREF=\"$root$dir/../$p[1]\">Include document $p[1]</A>]<P>\n");
- }
- elsif ($c eq "TH" || $c eq "Dt") # Man page title
- {
- endParagraph();
- $sectionNumber = $p[2];
- $sectionName = $sectionName{"\L$sectionNumber"};
- $sectionName = "Manual Reference Pages" unless ($sectionName);
- $pageName = "$p[1] ($sectionNumber)";
- outputPageHead();
- if ($c eq "TH")
- {
- $right = $p[3];
- $left = $p[4];
- $left = $osver unless ($left);
- $macroPackage = "using man macros";
- }
- else
- {
- $macroPackage = "using doc macros";
- }
- }
- elsif ($c eq "Nd")
- {
- outputLine("- $joined\n");
- }
- elsif ($c eq "SH" || $c eq "SS" || $c eq "Sh" || $c eq "Ss") # Section/subsection
- {
- lineBreak();
- endNoFill();
- endParagraph();
- $id = $contents{"\U$joined"};
- $currentSection = $joined;
-
- if ($c eq "SH" || $c eq "Sh")
- {
- endBlockquote();
- if ($firstSection++==1) # after first 'Name' section
- {
- outputContents();
- }
- outputLine( "<A name=$id>\n\n <H3>$joined</H3>\n\n</A>\n" );
- blockquote();
- }
- elsif ($joined =~ m/\\f/)
- {
- $joined =~ s/\\f.//g;
- $id = $contents{"\U$joined"};
- outputLine( "<A name=$id>\n<H4><I>$joined</I></H4></A>\n" );
- }
- else
- {
- endBlockquote();
- outputLine( "<A name=$id>\n\n <H4>&nbsp; &nbsp; $joined</H4>\n</A>\n" );
- blockquote();
- }
- lineBreak();
- }
- elsif ($c eq "TX" || $c eq "TZ") # Document reference
- {
- $title = $title{$p[1]};
- $title = "Document [$p[1]]" unless ($title);
- outputLine( "\\fI$title\\fP$joined2\n" );
- }
- elsif ($c eq "PD") # Line spacing
- {
- $noSpace = ($p[1] eq "0");
- $doneLine = 0;
- }
- elsif ($c eq "TS") # Table start
- {
- unless ($macroPackage =~ /tbl/)
- {
- if ($macroPackage =~ /eqn/)
- { $macroPackage =~ s/eqn/eqn & tbl/; }
- else
- { $macroPackage .= " with tbl support"; }
- }
- resetStyles();
- endNoFill();
- $troffTable = 1;
- $troffSeparator = "\t";
- plainOutput( "<P><BLOCKQUOTE><TABLE bgcolor=#E0E0E0 border=1 cellspacing=0 cellpadding=3>\n" );
- }
- elsif ($c eq "EQ") # Eqn start
- {
- unless ($macroPackage =~ /eqn/)
- {
- if ($macroPackage =~ /tbl/)
- { $macroPackage =~ s/tbl/tbl & eqn/; }
- else
- { $macroPackage .= " with eqn support"; }
- }
- $eqnMode = 2;
- }
- elsif ($c eq "ps") # Point size
- {
- plainOutput(&sizeChange($p[1]));
- }
- elsif ($c eq "ft") # Font change
- {
- plainOutput(&fontChange($p[1]));
- }
- elsif ($c eq "I" || $c eq "B") # Single word font change
- {
- $id = $contents{"\U$joined"};
- if ($id && $joined =~ m/^[A-Z]/)
- { $joined = "<A HREF=#$id>$joined</A>"; }
- outputLine( "\\f$c$joined\\fP " );
- plainOutput("\n") if ($noFill);
- }
- elsif ($c eq "SM") # Single word smaller
- {
- outputLine("\\s-1$joined\\s0 ");
- $doneLine = 0 unless ($joined);
- }
- elsif ($c eq "SB") # Single word bold and small
- {
- outputLine("\\fB\\s-1$joined\\s0\\fP ");
- }
- elsif (m/^\.[BI]R (\S+)\s?\(\s?([0-9lL][0-9a-zA-Z]*)\s?\)(.*)$/)
- {
- # Special form, .BR is generally used for references to other pages
- # Annoyingly, some people have more than one per line...
- # Also, some people use .IR ...
- for ($i=1; $i<=$#p; $i+=2)
- {
- $pair = $p[$i]." ".$p[$i+1];
- if ($p[$i+1] eq "(")
- {
- $pair .= $p[$i+2].$p[$i+3];
- $i += 2;
- }
- if ($pair =~ m/^(\S+)\s?\(\s?([0-9lL][0-9a-zA-Z]*)\s?\)(.*)$/)
- {
- if ($cmdLineMode)
- { outputLine( "\\fB$1\\fR($2)$3\n" ); }
- else
- { outputLine( "<A HREF=\"$root/$1.$2\">$1($2)</A>$3\n" ); }
- }
- else
- { outputLine( "$pair\n" ); }
- }
- }
- elsif ($c eq "BR" || $c eq "BI" || $c eq "IB" ||
- $c eq "IR" || $c eq "RI" || $c eq "RB")
- {
- $f1 = (substr($c ,0,1));
- $f2 = (substr($c,1,1));
-
- # Check if first param happens to be a section name
- $id = $contents{"\U$p[1]"};
- if ($id && $p[1] =~ m/^[A-Z]/)
- {
- $p[1] = "<A HREF=#$id>$p[1]</A>";
- }
-
- for ($i=1; $i<=$#p; ++$i)
- {
- $f = ($i%2 == 1) ? $f1 : $f2;
- outputLine("\\f$f$p[$i]");
- }
- outputLine("\\fP ");
- plainOutput("\n") if ($noFill);
- }
- elsif ($c eq "nf" || $c eq "Bd") # No fill
- {
- startNoFill();
- }
- elsif ($c eq "fi" || $c eq "Ed") # Fill
- {
- endNoFill();
- }
- elsif ($c eq "HP")
- {
- $indent = evalnum($p[1]);
- if ($trapOnBreak)
- {
- plainOutput("<BR>\n");
- }
- else
- {
- # Outdent first line, ie. until next break
- $trapOnBreak = 1;
- $trapAction = *trapHP;
- newParagraph($indent);
- plainOutput( "<TD colspan=2>\n" );
- $colState = 2;
- }
- }
- elsif ($c eq "IP")
- {
- $trapOnBreak = 0;
- $tag = $p[1];
- $indent = evalnum($p[2]);
- newParagraph($indent);
- outputLine("<TD$width>\n$tag\n</TD><TD>\n");
- $colState = 1;
- lineBreak();
- }
- elsif ($c eq "TP")
- {
- $trapOnBreak = 0;
- $trapLine = 1; # Next line is tag, then next column
- $doneLine = 0; # (But don't count this line)
- $trapAction = *trapTP;
- $indent = evalnum($p[1]);
- $tag = lookahead();
- chop $tag;
- $i = ($indent ? $indent : $prevailingIndent) ;
- $w = width($tag);
- if ($w > $i)
- {
- plainOutput("<!-- Length of tag '$tag' ($w) > indent ($i) -->\n") if ($debug);
- newParagraph($indent);
- $trapAction = *trapHP;
- plainOutput( "<TD colspan=2>\n" );
- $colState = 2;
- }
- else
- {
- newParagraph($indent);
- plainOutput( "<TD$width nowrap>\n" );
- $colState = 0;
- }
- $body = lookahead();
- $lookaheadPtr = 0;
- if ($body =~ m/^\.[HILP]?P/)
- {
- chop $body;
- plainOutput("<!-- Suppressing TP body due to $body -->\n");
- $trapLine = 0;
- }
- }
- elsif ($c eq "LP" || $c eq "PP" || $c eq "P" || $c eq "Pp") # Paragraph
- {
- $trapOnBreak = 0;
- $prevailingIndent = 6;
- if ($indent[$indentLevel] > 0 && $docListStyle eq "")
- {
- $line = lookahead();
- if ($line =~ m/^\.(TP|IP|HP)/)
- {
- plainOutput("<!-- suppressed $c before $1 -->\n");
- }
- elsif ($line =~ m/^\.RS/)
- {
- plainOutput("<P>\n");
- }
- else
- {
- endRow();
- $foundTag = "";
- $lookaheadPtr = 0;
- do
- {
- $line = lookahead();
- if ($line =~ m/^\.(TP|HP|IP|RS)( \d+)?/)
- {
- $indent = $2;
- $indent = $prevailingIndent unless ($2);
- if ($indent == $indent[$indentLevel])
- { $foundTag = $1; }
- $line = "";
- }
- }
- while ($line ne "" && $line !~ m/^\.(RE|SH|SS|PD)/);
- $lookaheadPtr = 0;
- if ($foundTag)
- {
- plainOutput("<!-- Found tag $foundTag -->\n");
- plainOutput("<TR><TD colspan=2>\n");
- $colState = 2;
- }
- else
- {
- plainOutput("<!-- $c ends table -->\n");
- setIndent(0);
- }
- }
- }
- else
- {
- plainOutput("<P>\n");
- }
- lineBreak();
- }
- elsif ($c eq "br") # Break
- {
- if ($trapOnBreak)
- {
- # Should this apply to all macros that cause a break?
- $trapOnBreak = 0;
- &$trapAction();
- }
- $needBreak = 1 if ($textSinceBreak);
- }
- elsif ($c eq "sp") # Space
- {
- lineBreak();
- plainOutput("<P>\n");
- }
- elsif ($c eq "RS") # Block indent start
- {
- if ($indentLevel==0 && $indent[0]==0)
- {
- blockquote();
- }
- else
- {
- $indent = $p[1];
- $indent = $prevailingIndent unless ($indent);
- if ($indent > $indent[$indentLevel] && !$extraIndent)
- {
- $extraIndent = 1;
- ++$indentLevel;
- $indent[$indentLevel] = 0;
- setIndent($indent-$indent[$indentLevel-1]);
- plainOutput("<TR><TD$width>&nbsp;</TD><TD>\n");
- $colState = 1;
- }
- elsif ($indent < $indent[$indentLevel] || $colState==2)
- {
- endRow();
- setIndent($indent);
- plainOutput("<TR><TD$width>&nbsp;</TD><TD>\n");
- $colState = 1;
- }
- ++$indentLevel;
- $indent[$indentLevel] = 0;
- }
- $prevailingIndent = 6;
- }
- elsif ($c eq "RE") # Block indent end
- {
- if ($extraIndent)
- {
- endRow();
- setIndent(0);
- --$indentLevel;
- $extraIndent = 0;
- }
- if ($indentLevel==0)
- {
- endParagraph();
- if ($blockquote>0)
- {
- plainOutput("</BLOCKQUOTE>\n");
- --$blockquote;
- }
- }
- else
- {
- endRow();
- setIndent(0);
- --$indentLevel;
- }
- $prevailingIndent = $indent[$indentLevel];
- $prevailingIndent = 6 unless($prevailingIndent);
- }
- elsif ($c eq "DT") # default tabs
- {
- @tabstops = ();
- }
- elsif ($c eq "ta") # Tab stops
- {
- @tabstops = ();
- for ($i=0; $i<$#p; ++$i)
- {
- $ts = $p[$i+1];
- $tb = 0;
- if ($ts =~ m/^\+/)
- {
- $tb = $tabstops[$i-1];
- $ts =~ s/^\+//;
- }
- $ts = evalnum($ts);
- $tabstops[$i] = $tb + $ts;
- }
- plainOutput("<!-- Tabstops set at ".join(",", @tabstops)." -->\n") if ($debug);
- }
- elsif ($c eq "It") # List item (mdoc)
- {
- lineBreak();
- if ($docListStyle eq "-tag")
- {
- endRow() unless($multilineIt);
- if ($tagWidth)
- {
- setIndent($tagWidth);
- }
- else
- {
- setIndent(6);
- $width = ""; # let table take care of own width
- }
- if ($p[1] eq "Xo")
- {
- plainOutput("<TR valign=top><TD colspan=2>");
- }
- else
- {
- $tag = &mdocStyle(@p[1..$#p]);
- $body = lookahead();
- if ($body =~ m/^\.It/)
- { $multilineItNext = 1; }
- else
- { $multilineItNext = 0; }
- if ($multilineIt)
- {
- outputLine("<BR>\n$tag\n");
- }
- elsif ($multilineItNext || $tagWidth>0 && width($tag)>$tagWidth)
- {
- outputLine("<TR valign=top><TD colspan=2>$tag\n");
- $colState = 2;
- }
- else
- {
- outputLine("<TR valign=top><TD>$tag\n");
- $colState = 1;
- }
- if ($multilineItNext)
- {
- $multilineIt = 1;
- }
- else
- {
- $multilineIt = 0;
- if ($colState==2)
- { plainOutput("</TD></TR><TR><TD>&nbsp;</TD><TD>\n"); }
- else
- { plainOutput("</TD><TD>\n"); }
- }
- }
- }
- else
- {
- plainOutput("<LI>");
- }
- lineBreak();
- }
- elsif ($c eq "Xc")
- {
- if ($docListStyle eq "-tag")
- {
- plainOutput("</TD></TR><TR><TD>&nbsp;</TD><TD>\n");
- }
- }
- elsif ($c eq "Bl") # Begin list (mdoc)
- {
- push @docListStyles, $docListStyle;
- if ($p[1] eq "-enum")
- {
- plainOutput("<OL>\n");
- $docListStyle = $p[1];
- }
- elsif($p[1] eq "-bullet")
- {
- plainOutput("<UL>\n");
- $docListStyle = $p[1];
- }
- else
- {
- $docListStyle = "-tag";
- if ($p[2] eq "-width")
- {
- $tagWidth = width($p[3]);
- if ($tagWidth < 6) { $tagWidth = 6; }
- }
- else
- {
- $tagWidth = 0;
- }
- $multilineIt = 0;
- }
- }
- elsif ($c eq "El") # End list
- {
- if ($docListStyle eq "-tag")
- {
- endRow();
- setIndent(0);
- }
- elsif ($docListStyle eq "-bullet")
- {
- plainOutput("</UL>\n");
- }
- else
- {
- plainOutput("</OL>\n");
- }
- $docListStyle = pop @docListStyles;
- }
- elsif ($c eq "Os")
- {
- $right = $joined;
- }
- elsif ($c eq "Dd")
- {
- $left = $joined;
- }
- elsif ($c eq "Sx") # See section
- {
- $id = $contents{"\U$joined"};
- if ($id && $joined =~ m/^[A-Z]/)
- {
- outputLine("<A HREF=#$id>".&mdocStyle(@p[1..$#p])."</A>\n");
- }
- else
- {
- my $x = &mdocStyle(@p[1..$#p]);
- $x =~ s/^ //;
- outputLine($x."\n");
- }
- }
- elsif (&mdocCallable($c))
- {
- my $x = &mdocStyle(@p);
- $x =~ s/^ //;
- outputLine($x."\n");
- }
- elsif ($c eq "Bx")
- {
- outputLine("<I>BSD $joined</I>\n");
- }
- elsif ($c eq "Ux")
- {
- outputLine("<I>Unix $joined</I>\n");
- }
- elsif ($c eq "At")
- {
- outputLine("<I>AT&T $joined</I>\n");
- }
- elsif ($c =~ m/[A-Z][a-z]/) # Unsupported doc directive
- {
- outputLine("<BR>.$c $joined\n");
- }
- elsif ($c eq "") # Empty line (eg. troff comment)
- {
- $doneLine = 0;
- }
- else # Unsupported directive
- {
- # Unknown macros are ignored, and don't count as a line as far as trapLine goes
- $doneLine = 0;
- plainOutput("<!-- ignored unsupported tag .$c -->\n");
- }
-}
-
-sub trapTP
-{
- $lookaheadPtr = 0;
- $body = lookahead();
- if ($body =~ m/^\.TP/)
- {
- consume();
- $trapLine = 1; # restore TP trap
- $doneLine = 0; # don't count this line
- plainOutput("<BR>\n");
- }
- else
- {
- plainOutput("</TD><TD valign=bottom>\n");
- $colState = 1;
- }
- lineBreak();
-}
-
-sub trapHP
-{
- $lookaheadPtr = 0;
- $body = lookahead();
- if ($body =~ m/^\.([TH]P)/)
- {
- consume();
- # Restore appropriate type of trap
- if ($1 eq "TP")
- {
- $trapLine = 1;
- $doneLine = 0; # don't count this line
- }
- else
- {
- $trapOnBreak = 1;
- }
- plainOutput("<BR>\n");
- }
- else
- {
- plainOutput("</TD></TR><TR valign=top><TD$width>&nbsp;</TD><TD>\n");
- $colState = 1;
- }
- lineBreak();
-}
-
-sub newParagraph
-{
- $indent = $_[0];
- endRow();
- startRow($indent);
-}
-
-sub startRow
-{
- $indent = $_[0];
- $indent = $prevailingIndent unless ($indent);
- $prevailingIndent = $indent;
- setIndent($indent);
- plainOutput( "<TR valign=top>" );
-}
-
-# End an existing HP/TP/IP/RS row
-sub endRow
-{
- if ($indent[$indentLevel] > 0)
- {
- lineBreak();
- plainOutput( "</TD></TR>\n" );
- }
-}
-
-# Called when we output a line break tag. Only needs to be called once if
-# calling plainOutput, but should call before and after if using outputLine.
-sub lineBreak
-{
- $needBreak = 0;
- $textSinceBreak = 0;
-}
-
-# Called to reset all indents and pending paragraphs (eg. at the start of
-# a new top level section).
-sub endParagraph
-{
- ++$indentLevel;
- while ($indentLevel > 0)
- {
- --$indentLevel;
- if ($indent[$indentLevel] > 0)
- {
- endRow();
- setIndent(0);
- }
- }
-}
-
-# Interpolate a number register (possibly autoincrementing)
-sub numreg
-{
- return 0 + $number{$_[0]};
-}
-
-# Evaluate a numeric expression
-sub evalnum
-{
- $n = $_[0];
- return "" if ($n eq "");
- if ($n =~ m/i$/) # inches
- {
- $n =~ s/i//;
- $n *= 10;
- }
- return 0+$n;
-}
-
-sub setIndent
-{
- $tsb = $textSinceBreak;
- $indent = evalnum($_[0]);
- if ($indent==0 && $_[0] !~ m/^0/)
- {
- $indent = 6;
- }
- plainOutput("<!-- setIndent $indent, indent[$indentLevel] = $indent[$indentLevel] -->\n") if ($debug);
- if ($indent[$indentLevel] != $indent)
- {
- lineBreak();
- if ($indent[$indentLevel] > 0)
- {
- plainOutput("<TR></TR>") unless ($noSpace);
- plainOutput("</TABLE>");
- }
- if ($indent > 0)
- {
- endNoFill();
- $border = "";
- $border = " border=1" if ($debug>2);
- #plainOutput("<P>") unless ($indent[$indentLevel] > 0);
- plainOutput("<TABLE$border");
- # Netscape bug, makes 2 cols same width? : plainOutput("<TABLE$border COLS=2");
- # Overcome some of the vagaries of Netscape tables
- plainOutput(" width=100%") if ($indentLevel>0);
- if ($noSpace)
- {
- plainOutput(" cellpadding=0 cellspacing=0>\n");
- }
- else
- {
- plainOutput(" cellpadding=3>".($tsb ? "<!-- tsb: $tsb -->\n<TR></TR><TR></TR>\n" : "\n") );
- }
- #$width = " width=".($indent*5); # causes text to be chopped if too big
- $percent = $indent;
- if ($indentLevel > 0)
- { $percent = $indent * 100 / (100-$indentLevel[0]); }
- $width = " width=$percent%";
- }
- $indent[$indentLevel] = $indent;
- }
-}
-
-# Process mdoc style macros recursively, as one of the macro arguments
-# may itself be the name of another macro to invoke.
-sub mdocStyle
-{
- return "" unless @_;
- my ($tag, @param) = @_;
- my ($rest, $term);
-
- # Don't format trailing punctuation
- if ($param[$#param] =~ m/^[.,;:]$/)
- {
- $term = pop @param;
- }
- if ($param[$#param] =~ m/^[)\]]$/)
- {
- $term = (pop @param).$term;
- }
-
- if ($param[0] =~ m,\\\\,)
- {
- print STDERR "$tag: ",join(",", @param),"\n";
- }
- $rest = &mdocStyle(@param);
-
- if ($tag eq "Op")
- {
- $rest =~ s/ //; # remove first space
- return " \\fP[$rest]$term";
- }
- elsif ($tag eq "Xr") # cross reference
- {
- my $p = shift @param;
- my $url = $p;
- if (@param==1)
- {
- $url .= ".".$param[0];
- $rest = "(".$param[0].")";
- }
- else
- {
- $rest = &mdocStyle(@param);
- }
- if ($cmdLineMode)
- {
- return " <B>".$p."</B>".$rest.$term;
- }
- else
- {
- return " <A HREF=\"".$root."/".$url."\">".$p."</A>".$rest.$term;
- }
- }
- elsif ($tag eq "Fl")
- {
- my ($sofar);
- while (@param)
- {
- $f = shift @param;
- if ($f eq "Ns") # no space
- {
- chop $sofar;
- }
- elsif (&mdocCallable($f))
- {
- unshift @param, $f;
- return $sofar.&mdocStyle(@param).$term;
- }
- else
- {
- $sofar .= "-<B>$f</B> "
- }
- }
- return $sofar.$term;
- }
- elsif ($tag eq "Pa" || $tag eq "Er" || $tag eq "Fn" || $tag eq "Dv")
- {
- return "\\fC$rest\\fP$term";
- }
- elsif ($tag eq "Ad" || $tag eq "Ar" || $tag eq "Em" || $tag eq "Fa" || $tag eq "St" ||
- $tag eq "Ft" || $tag eq "Va" || $tag eq "Ev" || $tag eq "Tn" || $tag eq "%T")
- {
- return "\\fI$rest\\fP$term";
- }
- elsif ($tag eq "Nm")
- {
- $defaultNm = $param[0] unless ($defaultNm);
- $rest = $defaultNm unless ($param[0]);
- return "\\fB$rest\\fP$term";
- }
- elsif ($tag eq "Ic" || $tag eq "Cm" || $tag eq "Sy")
- {
- return "\\fB$rest\\fP$term";
- }
- elsif ($tag eq "Ta") # Tab
- {
- # Tabs are used inconsistently so this is the best we can do. Columns won't line up. Tough.
- return "&nbsp; &nbsp; &nbsp; $rest$term";
- }
- elsif ($tag eq "Ql")
- {
- $rest =~ s/ //;
- return "`<TT>$rest</TT>'$term";
- }
- elsif ($tag eq "Dl")
- {
- return "<P>&nbsp; &nbsp; <TT>$rest</TT>$term<P>\n";
- }
- elsif ($tag =~ m/^[ABDEOPQS][qoc]$/)
- {
- $lq = "";
- $rq = "";
- if ($tag =~ m/^A/)
- { $lq = "&lt;"; $rq = "&gt;"; }
- elsif ($tag =~ m/^B/)
- { $lq = "["; $rq = "]"; }
- elsif ($tag =~ m/^D/)
- { $lq = "\""; $rq = "\""; }
- elsif ($tag =~ m/^P/)
- { $lq = "("; $rq = ")"; }
- elsif ($tag =~ m/^Q/)
- { $lq = "\""; $rq = "\""; }
- elsif ($tag =~ m/^S/)
- { $lq = "\\'"; $rq = "\\'"; }
- elsif ($tag =~ m/^O/)
- { $lq = "["; $rq = "]"; }
- if ($tag =~ m/^.o/)
- { $rq = ""; }
- if ($tag =~ m/^.c/)
- { $lq = ""; }
- $rest =~ s/ //;
- return $lq.$rest.$rq.$term ;
- }
- elsif (&mdocCallable($tag)) # but not in list above...
- {
- return $rest.$term;
- }
- elsif ($tag =~ m/^[.,;:()\[\]]$/) # punctuation
- {
- return $tag.$rest.$term;
- }
- elsif ($tag eq "Ns")
- {
- return $rest.$term;
- }
- else
- {
- return " ".$tag.$rest.$term;
- }
-}
-
-# Determine if a macro is mdoc parseable/callable
-sub mdocCallable
-{
- return ($_[0] =~ m/^(Op|Fl|Pa|Er|Fn|Ns|No|Ad|Ar|Xr|Em|Fa|Ft|St|Ic|Cm|Va|Sy|Nm|Li|Dv|Ev|Tn|Pf|Dl|%T|Ta|Ql|[ABDEOPQS][qoc])$/);
-}
-
-
-# Estimate the output width of a string
-sub width
-{
- local($word) = $_[0];
- $word =~ s,<[/A-Z][^>]*>,,g; # remove any html tags
- $word =~ s/^\.\S+\s//;
- $word =~ s/\\..//g;
- $x = length($word);
- $word =~ s/[ ()|.,!;:"']//g; # width of punctuation is about half a character
- return ($x + length($word)) / 2;
-}
-
-# Process a tbl table (between TS/TE tags)
-sub processTable
-{
- if ($troffTable == "1")
- {
- @troffRowDefs = ();
- @tableRows = ();
- $hadUnderscore = 0;
- while(1)
- {
- outputOrigLine();
- if (m/;\s*$/)
- {
- $troffSeparator = quotemeta($1) if (m/tab\s*\((.)\)/);
- }
- else
- {
- s/\.\s*$//;
- s/\t/ /g;
- s/^[^lrcan^t]*//; # remove any 'modifiers' coming before tag
- # delimit on tags excluding s (viewed as modifier of previous column)
- s/([lrcan^t])/\t$1/g;
- s/^\t//;
- push @troffRowDefs, $_;
- last if ($origLine =~ m/\.\s*$/);
- }
- $_ = getLine();
- preProcessLine();
- }
- $troffTable = 2;
- return;
- }
-
- s/$troffSeparator/\t/g;
- if ($_ eq ".TE")
- {
- endTblRow();
- flushTable();
- $troffTable = 0;
- plainOutput("</TABLE></BLOCKQUOTE>\n");
- }
- elsif ($_ eq ".T&")
- {
- endTblRow();
- flushTable();
- $troffTable = 1;
- }
- elsif (m/[_=]/ && m/^[_=\t]*$/ && $troffCol==0)
- {
- if (m/^[_=]$/)
- {
- flushTable();
- plainOutput("<TR></TR><TR></TR>\n");
- $hadUnderscore = 1;
- }
- elsif ($troffCol==0 && @troffRowDefs)
- {
- # Don't output a row, but this counts as a row as far as row defs go
- $rowDef = shift @troffRowDefs;
- @troffColDefs = split(/\t/, $rowDef);
- }
- }
- elsif (m/^\.sp/ && $troffCol==0 && !$hadUnderscore)
- {
- flushTable();
- plainOutput("<TR></TR><TR></TR>\n");
- }
- elsif ($_ eq ".br" && $troffMultiline)
- {
- $rowref->[$troffCol] .= "<BR>\n";
- }
- elsif ($_ !~ m/^\./)
- {
- $rowref = $tableRows[$#tableRows]; # reference to current row (last row in array)
- if ($troffCol==0 && @troffRowDefs)
- {
- $rowDef = shift @troffRowDefs;
- if ($rowDef =~ m/^[_=]/)
- {
- $xxx = $_;
- flushTable();
- plainOutput("<TR></TR><TR></TR>\n");
- $hadUnderscore = 1;
- $_ = $xxx;
- $rowDef = shift @troffRowDefs;
- }
- @troffColDefs = split(/\t/, $rowDef);
- }
-
- if ($troffCol == 0 && !$troffMultiline)
- {
- $rowref = [];
- push(@tableRows, $rowref);
- #plainOutput("<TR valign=top>");
- }
-
- #{
- if (m/T}/)
- {
- $troffMultiline = 0;
- }
- if ($troffMultiline)
- {
- $rowref->[$troffCol] .= "$_\n";
- return;
- }
-
- @columns = split(/\t/, $_);
- plainOutput("<!-- Adding (".join(",", @columns)."), type (".join(",", @troffColDefs).") -->\n") if ($debug);
- while ($troffCol <= $#troffColDefs && @columns > 0)
- {
- $def = $troffColDefs[$troffCol];
- $col = shift @columns;
- $col =~ s/\s*$//;
- $align = "";
- $col = "\\^" if ($col eq "" && $def =~ m/\^/);
- $col = "&nbsp;" if ($col eq "");
- $style1 = "";
- $style2 = "";
- if ($col ne "\\^")
- {
- if ($def =~ m/[bB]/ || $def =~ m/f3/)
- { $style1 = "\\fB"; $style2 = "\\fP"; }
- if ($def =~ m/I/ || $def =~ m/f2/)
- { $style1 = "\\fI"; $style2 = "\\fP"; }
- }
- if ($def =~ m/c/) { $align = " align=center"; }
- if ($def =~ m/[rn]/) { $align = " align=right"; }
- $span = $def;
- $span =~ s/[^s]//g;
- if ($span) { $align.= " colspan=".(length($span)+1); }
-
- #{
- if ($col =~ m/T}/)
- {
- $rowref->[$troffCol] .= "$style2</TD>";
- ++$troffCol;
- }
- elsif ($col =~ m/T\{/) #}
- {
- $col =~ s/T\{//; #}
- $rowref->[$troffCol] = "<TD$align>$style1$col";
- $troffMultiline = 1;
- }
- else
- {
- $rowref->[$troffCol] = "<TD$align>$style1$col$style2</TD>";
- ++$troffCol;
- }
- }
-
- endTblRow() unless ($troffMultiline);
- }
-}
-
-sub endTblRow
-{
- return if ($troffCol == 0);
- while ($troffCol <= $#troffColDefs)
- {
- $rowref->[$troffCol] = "<TD>&nbsp;</TD>";
- #print OUT "<TD>&nbsp;</TD>";
- ++$troffCol;
- }
- $troffCol = 0;
- #print OUT "</TR>\n"
-}
-
-sub flushTable
-{
- plainOutput("<!-- flushTable $#tableRows rows -->\n") if ($debug);
-
- # Treat rows with first cell blank or with more than one vertically
- # spanned row as a continuation of the previous line.
- # Note this is frequently a useful heuristic but isn't foolproof.
- for($r=0; $r<$#tableRows; ++$r)
- {
- $vspans = 0;
- for ($c=0; $c<=$#{$tableRows[$r+1]}; ++$c)
- {++$vspans if ($tableRows[$r+1][$c] =~ m,<TD.*?>\\\^</TD>,);}
- if ((($vspans>1) || ($tableRows[$r+1][0] =~ m,<TD.*?>&nbsp;</TD>,)) &&
- $#{$tableRows[$r]} == $#{$tableRows[$r+1]} && 0)
- {
- if ($debug)
- {
- plainOutput("<!-- merging row $r+1 into previous -->\n");
- plainOutput("<!-- row $r: (".join(",", @{$tableRows[$r]}).") -->\n");
- plainOutput("<!-- row $r+1: (".join(",", @{$tableRows[$r+1]}).") -->\n");
- }
- for ($c=0; $c<=$#{$tableRows[$r]}; ++$c)
- {
- $tableRows[$r][$c] .= $tableRows[$r+1][$c];
- $tableRows[$r][$c] =~ s,\\\^,,g; # merging is stronger than spanning!
- $tableRows[$r][$c] =~ s,</TD><TD.*?>,<BR>,;
- }
- @tableRows = (@tableRows[0..$r], @tableRows[$r+2 .. $#tableRows]);
- --$r; # process again
- }
- }
-
- # Turn \^ vertical span requests into rowspan tags
- for($r=0; $r<$#tableRows; ++$r)
- {
- for ($c=0; $c<=$#{$tableRows[$r]}; ++$c)
- {
- $r2 = $r+1;
- while ( $r2<=$#tableRows && ($tableRows[$r2][$c] =~ m,<TD.*?>\\\^</TD>,) )
- {
- ++$r2;
- }
- $rs = $r2-$r;
- if ($rs > 1)
- {
- plainOutput("<!-- spanning from $r,$c -->\n") if ($debug);
- $tableRows[$r][$c] =~ s/<TD/<TD rowspan=$rs/;
- }
- }
- }
-
- # As tbl and html differ in whether they expect spanned cells to be
- # supplied, remove any cells that are 'rowspanned into'.
- for($r=0; $r<=$#tableRows; ++$r)
- {
- for ($c=$#{$tableRows[$r]}; $c>=0; --$c)
- {
- if ($tableRows[$r][$c] =~ m/<TD rowspan=(\d+)/)
- {
- for ($r2=$r+1; $r2<$r+$1; ++$r2)
- {
- $rowref = $tableRows[$r2];
- plainOutput("<!-- removing $r2,$c: ".$rowref->[$c]." -->\n") if ($debug);
- @$rowref = (@{$rowref}[0..$c-1], @{$rowref}[$c+1..$#$rowref]);
- }
- }
- }
- }
-
- # Finally, output the cells that are left
- for($r=0; $r<=$#tableRows; ++$r)
- {
- plainOutput("<TR valign=top>\n");
- for ($c=0; $c <= $#{$tableRows[$r]}; ++$c)
- {
- outputLine($tableRows[$r][$c]);
- }
- plainOutput("</TR>\n");
- }
- @tableRows = ();
- $troffCol = 0;
- plainOutput("<!-- flushTable done -->\n") if ($debug);
-}
-
-
-# Use these for all font changes, including .ft, .ps, .B, .BI, .SM etc.
-# Need to add a mechanism to stack up these changes so tags match: <X> <Y> ... </Y> </X> etc.
-
-sub pushStyle
-{
- $result = "";
- $type = $_[0];
- $tag = $_[1];
- print OUT "<!-- pushStyle $type($tag) [".join(",", @styleStack)."] " if ($debug>1);
- @oldItems = ();
- if (grep(m/^$type/, @styleStack))
- {
- print OUT "undoing up to old $type " if ($debug>1);
- while (@styleStack)
- {
- # search back, undoing intervening tags in reverse order
- $oldItem = pop @styleStack;
- ($oldTag) = ($oldItem =~ m/^.(\S+)/);
- $result .= "</$oldTag>";
- if (substr($oldItem,0,1) eq $type)
- {
- print OUT "found $oldItem " if ($debug>1);
- while (@oldItems)
- {
- # restore the intermediates again
- $oldItem = shift @oldItems;
- push(@styleStack, $oldItem);
- $result .= "<".substr($oldItem,1).">";
- }
- last;
- }
- else
- {
- unshift(@oldItems, $oldItem);
- }
- }
- }
- print OUT "oldItems=(@oldItems) " if ($debug>1);
- push(@styleStack, @oldItems); # if we didn't find anything of type
- if ($tag)
- {
- $result .= "<$tag>";
- push(@styleStack, $type.$tag);
- }
- print OUT "-> '$result' -->\n" if ($debug>1);
- return $result;
-}
-
-sub resetStyles
-{
- if (@styleStack)
- {
- print OUT "<!-- resetStyles [".join(",", @styleStack)."] -->\n";
- print OUT "<HR> resetStyles [".join(",", @styleStack)."] <HR>\n" if ($debug);
- }
- while (@styleStack)
- {
- $oldItem = pop @styleStack;
- ($oldTag) = ($oldItem =~ m/^.(\S+)/);
- print OUT "</$oldTag>";
- }
- $currentSize = 0;
- $currentShift = 0;
-}
-
-sub blockquote
-{
- print OUT "<BLOCKQUOTE>\n";
- ++$blockquote;
-}
-
-sub endBlockquote
-{
- resetStyles();
- while ($blockquote > 0)
- {
- print OUT "</BLOCKQUOTE>\n";
- --$blockquote;
- }
-}
-
-sub indent
-{
- plainOutput(pushStyle("I", "TABLE"));
- $width = $_[0];
- $width = " width=$width%" if ($width);
- plainOutput("<TR><TD$width>&nbsp;</TD><TD>\n");
-}
-
-sub outdent
-{
- plainOutput("</TD></TR>\n");
- plainOutput(pushStyle("I"));
-}
-
-sub inlineStyle
-{
- $_[0] =~ m/^(.)(.*)$/;
- if ($1 eq "f")
- { fontChange($2); }
- elsif ($1 eq "s" && ! $noFill)
- { sizeChange($2); }
- else
- { superSub($1); }
-}
-
-sub fontChange
-{
- $fnt = $_[0];
- $fnt =~ s/^\(//;
-
- if ($fnt eq "P" || $fnt eq "R" || $fnt eq "1" || $fnt eq "")
- { $font = ""; }
- elsif ($fnt eq "B" || $fnt eq "3")
- { $font = "B"; }
- elsif ($fnt eq "I" || $fnt eq "2")
- { $font = "I"; }
- else
- { $font = "TT"; }
- return pushStyle("F", $font);
-}
-
-sub sizeChange
-{
- $size= $_[0];
- if ($size =~ m/^[+-]/)
- { $currentSize += $size; }
- else
- { $currentSize = $size-10; }
- $currentSize = 0 if (! $size);
-
- $sz = $currentSize;
- $sz = -2 if ($sz < -2);
- $sz = 2 if ($sz > 2);
-
- if ($currentSize eq "0")
- { $size = ""; }
- else
- { $size = "FONT size=$sz"; }
- return pushStyle("S", $size);
-}
-
-sub superSub
-{
- $sub = $_[0];
- ++$currentShift if ($sub eq "u");
- --$currentShift if ($sub eq "d");
- $tag = "";
- $tag = "SUP" if ($currentShift > 0);
- $tag = "SUB" if ($currentShift < 0);
- return pushStyle("D", $tag);
-}
-
-sub startNoFill
-{
- print OUT "<PRE>\n" unless($noFill);
- $noFill = 1;
-}
-
-sub endNoFill
-{
- print OUT "</PRE>\n" if ($noFill);
- $noFill = 0;
-}
-
-
-sub processEqns
-{
- if ($eqnMode==2 && $_[0] =~ m/^\.EN/)
- {
- $eqnMode = 0;
- outputLine(flushEqn());
- plainOutput("\n");
- return;
- }
- $eqnBuffer .= $_[0]." ";
-}
-
-sub processEqnd
-{
- processEqns(@_);
- return flushEqn();
-}
-
-sub flushEqn
-{
- @p = grep($_ !~ m/^ *$/, split(/("[^"]*"|\s+|[{}~^])/, $eqnBuffer) );
- $eqnBuffer = "";
- #return "[".join(',', @p)." -> ".&doEqn(@p)."]\n";
- $res = &doEqn(@p);
- #$res =~ s,\\\((..),$special{$1}||"\\($1",ge;
- #$res =~ s,<,&lt;,g;
- #$res =~ s,>,&gt;,g;
- return $res;
-}
-
-sub doEqn
-{
- my @p = @_;
- my $result = "";
- my $res;
- my $c;
- while (@p)
- {
- ($res, @p) = doEqn1(@p);
- $result .= $res;
- }
- return $result;
-}
-
-sub doEqn1
-{
- my @p = @_;
- my $res = "";
- my $c;
-
- $c = shift @p;
- if ($eqndefs{$c})
- {
- @x = split(/\0/, $eqndefs{$c});
- unshift @p, @x;
- $c = shift @p;
- }
- if ($c =~ m/^"(.*)"$/)
- {
- $res = $1;
- }
- elsif ($c eq "delim")
- {
- $c = shift @p;
- if ($c eq "off")
- {
- $eqnStart = "";
- $eqnEnd = "";
- }
- else
- {
- $c =~ m/^(.)(.)/;
- $eqnStart = quotemeta($1);
- $eqnEnd = quotemeta($2);
- }
- }
- elsif ($c eq "define" || $c eq "tdefine" || $c eq "ndefine")
- {
- $t = shift @p;
- $d = shift @p;
- $def = "";
- if (length($d) != 1)
- {
- $def = $d;
- $def =~ s/^.(.*)./\1/;
- }
- else
- {
- while (@p && $p[0] ne $d)
- {
- $def .= shift @p;
- $def .= "\0";
- }
- chop $def;
- shift @p;
- }
- $eqndefs{$t} = $def unless ($c eq "ndefine");
- }
- elsif ($c eq "{")
- {
- my $level = 1;
- my $i;
- for ($i=0; $i<=$#p; ++$i)
- {
- ++$level if ($p[$i] eq "{");
- --$level if ($p[$i] eq "}");
- last if ($level==0);
- }
- $res = doEqn(@p[0..$i-1]);
- @p = @p[$i+1..$#p];
- }
- elsif ($c eq "sup")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "\\u$c\\d";
- }
- elsif ($c eq "to")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "\\u$c\\d ";
- }
- elsif ($c eq "sub" || $c eq "from")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "\\d$c\\u";
- }
- elsif ($c eq "matrix")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "matrix ( $c )";
- }
- elsif ($c eq "bold")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "\\fB$c\\fP";
- }
- elsif ($c eq "italic")
- {
- ($c,@p) = &doEqn1(@p);
- $res = "\\fI$c\\fP";
- }
- elsif ($c eq "roman")
- {
- }
- elsif ($c eq "font" || $c eq "gfont" || $c eq "size" || $c eq "gsize")
- {
- shift @p;
- }
- elsif ($c eq "mark" || $c eq "lineup")
- {
- }
- elsif ($c eq "~" || $c eq "^")
- {
- $res = " ";
- }
- elsif ($c eq "over")
- {
- $res = " / ";
- }
- elsif ($c eq "half")
- {
- $res = "\\(12";
- }
- elsif ($c eq "prime")
- {
- $res = "\\' ";
- }
- elsif ($c eq "dot")
- {
- $res = "\\u.\\d ";
- }
- elsif ($c eq "dotdot")
- {
- $res = "\\u..\\d ";
- }
- elsif ($c eq "tilde")
- {
- $res = "\\u~\\d ";
- }
- elsif ($c eq "hat")
- {
- $res = "\\u^\\d ";
- }
- elsif ($c eq "bar" || $c eq "vec")
- {
- $res = "\\(rn ";
- }
- elsif ($c eq "under")
- {
- $res = "_ ";
- }
- elsif ( $c eq "sqrt" || $c eq "lim" || $c eq "sum" || $c eq "pile" || $c eq "lpile" ||
- $c eq "rpile" || $c eq "cpile" || $c eq "int" || $c eq "prod" )
- {
- $res = " $c ";
- }
- elsif ($c eq "cdot")
- {
- $res = " . ";
- }
- elsif ($c eq "inf")
- {
- $res = "\\(if";
- }
- elsif ($c eq "above" || $c eq "lcol" || $c eq "ccol")
- {
- $res = " ";
- }
- elsif ($c eq "sin" || $c eq "cos" || $c eq "tan" || $c eq "log" || $c eq "ln" )
- {
- $res = " $c ";
- }
- elsif ($c eq "left" || $c eq "right" || $c eq "nothing")
- {
- }
- elsif ($c =~ m/^[A-Za-z]/)
- {
- $res = "\\fI$c\\fP";
- }
- else
- {
- $res = $c;
- }
-
- return ($res, @p);
-}
-
-##### Search manpath and initialise special char array #####
-
-sub initialise
-{
- # Determine groff version if possible
- my $groffver = `groff -v`;
- $groffver =~ /^GNU groff version (\S+)/;
- $groffver = $1;
-
- # Parse the macro definition file for section names
- if (open(MACRO, "/usr/lib/tmac/tmac.an") ||
- open(MACRO, "/usr/lib/tmac/an") ||
- open(MACRO, "/usr/lib/groff/tmac/tmac.an") ||
- open(MACRO, "/usr/lib/groff/tmac/an.tmac") ||
- open(MACRO, "/usr/share/tmac/tmac.an") ||
- open(MACRO, "/usr/share/tmac/an.tmac") ||
- open(MACRO, "/usr/share/groff/tmac/tmac.an") ||
- open(MACRO, "/usr/share/groff/tmac/an.tmac") ||
- open(MACRO, "/usr/share/groff/$groffver/tmac/an.tmac") )
- {
- while (<MACRO>)
- {
- chop;
- if (m/\$2'([0-9a-zA-Z]+)' .ds ]D (.*)$/)
- {
- $sn = $2;
- unless ($sn =~ m/[a-z]/)
- {
- $sn = "\u\L$sn";
- $sn =~ s/ (.)/ \u\1/g;
- }
- $sectionName{"\L$1"} = $sn;
- }
- if (m/\$1'([^']+)' .ds Tx "?(.*)$/)
- {
- $title{"$1"} = $2;
- }
- if (m/^.ds ]W (.*)$/)
- {
- $osver = $1;
- }
- }
- }
- else
- {
- print STDERR "Failed to read tmac.an definitions\n" unless ($cgiMode);
- }
- if (open(MACRO, "/usr/lib/tmac/tz.map"))
- {
- while (<MACRO>)
- {
- chop;
- if (m/\$1'([^']+)' .ds Tz "?(.*)$/)
- {
- $title{"$1"} = $2;
- }
- }
- }
-
- # Prevent redefinition of macros that have special meaning to us
- $reservedMacros = '^(SH|SS|Sh|Ss)$';
-
- # Predefine special number registers
- $number{'.l'} = 75;
-
- # String variables defined by man package
- $vars{'lq'} = '&#147;';
- $vars{'rq'} = '&#148;';
- $vars{'R'} = '\\(rg';
- $vars{'S'} = '\\s0';
-
- # String variables defined by mdoc package
- $vars{'Le'} = '\\(<=';
- $vars{'<='} = '\\(<=';
- $vars{'Ge'} = '\\(>=';
- $vars{'Lt'} = '<';
- $vars{'Gt'} = '>';
- $vars{'Ne'} = '\\(!=';
- $vars{'>='} = '\\(>=';
- $vars{'q'} = '&#34;'; # see also special case in preProcessLine
- $vars{'Lq'} = '&#147;';
- $vars{'Rq'} = '&#148;';
- $vars{'ua'} = '\\(ua';
- $vars{'ga'} = '\\(ga';
- $vars{'Pi'} = '\\(*p';
- $vars{'Pm'} = '\\(+-';
- $vars{'Na'} = 'NaN';
- $vars{'If'} = '\\(if';
- $vars{'Ba'} = '|';
-
- # String variables defined by ms package (access to accented characters)
- $vars{'bu'} = '&#187;';
- $vars{'66'} = '&#147;';
- $vars{'99'} = '&#148;';
- $vars{'*!'} = '&#161;';
- $vars{'ct'} = '&#162;';
- $vars{'po'} = '&#163;';
- $vars{'gc'} = '&#164;';
- $vars{'ye'} = '&#165;';
- #$vars{'??'} = '&#166;';
- $vars{'sc'} = '&#167;';
- $vars{'*:'} = '&#168;';
- $vars{'co'} = '&#169;';
- $vars{'_a'} = '&#170;';
- $vars{'<<'} = '&#171;';
- $vars{'no'} = '&#172;';
- $vars{'hy'} = '&#173;';
- $vars{'rg'} = '&#174;';
- $vars{'ba'} = '&#175;';
- $vars{'de'} = '&#176;';
- $vars{'pm'} = '&#177;';
- #$vars{'??'} = '&#178;';
- #$vars{'??'} = '&#179;';
- $vars{'aa'} = '&#180;';
- $vars{'mu'} = '&#181;';
- $vars{'pg'} = '&#182;';
- $vars{'c.'} = '&#183;';
- $vars{'cd'} = '&#184;';
- #$vars{'??'} = '&#185;';
- $vars{'_o'} = '&#186;';
- $vars{'>>'} = '&#187;';
- $vars{'14'} = '&#188;';
- $vars{'12'} = '&#189;';
- #$vars{'??'} = '&#190;';
- $vars{'*?'} = '&#191;';
- $vars{'`A'} = '&#192;';
- $vars{"'A"} = '&#193;';
- $vars{'^A'} = '&#194;';
- $vars{'~A'} = '&#195;';
- $vars{':A'} = '&#196;';
- $vars{'oA'} = '&#197;';
- $vars{'AE'} = '&#198;';
- $vars{',C'} = '&#199;';
- $vars{'`E'} = '&#200;';
- $vars{"'E"} = '&#201;';
- $vars{'^E'} = '&#202;';
- $vars{':E'} = '&#203;';
- $vars{'`I'} = '&#204;';
- $vars{"'I"} = '&#205;';
- $vars{'^I'} = '&#206;';
- $vars{':I'} = '&#207;';
- $vars{'-D'} = '&#208;';
- $vars{'~N'} = '&#209;';
- $vars{'`O'} = '&#210;';
- $vars{"'O"} = '&#211;';
- $vars{'^O'} = '&#212;';
- $vars{'~O'} = '&#213;';
- $vars{':O'} = '&#214;';
- #$vars{'mu'} = '&#215;';
- $vars{'NU'} = '&#216;';
- $vars{'`U'} = '&#217;';
- $vars{"'U"} = '&#218;';
- $vars{'^U'} = '&#219;';
- $vars{':U'} = '&#220;';
- #$vars{'??'} = '&#221;';
- $vars{'Th'} = '&#222;';
- $vars{'*b'} = '&#223;';
- $vars{'`a'} = '&#224;';
- $vars{"'a"} = '&#225;';
- $vars{'^a'} = '&#226;';
- $vars{'~a'} = '&#227;';
- $vars{':a'} = '&#228;';
- $vars{'oa'} = '&#229;';
- $vars{'ae'} = '&#230;';
- $vars{',c'} = '&#231;';
- $vars{'`e'} = '&#232;';
- $vars{"'e"} = '&#233;';
- $vars{'^e'} = '&#234;';
- $vars{':e'} = '&#235;';
- $vars{'`i'} = '&#236;';
- $vars{"'i"} = '&#237;';
- $vars{'^i'} = '&#238;';
- $vars{':i'} = '&#239;';
- #$vars{'??'} = '&#240;';
- $vars{'~n'} = '&#241;';
- $vars{'`o'} = '&#242;';
- $vars{"'o"} = '&#243;';
- $vars{'^o'} = '&#244;';
- $vars{'~o'} = '&#245;';
- $vars{':o'} = '&#246;';
- $vars{'di'} = '&#247;';
- $vars{'nu'} = '&#248;';
- $vars{'`u'} = '&#249;';
- $vars{"'u"} = '&#250;';
- $vars{'^u'} = '&#251;';
- $vars{':u'} = '&#252;';
- #$vars{'??'} = '&#253;';
- $vars{'th'} = '&#254;';
- $vars{':y'} = '&#255;';
-
- # troff special characters and their closest equivalent
-
- $special{'em'} = '&#151;';
- $special{'hy'} = '-';
- $special{'\-'} = '&#150;'; # was -
- $special{'bu'} = 'o';
- $special{'sq'} = '[]';
- $special{'ru'} = '_';
- $special{'14'} = '&#188;';
- $special{'12'} = '&#189;';
- $special{'34'} = '&#190;';
- $special{'fi'} = 'fi';
- $special{'fl'} = 'fl';
- $special{'ff'} = 'ff';
- $special{'Fi'} = 'ffi';
- $special{'Fl'} = 'ffl';
- $special{'de'} = '&#176;';
- $special{'dg'} = '&#134;'; # was 182, para symbol
- $special{'fm'} = "\\'";
- $special{'ct'} = '&#162;';
- $special{'rg'} = '&#174;';
- $special{'co'} = '&#169;';
- $special{'pl'} = '+';
- $special{'mi'} = '-';
- $special{'eq'} = '=';
- $special{'**'} = '*';
- $special{'sc'} = '&#167;';
- $special{'aa'} = '&#180;'; # was '
- $special{'ga'} = '&#96;'; # was `
- $special{'ul'} = '_';
- $special{'sl'} = '/';
- $special{'*a'} = 'a';
- $special{'*b'} = '&#223;';
- $special{'*g'} = 'y';
- $special{'*d'} = 'd';
- $special{'*e'} = 'e';
- $special{'*z'} = 'z';
- $special{'*y'} = 'n';
- $special{'*h'} = 'th';
- $special{'*i'} = 'i';
- $special{'*k'} = 'k';
- $special{'*l'} = 'l';
- $special{'*m'} = '&#181;';
- $special{'*n'} = 'v';
- $special{'*c'} = '3';
- $special{'*o'} = 'o';
- $special{'*p'} = 'pi';
- $special{'*r'} = 'p';
- $special{'*s'} = 's';
- $special{'*t'} = 't';
- $special{'*u'} = 'u';
- $special{'*f'} = 'ph';
- $special{'*x'} = 'x';
- $special{'*q'} = 'ps';
- $special{'*w'} = 'o';
- $special{'*A'} = 'A';
- $special{'*B'} = 'B';
- $special{'*G'} = '|\\u_\\d';
- $special{'*D'} = '/&#92;';
- $special{'*E'} = 'E';
- $special{'*Z'} = 'Z';
- $special{'*Y'} = 'H';
- $special{'*H'} = 'TH';
- $special{'*I'} = 'I';
- $special{'*K'} = 'K';
- $special{'*L'} = 'L';
- $special{'*M'} = 'M';
- $special{'*N'} = 'N';
- $special{'*C'} = 'Z';
- $special{'*O'} = 'O';
- $special{'*P'} = '||';
- $special{'*R'} = 'P';
- $special{'*S'} = 'S';
- $special{'*T'} = 'T';
- $special{'*U'} = 'Y';
- $special{'*F'} = 'PH';
- $special{'*X'} = 'X';
- $special{'*Q'} = 'PS';
- $special{'*W'} = 'O';
- $special{'ts'} = 's';
- $special{'sr'} = 'v/';
- $special{'rn'} = '\\u&#150;\\d'; # was 175
- $special{'>='} = '&gt;=';
- $special{'<='} = '&lt;=';
- $special{'=='} = '==';
- $special{'~='} = '~=';
- $special{'ap'} = '&#126;'; # was ~
- $special{'!='} = '!=';
- $special{'->'} = '-&gt;';
- $special{'<-'} = '&lt;-';
- $special{'ua'} = '^';
- $special{'da'} = 'v';
- $special{'mu'} = '&#215;';
- $special{'di'} = '&#247;';
- $special{'+-'} = '&#177;';
- $special{'cu'} = 'U';
- $special{'ca'} = '^';
- $special{'sb'} = '(';
- $special{'sp'} = ')';
- $special{'ib'} = '(=';
- $special{'ip'} = '=)';
- $special{'if'} = 'oo';
- $special{'pd'} = '6';
- $special{'gr'} = 'V';
- $special{'no'} = '&#172;';
- $special{'is'} = 'I';
- $special{'pt'} = '~';
- $special{'es'} = '&#216;';
- $special{'mo'} = 'e';
- $special{'br'} = '|';
- $special{'dd'} = '&#135;'; # was 165, yen
- $special{'rh'} = '=&gt;';
- $special{'lh'} = '&lt;=';
- $special{'or'} = '|';
- $special{'ci'} = 'O';
- $special{'lt'} = '(';
- $special{'lb'} = '(';
- $special{'rt'} = ')';
- $special{'rb'} = ')';
- $special{'lk'} = '|';
- $special{'rk'} = '|';
- $special{'bv'} = '|';
- $special{'lf'} = '|';
- $special{'rf'} = '|';
- $special{'lc'} = '|';
- $special{'rc'} = '|';
-
- # Not true troff characters but very common typos
- $special{'cp'} = '&#169;';
- $special{'tm'} = '&#174;';
- $special{'en'} = '-';
-
- # Build a list of directories containing man pages
- @manpath = ();
- if (open(MPC, "/etc/manpath.config") || open(MPC, "/etc/man.config"))
- {
- while (<MPC>)
- {
- if (m/^(MANDB_MAP|MANPATH)\s+(\S+)/)
- {
- push(@manpath, $2);
- }
- }
- }
- @manpath = split(/:/, $ENV{'MANPATH'}) unless (@manpath);
- @manpath = ("/usr/man") unless (@manpath);
-}
-
-# Search through @manpath and construct @mandirs (non-empty subsections)
-sub loadManDirs
-{
- return if (@mandirs);
- print STDERR "Searching ",join(":", @manpath)," for mandirs\n" unless($cgiMode);
- foreach $tld (@manpath)
- {
- $tld =~ m/^(.*)$/;
- $tld = $1; # untaint manpath
- if (opendir(DIR, $tld))
- {
- # foreach $d (<$tld/man[0-9a-z]*>)
- foreach $d (sort readdir(DIR))
- {
- if ($d =~ m/^man\w/ && -d "$tld/$d")
- {
- push (@mandirs, "$tld/$d");
- }
- }
- closedir DIR;
- }
- }
-}
-
-##### Utility to search manpath for a given command #####
-
-sub findPage
-{
- $request = $_[0];
- $request =~ s,^/,,;
- @multipleMatches = ();
-
- $file = $_[0];
- return $file if (-f $file || -f "$file.gz" || -f "$file.bz2");
-
- # Search the path for the requested man page, which may be of the form:
- # "/usr/man/man1/ls.1", "ls.1" or "ls".
- ($page,$sect) = ($request =~ m/^(.+)\.([^.]+)$/);
- $sect = "\L$sect";
-
- # Search the specified section first (if specified)
- if ($sect)
- {
- foreach $md (@manpath)
- {
- $dir = $md;
- $file = "$dir/man$sect/$page.$sect";
- push(@multipleMatches, $file) if (-f $file || -f "$file.gz" || -f "$file.bz2");
- }
- }
- else
- {
- $page = $request;
- }
- if (@multipleMatches == 1)
- {
- return pop @multipleMatches;
- }
-
- # If not found need to search through each directory
- loadManDirs();
- foreach $dir (@mandirs)
- {
- ($s) = ($dir =~ m/man([0-9A-Za-z]+)$/);
- $file = "$dir/$page.$s";
- push(@multipleMatches, $file) if (-f $file || -f "$file.gz" || -f "$file.bz2");
- $file = "$dir/$request";
- push(@multipleMatches, $file) if (-f $file || -f "$file.gz" || -f "$file.bz2");
- if ($sect && "$page.$sect" ne $request)
- {
- $file = "$dir/$page.$sect";
- push(@multipleMatches, $file) if (-f $file || -f "$file.gz" || -f "$file.bz2");
- }
- }
- if (@multipleMatches == 1)
- {
- return pop @multipleMatches;
- }
- if (@multipleMatches > 1)
- {
- return "";
- }
- # Ok, didn't find it using section numbers. Perhaps there's a page with the
- # right name but wrong section number lurking there somewhere. (This search is slow)
- # eg. page.1x in man1 (not man1x) directory
- foreach $dir (@mandirs)
- {
- opendir(DIR, $dir);
- foreach $f (readdir DIR)
- {
- if ($f =~ m/^$page\./)
- {
- $f =~ s/\.(gz|bz2)$//;
- push(@multipleMatches, "$dir/$f");
- }
- }
- }
- if (@multipleMatches == 1)
- {
- return pop @multipleMatches;
- }
- return "";
-}
-
-sub loadPerlPages
-{
- my ($dir,$f,$name,@files);
- loadManDirs();
- return if (%perlPages);
- foreach $dir (@mandirs)
- {
- if (opendir(DIR, $dir))
- {
- @files = sort readdir DIR;
- foreach $f (@files)
- {
- next if ($f eq "." || $f eq ".." || $f !~ m/\./);
- next unless ("$dir/$f" =~ m/perl/);
- $f =~ s/\.(gz|bz2)$//;
- ($name) = ($f =~ m,(.+)\.[^.]*$,);
- $perlPages{$name} = "$dir/$f";
- }
- closedir DIR;
- }
- }
- delete $perlPages{'perl'}; # too ubiquitous to be useful
-}
-
-sub fmtTime
-{
- my $time = $_[0];
- my @days = qw (Sun Mon Tue Wed Thu Fri Sat);
- my @months = qw (Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$istdst) = localtime($time);
- return sprintf ("%s, %02d %s %4d %02d:%02d:%02d GMT",
- $days[$wday],$mday,$months[$mon],1900+$year,$hour,$min,$sec);
-}
-