tcsh.man2html revision 83098
183098Smp: # -*- perl -*- 283098Smp# $Id: tcsh.man2html,v 1.12 2001/04/28 05:20:42 kim Exp $ 359243Sobrien 459243Sobrien# tcsh.man2html, Dave Schweisguth <dcs@proton.chem.yale.edu> 559243Sobrien# 659243Sobrien# Notes: 759243Sobrien# 859243Sobrien# Always puts all files in the directory tcsh.html, creating it if necessary. 959243Sobrien# tcsh.html/top.html is the entry point, and tcsh.html/index.html is a symlink 1059243Sobrien# to tcsh.html/top.html so one needn't specify a file at all if working through 1159243Sobrien# a typically configured server. 1259243Sobrien# 1359243Sobrien# Designed for tcsh manpage. Guaranteed not to work on manpages not written 1459243Sobrien# in the exact same style of nroff -man, i.e. any other manpage. 1559243Sobrien# 1659243Sobrien# Makes links FROM items which are both a) in particular sections (see 1759243Sobrien# Configuration) and b) marked with .B or .I. Makes links TO items which 1859243Sobrien# are marked with \fB ... \fR or \fI ... \fR. 1959243Sobrien# 2059243Sobrien# Designed with X Mosaic in mind and tested lightly with lynx. I've punted on 2159243Sobrien# HTML's lack of a .PD equivalent and lynx's different <menu> handling. 2259243Sobrien 2359243Sobrien# Emulate #!/usr/local/bin/perl on systems without #! 2459243Sobrien 2561515Sobrieneval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 2661515Sobrien& eval 'exec perl -S $0 $argv:q' if 0; 2759243Sobrien 2859243Sobrien### Constants 2959243Sobrien 3059243Sobrien# Setup 3159243Sobrien 3259243Sobrien($whatami = $0) =~ s|.*/||; # `basename $0` 3359243Sobrien$isatty = -t STDIN; 3459243Sobrien 3559243Sobrien# Configuration 3659243Sobrien 3759243Sobrien$index = 0; # Don't make a searchable index CGI script 3859243Sobrien$cgibin = 0; # Look for $cgifile in $dir, not $cgibindir 3959243Sobrien$shortfiles = 0; # Use long filenames 4059243Sobrien$single = 0; # Make single page instead of top and sections 4159243Sobrien 4259243Sobrien$host = ''; # host:port part of server URL *** 4359243Sobrien$updir = ''; # Directories between $host and $dir *** 4459243Sobrien$dir = 'tcsh'; # Directory in which to put the pieces * 4559243Sobrien$cgifile = 'tcsh.cgi'; # CGI script name ** 4659243Sobrien$cgibindir = 'cgi-bin'; # CGI directory *** 4759243Sobrien$headerfile = 'header'; # HTML file for initial comments * 4859243Sobrien$indexfile = 'index'; # Symlink to $topfile * 4959243Sobrien$listsfile = 'lists'; # Mailing list description HTML file * 5059243Sobrien$outfile = 'tcsh.man'; # Default input file and copy of input file 5159243Sobrien$script = $whatami; # Copy of script; filename length must be OK 5259243Sobrien$topfile = 'top'; # Top-level HTML file * 5359243Sobrien 5459243Sobrien# * .htm or .html suffix added later 5559243Sobrien# ** Only used with -i or -c 5659243Sobrien# *** Only used with -c 5759243Sobrien 5859243Sobrien# Sections to inline in the top page 5959243Sobrien 6059243Sobrien%inline_me = ('NAME', 1, 6159243Sobrien 'SYNOPSIS', 1); 6259243Sobrien 6359243Sobrien# Sections in which to put name anchors and the font in which to look for 6459243Sobrien# links to those anchors 6559243Sobrien 6659243Sobrien%link_me = ('Editor commands', 'I', 6759243Sobrien 'Builtin commands', 'I', 6859243Sobrien 'Special aliases', 'I', 6959243Sobrien 'Special shell variables', 'B', 7059243Sobrien 'ENVIRONMENT', 'B', 7159243Sobrien 'FILES', 'I'); 7259243Sobrien 7359243Sobrien### Arguments and error-checking 7459243Sobrien 7559243Sobrien# Parse args 7659243Sobrien 7759243Sobrienwhile ($#ARGV > -1 && (($first, $rest) = ($ARGV[0] =~ /^-(.)(.*)/))) { 7859243Sobrien # Perl 5 lossage alert 7959243Sobrien if ($first =~ /[CdDGh]/) { # Switches with arguments 8059243Sobrien shift; 8159243Sobrien $arg = $rest ne '' ? $rest : $ARGV[0] ne '' ? shift : 8259243Sobrien &usage("$whatami: -$first requires an argument.\n"); 8359243Sobrien } elsif ($rest ne '') { 8459243Sobrien $ARGV[0] = "-$rest"; 8559243Sobrien } else { 8659243Sobrien shift; 8759243Sobrien } 8859243Sobrien if ($first eq '1') { $single = 1; } 8959243Sobrien elsif ($first eq 'c') { $cgibin = 1; } 9059243Sobrien elsif ($first eq 'C') { $cgibindir = $arg; } 9159243Sobrien elsif ($first eq 'd') { $updir = $arg; } 9259243Sobrien elsif ($first eq 'D') { $dir = $arg; } 9359243Sobrien elsif ($first eq 'G') { $cgifile = $arg; } 9459243Sobrien elsif ($first eq 'h') { $host = $arg; } 9559243Sobrien elsif ($first eq 'i') { $index = 1; } 9659243Sobrien elsif ($first eq 's') { $shortfiles = 1; } 9759243Sobrien elsif ($first eq 'u') { &usage(0); } 9859243Sobrien else { &usage("$whatami: -$first is not an option.\n"); } 9959243Sobrien} 10059243Sobrien 10159243Sobrienif (@ARGV == 0) { 10259243Sobrien if ($isatty) { 10359243Sobrien $infile = $outfile; # Default input file if interactive 10459243Sobrien } else { 10559243Sobrien $infile = 'STDIN'; # Read STDIN if no args and not a tty 10659243Sobrien } 10759243Sobrien} elsif (@ARGV == 1) { 10859243Sobrien $infile = $ARGV[0]; 10959243Sobrien} else { 11059243Sobrien &usage("$whatami: Please specify one and only one file.\n"); 11159243Sobrien} 11259243Sobrien 11359243Sobrien$index = $index || $cgibin; # $index is true if $cgibin is true 11459243Sobrien 11559243Sobrienif ($cgibin && ! $host) { 11659243Sobrien die "$whatami: Must specify host with -h if using -c.\n"; 11759243Sobrien} 11859243Sobrien 11959243Sobrien# Decide on HTML suffix and append it to filenames 12059243Sobrien 12159243Sobrien$html = $shortfiles ? 'htm' : 'html'; # Max 3-character extension 12259243Sobrien$dir .= ".$html"; # Directory in which to put the pieces 12359243Sobrien$headerfile .= ".$html"; # HTML file for initial comments 12459243Sobrien$topfile .= ".$html"; # Top-level HTML file (or moved notice) 12559243Sobrien$indexfile .= ".$html"; # Symlink to $topfile 12659243Sobrien$listsfile .= ".$html"; # Mailing list description HTML file 12759243Sobrien 12859243Sobrien# Check for input file 12959243Sobrien 13059243Sobrienunless ($infile eq 'STDIN') { 13159243Sobrien die "$whatami: $infile doesn't exist!\n" unless -e $infile; 13259243Sobrien die "$whatami: $infile is unreadable!\n" unless -r _; 13359243Sobrien die "$whatami: $infile is empty!\n" unless -s _; 13459243Sobrien} 13559243Sobrien 13659243Sobrien# Check for output directory and create if necessary 13759243Sobrien 13859243Sobrienif (-e $dir) { 13959243Sobrien -d _ || die "$whatami: $dir is not a directory!\n"; 14059243Sobrien -r _ && -w _ && -x _ || die "$whatami: $dir is inaccessible!\n" 14159243Sobrien} else { 14259243Sobrien mkdir($dir, 0755) || die "$whatami: Can't create $dir!\n"; 14359243Sobrien} 14459243Sobrien 14559243Sobrien# Slurp manpage 14659243Sobrien 14759243Sobrienif ($infile eq 'STDIN') { 14859243Sobrien @man = <STDIN>; 14959243Sobrien} else { 15059243Sobrien open(MAN, $infile) || die "$whatami: Error opening $infile!\n"; 15159243Sobrien @man = <MAN>; 15259243Sobrien close MAN; 15359243Sobrien} 15459243Sobrien 15559243Sobrien# Print manpage to HTML directory (can't use cp if we're reading from STDIN) 15659243Sobrien 15759243Sobrienopen(MAN, ">$dir/$outfile") || die "$whatami: Can't open $dir/$outfile!\n"; 15859243Sobrienprint MAN @man; 15959243Sobrienclose MAN; 16059243Sobrien 16159243Sobrien# Copy script to HTML directory 16259243Sobrien 16359243Sobrien(system("cp $0 $dir") >> 8) && die "$whatami: Can't copy $0 to $dir!\n"; 16459243Sobrien 16559243Sobrien# Link top.html to index.html in case someone looks at tcsh.html/ 16659243Sobrien 16759243Sobriensystem("rm -f $dir/$indexfile"); # Some systems can't ln -sf 16859243Sobrien(system("ln -s $topfile $dir/$indexfile") >> 8) 16959243Sobrien && die "$whatami: Can't link $topfile to $dir/$indexfile!\n"; 17059243Sobrien 17159243Sobrien### Get title and section headings 17259243Sobrien 17359243Sobrien$comment = 0; # 0 for text, 1 for ignored text 17459243Sobrien@sectionlines = (0); # First line of section 17559243Sobrien@sectiontypes = (0); # H or S 17659243Sobrien@sectiontexts = ('Header'); # Text of section heading 17759243Sobrien@sectionfiles = ($headerfile); # Filename in which to store section 17859243Sobrien%name = (); # Array of name anchors 17959243Sobrien@name = () if $index; # Ordered array of name anchors 18059243Sobrien$font = ''; # '' to not make names, 'B' or 'I' to do so 18159243Sobrien 18259243Sobrien$line = 0; 18359243Sobrienforeach (@man) { 18459243Sobrien if (/^\.ig/) { # Start ignoring 18559243Sobrien $comment = 1; 18659243Sobrien } elsif (/^\.\./) { # Stop ignoring 18759243Sobrien $comment = 0; 18859243Sobrien } elsif (! $comment) { # Not in .ig'ed section; do stuff 18959243Sobrien 19059243Sobrien # nroff special characters 19159243Sobrien 19259243Sobrien s/\\-/-/g; # \- 19359243Sobrien s/\\^//g; # \^ 19459243Sobrien s/^\\'/'/; # leading ' escape 19559243Sobrien s/^\\(\s)/$1/; # leading space escape 19659243Sobrien s/\\(e|\\)/\\/g; # \e, \\; must do this after other escapes 19759243Sobrien 19859243Sobrien # HTML special characters; deal with these before adding more 19959243Sobrien 20059243Sobrien s/&/&\;/g; 20159243Sobrien s/>/>\;/g; 20259243Sobrien s/</<\;/g; 20359243Sobrien 20459243Sobrien # Get title 20559243Sobrien 20659243Sobrien if (/^\.TH\s+(\w+)\s+(\w+)\s+\"([^\"]*)\"\s+\"([^\"]*)\"/) { 20759243Sobrien $title = "$1($2) $4 ($3) $1($2)"; 20859243Sobrien } 20959243Sobrien 21059243Sobrien # Build per-section info arrays 21159243Sobrien 21259243Sobrien if (($type, $text) = /^\.S([HS])\s+\"?([^\"]*)\"?/) { 21359243Sobrien 21459243Sobrien push(@sectionlines, $line); # Index of first line of section 21559243Sobrien push(@sectiontypes, $type eq 'H' ? 0 : 1); # Type of section 21659243Sobrien $text =~ s/\s*$//; # Remove trailing whitespace 21759243Sobrien push(@sectiontexts, $text); # Title of section (key for href) 21859243Sobrien $text =~ s/\s*\(\+\)$//; # Remove (+) 21959243Sobrien if ($shortfiles) { 22059243Sobrien $file = $#sectionlines; # Short filenames; use number 22159243Sobrien } else { 22259243Sobrien $file = $text; # Long filenames; use title 22359243Sobrien $file =~ s/[\s\/]+/_/g; # Replace whitespace and / with _ 22459243Sobrien } 22559243Sobrien $file .= ".$html" unless $single; 22659243Sobrien push(@sectionfiles, $file); # File in which to store section 22759243Sobrien $name{"$text B"} = ($single ? '#' : '') . $file; 22859243Sobrien # Index entry for &make_hrefs 22959243Sobrien push(@name, "$text\t" . $name{"$text B"}) if $index; 23059243Sobrien # Index entry for CGI script 23159243Sobrien # Look for anchors in the rest of this section if $link_me{$text} 23259243Sobrien # is non-null, and mark them with the font which is its value 23359243Sobrien 23459243Sobrien $font = $link_me{$text}; 23559243Sobrien } 23659243Sobrien &make_name(*name, *font, *file, *index, *_) if $font; 23759243Sobrien } 23859243Sobrien $line++; 23959243Sobrien} 24059243Sobrien 24159243Sobrien### Make top page 24259243Sobrien 24359243Sobrienopen(TOP, ">$dir/$topfile"); 24459243Sobrienselect TOP; 24559243Sobrien 24659243Sobrien# Top page header 24759243Sobrien 24859243Sobrienprint <<EOP; 24959243Sobrien<HEAD> 25059243Sobrien<TITLE>$title</TITLE> 25159243Sobrien</HEAD> 25259243Sobrien<BODY> 25359243Sobrien<A NAME="top"></A> 25459243Sobrien<H1>$title</H1> 25559243Sobrien<HR> 25659243SobrienEOP 25759243Sobrien 25859243Sobrien# FORM block, if we're making an index 25959243Sobrien 26059243Sobrien$action = $cgibin ? "http://$host/$cgibindir/$cgifile" : $cgifile; 26159243Sobrien 26259243Sobrienprint <<EOP if $index; 26359243Sobrien<FORM METHOD="GET" ACTION="$action"> 26459243SobrienGo directly to a section, command or variable: <INPUT NAME="input"> 26559243Sobrien</FORM> 26659243SobrienEOP 26759243Sobrien 26859243Sobrien# Table of contents 26959243Sobrien 27059243Sobrienprint <<EOP; 27159243Sobrien<H2> 27259243SobrienEOP 27359243Sobrien 27459243Sobrienforeach $section (1 .. $#sectionlines) { 27559243Sobrien if ($sectiontypes[$section - 1] < $sectiontypes[$section]) { 27659243Sobrien print "</H2> <menu>\n"; # Indent, smaller font 27759243Sobrien } elsif ($sectiontypes[$section - 1] > $sectiontypes[$section]) { 27859243Sobrien print "</menu> <H2>\n"; # Outdent, larger font 27959243Sobrien } 28059243Sobrien if ($inline_me{$sectiontexts[$section]}) { # Section is in %inline_me 28159243Sobrien 28259243Sobrien # Print section inline 28359243Sobrien 28459243Sobrien print "$sectiontexts[$section]\n"; 28559243Sobrien print "</H2> <menu>\n"; # Indent, smaller font 28659243Sobrien &printsectionbody(*man, *sectionlines, *section, *name); 28759243Sobrien print "</menu> <H2>\n"; # Outdent, larger font 28859243Sobrien } else { 28959243Sobrien 29059243Sobrien # Print link to section 29159243Sobrien 29259243Sobrien print "<A HREF=\"", $single ? '#' : '', 29359243Sobrien "$sectionfiles[$section]\">$sectiontexts[$section]</A><BR>\n"; 29459243Sobrien } 29559243Sobrien} 29659243Sobrien 29759243Sobrienprint <<EOP; 29859243Sobrien</H2> 29959243SobrienEOP 30059243Sobrien 30159243Sobrienprint "<HR>\n" if $single; 30259243Sobrien 30359243Sobrien### Make sections 30459243Sobrien 30559243Sobrienforeach $section (0 .. $#sectionlines) { 30659243Sobrien 30759243Sobrien # Skip inlined sections 30859243Sobrien 30959243Sobrien next if $inline_me{$sectiontexts[$section]}; 31059243Sobrien 31159243Sobrien if ($single) { 31259243Sobrien 31359243Sobrien # Header 31459243Sobrien 31559243Sobrien print <<EOP if $section; # Skip header section 31659243Sobrien<H2><A NAME="$sectionfiles[$section]">$sectiontexts[$section]</A></H2> 31759243Sobrien<menu> 31859243SobrienEOP 31959243Sobrien &printsectionbody(*man, *sectionlines, *section, *name); 32059243Sobrien print <<EOP if $section; # Skip header section 32159243Sobrien<A HREF="#top">Table of Contents</A> 32259243Sobrien</menu> 32359243SobrienEOP 32459243Sobrien 32559243Sobrien } else { 32659243Sobrien 32759243Sobrien # Make pointer line for header and trailer 32859243Sobrien 32959243Sobrien $pointers = "<A HREF=\"$topfile\">Up</A>"; 33059243Sobrien $pointers .= "\n<A HREF=\"$sectionfiles[$section + 1]\">Next</A>" 33159243Sobrien if ($section < $#sectionlines) && 33259243Sobrien ! $inline_me{$sectiontexts[$section + 1]}; 33359243Sobrien $pointers .= "\n<A HREF=\"$sectionfiles[$section - 1]\">Previous</A>" 33459243Sobrien if ($section > 1) && # section 0 is initial comments 33559243Sobrien ! $inline_me{$sectiontexts[$section - 1]}; 33659243Sobrien 33759243Sobrien # Header 33859243Sobrien 33959243Sobrien open(OUT, ">$dir/$sectionfiles[$section]"); 34059243Sobrien select OUT; 34159243Sobrien print <<EOP; 34259243Sobrien<HEAD> 34359243Sobrien<TITLE>$sectiontexts[$section]</TITLE> 34459243Sobrien</HEAD> 34559243Sobrien<BODY> 34659243Sobrien$pointers 34759243Sobrien<H2>$sectiontexts[$section]</H2> 34859243SobrienEOP 34959243Sobrien &printsectionbody(*man, *sectionlines, *section, *name); 35059243Sobrien 35159243Sobrien # Trailer 35259243Sobrien 35359243Sobrien print <<EOP; 35459243Sobrien$pointers 35559243Sobrien</BODY> 35659243SobrienEOP 35759243Sobrien 35859243Sobrien } 35959243Sobrien} 36059243Sobrien 36159243Sobrienselect TOP unless $single; 36259243Sobrien 36359243Sobrien# Top page trailer 36459243Sobrien 36559243Sobrienprint <<EOP; 36659243Sobrien</H2> 36759243Sobrien<HR> 36859243SobrienHere are the <A HREF="$outfile">nroff manpage</A> (175K) 36959243Sobrienfrom which this HTML version was generated, 37059243Sobrienthe <A HREF="$script">Perl script</A> which did the conversion 37161515Sobrienand the <A HREF="ftp://ftp.astron.com/pub/tcsh/"> 37259243Sobriencomplete source code</A> for <I>tcsh</I>. 37359243Sobrien<HR> 37459243Sobrien<I>tcsh</I> is maintained by 37559243SobrienChristos Zoulas <A HREF="mailto:christos\@gw.com"><christos\@gw.com></A> 37659243Sobrienand the <A HREF="$listsfile"><I>tcsh</I> maintainers' mailing list</A>. 37759243SobrienDave Schweisguth <A HREF="mailto:dcs\@proton.chem.yale.edu"><dcs\@proton.chem.yale.edu></A> 37859243Sobrienwrote the manpage and the HTML conversion script. 37959243Sobrien</BODY> 38059243SobrienEOP 38159243Sobrien 38259243Sobrienclose TOP; 38359243Sobrien 38459243Sobrien### Make lists page 38559243Sobrien 38659243Sobrienopen(LISTS, ">$dir/$listsfile"); 38759243Sobrienselect LISTS; 38859243Sobrienwhile(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 38959243Sobrien s/TOPFILEHERE/$topfile/; 39059243Sobrien print; 39159243Sobrien} 39259243Sobrienclose LISTS; 39359243Sobrien 39459243Sobrien### Make search script 39559243Sobrien 39659243Sobrienif ($index) { 39759243Sobrien 39859243Sobrien # URL of $dir; see comments in search script 39959243Sobrien 40059243Sobrien $root = $cgibin 40159243Sobrien ? "'http://$host/" . ($updir ? "$updir/" : '') . "$dir/'" 40259243Sobrien : '"http://$ENV{\'SERVER_NAME\'}:$ENV{\'SERVER_PORT\'}" . (($_ = $ENV{\'SCRIPT_NAME\'}) =~ s|[^/]*$||, $_)'; 40359243Sobrien 40459243Sobrien # String for passing @name to search script 40559243Sobrien 40659243Sobrien $name = join("',\n'", @name); 40759243Sobrien 40859243Sobrien open(TOP, ">$dir/$cgifile"); 40959243Sobrien select TOP; 41059243Sobrien while(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 41159243Sobrien s/ROOTHERE/$root/; 41259243Sobrien s/NAMEHERE/$name/; 41359243Sobrien s/TOPFILEHERE/$topfile/; 41459243Sobrien print; 41559243Sobrien } 41659243Sobrien close TOP; 41759243Sobrien chmod(0755, "$dir/$cgifile") || 41859243Sobrien die "$whatami: Can't chmod 0755 $dir/$cgifile!\n"; 41959243Sobrien warn "$whatami: Don't forget to move $dir/$cgifile to /$cgibindir.\n" 42059243Sobrien if $cgibin; 42159243Sobrien} 42259243Sobrien 42359243Sobrien### That's all, folks 42459243Sobrien 42559243Sobrienexit; 42659243Sobrien 42759243Sobrien### Subroutines 42859243Sobrien 42959243Sobrien# Process and print the body of a section 43059243Sobrien 43159243Sobriensub printsectionbody { 43259243Sobrien 43359243Sobrien local(*man, *sectionlines, *sline, *name) = @_; # Number of section 43459243Sobrien local($sfirst, $slast, @paralines, @paratypes, $comment, $dl, $pline, 43559243Sobrien $comment, $pfirst, $plast, @para, @tag, $changeindent); 43659243Sobrien 43759243Sobrien # Define section boundaries 43859243Sobrien 43959243Sobrien $sfirst = $sectionlines[$sline] + 1; 44059243Sobrien if ($sline == $#sectionlines) { 44159243Sobrien $slast = $#man; 44259243Sobrien } else { 44359243Sobrien $slast = $sectionlines[$sline + 1] - 1; 44459243Sobrien } 44559243Sobrien 44659243Sobrien # Find paragraph markers, ignoring those between '.ig' and '..' 44759243Sobrien 44859243Sobrien if ($man[$sfirst] =~ /^\.[PIT]P/) { 44959243Sobrien @paralines = (); 45059243Sobrien @paratypes = (); 45159243Sobrien } else { 45259243Sobrien @paralines = ($sfirst - 1); # .P follows .S[HS] by default 45359243Sobrien @paratypes = ('P'); 45459243Sobrien } 45559243Sobrien $comment = 0; 45659243Sobrien foreach ($sfirst .. $slast) { 45759243Sobrien if ($man[$_] =~ /^\.ig/) { # Start ignoring 45859243Sobrien $comment = 1; 45959243Sobrien } elsif ($man[$_] =~ /^\.\./) { # Stop ignoring 46059243Sobrien $comment = 0; 46159243Sobrien } elsif (! $comment && $man[$_] =~ /^\.([PIT])P/) { 46259243Sobrien push(@paralines, $_); 46359243Sobrien push(@paratypes, $1); 46459243Sobrien } 46559243Sobrien } 46659243Sobrien 46759243Sobrien # Process paragraphs 46859243Sobrien 46959243Sobrien $changeindent = 0; 47059243Sobrien $dl = 0; 47159243Sobrien foreach $pline (0 .. $#paralines) { 47259243Sobrien 47359243Sobrien @para = (); 47459243Sobrien $comment = 0; 47559243Sobrien 47659243Sobrien # Define para boundaries 47759243Sobrien 47859243Sobrien $pfirst = $paralines[$pline] + 1; 47959243Sobrien if ($pline == $#paralines) { 48059243Sobrien $plast = $slast; 48159243Sobrien } else { 48259243Sobrien $plast = $paralines[$pline + 1] - 1; 48359243Sobrien } 48459243Sobrien 48559243Sobrien foreach (@man[$pfirst .. $plast]) { 48659243Sobrien if (/^\.ig/) { # nroff begin ignore 48759243Sobrien if ($comment == 0) { 48859243Sobrien $comment = 2; 48959243Sobrien push(@para, "<!--\n"); 49059243Sobrien } elsif ($comment == 1) { 49159243Sobrien $comment = 2; 49259243Sobrien } elsif ($comment == 2) { 49359243Sobrien s/--/-/g; # Remove double-dashes in comments 49459243Sobrien push(@para, $_); 49559243Sobrien } 49659243Sobrien } elsif (/^\.\./) { # nroff end ignore 49759243Sobrien if ($comment == 0) { 49859243Sobrien ; 49959243Sobrien } elsif ($comment == 1) { 50059243Sobrien ; 50159243Sobrien } elsif ($comment == 2) { 50259243Sobrien $comment = 1; 50359243Sobrien } 50459243Sobrien } elsif (/^\.\\\"/) { # nroff comment 50559243Sobrien if ($comment == 0) { 50659243Sobrien $comment = 1; 50759243Sobrien push(@para, "<!--\n"); 50859243Sobrien s/^\.\\\"//; 50959243Sobrien } elsif ($comment == 1) { 51059243Sobrien s/^\.\\\"//; 51159243Sobrien } elsif ($comment == 2) { 51259243Sobrien ; 51359243Sobrien } 51459243Sobrien s/--/-/g; # Remove double-dashes in comments 51559243Sobrien push(@para, $_); 51659243Sobrien } else { # Nothing to do with comments 51759243Sobrien if ($comment == 0) { 51859243Sobrien ; 51959243Sobrien } elsif ($comment == 1) { 52059243Sobrien $comment = 0; 52159243Sobrien push(@para, "-->\n"); 52259243Sobrien } elsif ($comment == 2) { 52359243Sobrien s/--/-/g; # Remove double-dashes in comments 52459243Sobrien } 52559243Sobrien 52659243Sobrien unless ($comment) { 52759243Sobrien 52859243Sobrien if (/^\.TH/) { # Title; got this already 52959243Sobrien next; 53059243Sobrien } elsif (/^\.PD/) { # Para spacing; unimplemented 53159243Sobrien next; 53259243Sobrien } elsif (/^\.RS/) { # Indent (one width only) 53359243Sobrien $changeindent++; 53459243Sobrien next; 53559243Sobrien } elsif (/^\.RE/) { # Outdent 53659243Sobrien $changeindent--; 53759243Sobrien next; 53859243Sobrien } 53959243Sobrien 54059243Sobrien # Line break 54159243Sobrien s/^\.br.*/<BR>/; 54259243Sobrien 54359243Sobrien # More nroff special characters 54459243Sobrien 54559243Sobrien s/^\\&\;//; # leading dot escape; save until 54659243Sobrien # now so leading dots aren't 54759243Sobrien # confused with ends of .igs 54859243Sobrien 54959243Sobrien &make_hrefs(*name, *_); 55059243Sobrien } 55159243Sobrien push(@para, $_); 55259243Sobrien } 55359243Sobrien } 55459243Sobrien 55559243Sobrien push(@para, "-->\n") if $comment; # Close open comment 55659243Sobrien 55759243Sobrien # Print paragraph 55859243Sobrien 55959243Sobrien if ($paratypes[$pline] eq 'P') { 56059243Sobrien &font(*para); 56159243Sobrien print @para; 56259243Sobrien } elsif ($paratypes[$pline] eq 'I') { 56359243Sobrien &font(*para); 56459243Sobrien print "<menu>\n", 56559243Sobrien @para, 56659243Sobrien "</menu>\n"; 56759243Sobrien } else { # T 56859243Sobrien @tag = shift(@para); 56959243Sobrien &font(*tag); 57059243Sobrien &font(*para); 57159243Sobrien print "<DL compact>\n" unless $dl; 57259243Sobrien print "<DT>\n", 57359243Sobrien @tag, 57459243Sobrien "<DD>\n", 57559243Sobrien @para; 57659243Sobrien if ($pline == $#paratypes || $paratypes[$pline + 1] ne 'T') { 57759243Sobrien # Perl 5 lossage alert 57859243Sobrien # Next para is not a definition list 57959243Sobrien $dl = 0; # Close open definition list 58059243Sobrien print "</DL>\n"; 58159243Sobrien } else { 58259243Sobrien $dl = 1; # Leave definition list open 58359243Sobrien } 58459243Sobrien } 58559243Sobrien print "<P>\n"; 58659243Sobrien 58759243Sobrien # Indent/outdent the *next* para 58859243Sobrien 58959243Sobrien while ($changeindent > 0) { 59059243Sobrien print "<menu>\n"; 59159243Sobrien $changeindent--; 59259243Sobrien } 59359243Sobrien while ($changeindent < 0) { 59459243Sobrien print "</menu>\n"; 59559243Sobrien $changeindent++; 59659243Sobrien } 59759243Sobrien } 59859243Sobrien 1; 59959243Sobrien} 60059243Sobrien 60159243Sobrien# Make one name anchor in a line; cue on fonts (.B or .I) but leave them alone 60259243Sobrien 60359243Sobriensub make_name { 60459243Sobrien 60559243Sobrien local(*name, *font, *file, *index, *line) = @_; 60659243Sobrien local($text); 60759243Sobrien 60859243Sobrien if (($text) = ($line =~ /^\.[BI]\s+([^\s\\]+)/)) { # Found pattern 60959243Sobrien 61059243Sobrien if ( 61159243Sobrien $text !~ /^-/ # Avoid lists of options 61259243Sobrien && (length($text) > 1 # and history escapes 61359243Sobrien || $text =~ /^[%:@]$/) # Special pleading for %, :, @ 61459243Sobrien && ! $name{"$text $font"} # Skip if there's one already 61559243Sobrien ) { 61659243Sobrien # Record link 61759243Sobrien 61859243Sobrien $name{"$text $font"} = ($single ? '' : $file) . "#$text"; 61959243Sobrien push(@name, "$text\t" . $name{"$text $font"}) if $index; 62059243Sobrien 62159243Sobrien # Put in the name anchor 62259243Sobrien 62359243Sobrien $line =~ s/^(\.[BI]\s+)([^\s\\]+)/$1<A NAME=\"$text\">$2<\/A>/; 62459243Sobrien } 62559243Sobrien } 62659243Sobrien $line; 62759243Sobrien} 62859243Sobrien 62959243Sobrien# Make all the href anchors in a line; cue on fonts (\fB ... \fR or 63059243Sobrien# \fI ... \fR) but leave them alone 63159243Sobrien 63259243Sobriensub make_hrefs { 63359243Sobrien 63459243Sobrien local(*name, *line) = @_; 63559243Sobrien local(@pieces, $piece); 63659243Sobrien 63759243Sobrien @pieces = split(/(\\f[BI][^\\]*\\fR)/, $line); 63859243Sobrien 63959243Sobrien $piece = 0; 64059243Sobrien foreach (@pieces) { 64159243Sobrien if (/\\f([BI])([^\\]*)\\fR/ # Found a possibility 64259243Sobrien 64359243Sobrien # It's not followed by (, i.e. it's not a manpage reference 64459243Sobrien 64559243Sobrien && substr($pieces[$piece + 1], 0, 1) ne '(') { 64659243Sobrien $key = "$2 $1"; 64759243Sobrien if ($name{$key}) { # If there's a matching name 64859243Sobrien s/(\\f[BI])([^\\]*)(\\fR)/$1<A HREF=\"$name{$key}\">$2<\/A>$3/; 64959243Sobrien } 65059243Sobrien } 65159243Sobrien $piece++; 65259243Sobrien } 65359243Sobrien $line = join('', @pieces); 65459243Sobrien} 65559243Sobrien 65659243Sobrien# Convert nroff font escapes to HTML 65759243Sobrien# Expects comments and breaks to be in HTML form already 65859243Sobrien 65959243Sobriensub font { 66059243Sobrien 66159243Sobrien local(*para) = @_; 66259243Sobrien local($i, $j, @begin, @end, $part, @pieces, $bold, $italic); 66359243Sobrien 66459243Sobrien return 0 if $#para == -1; # Ignore empty paragraphs 66559243Sobrien # Perl 5 lossage alert 66659243Sobrien 66759243Sobrien # Find beginning and end of each part between HTML comments 66859243Sobrien 66959243Sobrien $i = 0; 67059243Sobrien @begin = (); 67159243Sobrien @end = (); 67259243Sobrien foreach (@para) { 67359243Sobrien push(@begin, $i + 1) if /^-->/ || /^<BR>/; 67459243Sobrien push(@end, $i - 1) if /^<!--/ || /^<BR>/; 67559243Sobrien $i++; 67659243Sobrien } 67759243Sobrien if ($para[0] =~ /^<!--/ || $para[0] =~ /^<BR>/) { 67859243Sobrien shift(@end); 67959243Sobrien } else { 68059243Sobrien unshift(@begin, 0); # Begin at the beginning 68159243Sobrien } 68259243Sobrien if ($para[$#para] =~ /^-->/ || $para[$#para] =~ /^<BR>/) { 68359243Sobrien pop(@begin); 68459243Sobrien } else { 68559243Sobrien push(@end, $#para); # End at the end 68659243Sobrien } 68759243Sobrien 68859243Sobrien # Fontify each part 68959243Sobrien 69059243Sobrien $bold = $italic = 0; 69159243Sobrien foreach $i (0 .. $#begin) { 69259243Sobrien $* = 1; 69359243Sobrien $part = join('', @para[$begin[$i] .. $end[$i]]); 69459243Sobrien $part =~ s/^\.([BI])\s+(.*)$/\\f$1$2\\fR/g; # .B, .I 69559243Sobrien @pieces = split(/(\\f[BIR])/, $part); 69659243Sobrien $part = ''; 69759243Sobrien foreach $j (@pieces) { 69859243Sobrien if ($j eq '\fB') { 69959243Sobrien if ($italic) { 70059243Sobrien $italic = 0; 70159243Sobrien $part .= '</I>'; 70259243Sobrien } 70359243Sobrien unless ($bold) { 70459243Sobrien $bold = 1; 70559243Sobrien $part .= '<B>'; 70659243Sobrien } 70759243Sobrien } elsif ($j eq '\fI') { 70859243Sobrien if ($bold) { 70959243Sobrien $bold = 0; 71059243Sobrien $part .= '</B>'; 71159243Sobrien } 71259243Sobrien unless ($italic) { 71359243Sobrien $italic = 1; 71459243Sobrien $part .= '<I>'; 71559243Sobrien } 71659243Sobrien } elsif ($j eq '\fR') { 71759243Sobrien if ($bold) { 71859243Sobrien $bold = 0; 71959243Sobrien $part .= '</B>'; 72059243Sobrien } elsif ($italic) { 72159243Sobrien $italic = 0; 72259243Sobrien $part .= '</I>'; 72359243Sobrien } 72459243Sobrien } else { 72559243Sobrien $part .= $j; 72659243Sobrien } 72759243Sobrien } 72859243Sobrien $* = 0; 72959243Sobrien 73059243Sobrien # Close bold/italic before break 73159243Sobrien 73259243Sobrien if ($end[$i] == $#para || $para[$end[$i] + 1] =~ /^<BR>/) { 73359243Sobrien # Perl 5 lossage alert 73459243Sobrien if ($bold) { 73559243Sobrien $bold = 0; 73659243Sobrien $part =~ s/(\n)?$/<\/B>$1\n/; 73759243Sobrien } elsif ($italic) { 73859243Sobrien $italic = 0; 73959243Sobrien $part =~ s/(\n)?$/<\/I>$1\n/; 74059243Sobrien } 74159243Sobrien } 74259243Sobrien 74359243Sobrien # Rebuild this section of @para 74459243Sobrien 74559243Sobrien foreach $j ($begin[$i] .. $end[$i]) { 74659243Sobrien $part =~ s/^([^\n]*(\n|$))//; 74759243Sobrien $para[$j] = $1; 74859243Sobrien } 74959243Sobrien } 75059243Sobrien 75159243Sobrien # Close bold/italic on last non-comment line 75259243Sobrien # Do this only here because fonts pass through comments 75359243Sobrien 75459243Sobrien $para[$end[$#end]] =~ s/(\n)?$/<\/B>$1/ if $bold; 75559243Sobrien $para[$end[$#end]] =~ s/(\n)?$/<\/I>$1/ if $italic; 75659243Sobrien} 75759243Sobrien 75859243Sobriensub usage { 75959243Sobrien local ($message) = $_[0]; 76059243Sobrien 76159243Sobrien warn $message if $message; 76259243Sobrien warn <<EOP; 76359243SobrienUsage: $whatami [-1icsu] [-C dir] [-d dir] [-h host] [file] 76459243SobrienWithout [file], reads from tcsh.man or stdin. 76559243Sobrien-1 Makes a single page instead of a table of contents and sections 76659243Sobrien-i Makes a CGI searchable index script, tcsh.html/tcsh.cgi, intended 76759243Sobrien for a server which respects the .cgi extension in any directory. 76859243Sobrien-c Like -i, but the CGI script is intended for a server which wants 76959243Sobrien scripts in /cgi-bin (or some other privileged directory separate 77059243Sobrien from the rest of the HTML) and must be moved there by hand. 77159243Sobrien-C dir Uses /dir instead of /cgi-bin as the CGI bin dir. 77259243Sobrien Meaningless without -c. 77359243Sobrien-d dir Uses /dir/tcsh.html instead of /tcsh.html as the HTML dir. 77459243Sobrien Meaningless without -c. 77559243Sobrien-D dir Uses /dir.html instead of /tcsh.html as the HTML dir. 77659243Sobrien Meaningless without -c. 77759243Sobrien-G name Uses name instead of tcsh.cgi as the name of the CGI script. 77859243Sobrien Meaningless without -c or -i. 77959243Sobrien-h host Uses host as the host:port part of the URL to the entry point. 78059243Sobrien Meaningless without -c. 78159243Sobrien-s Filenames are shorter (max 8 + 3) but less descriptive. 78259243Sobrien-u This message 78359243SobrienEOP 78459243Sobrien exit !! $message; 78559243Sobrien} 78659243Sobrien 78759243Sobrien### Inlined documents. Watch for *HERE tokens. 78859243Sobrien 78959243Sobrien__END__ 79059243Sobrien<HEAD> 79159243Sobrien<TITLE>The tcsh mailing lists</TITLE> 79259243Sobrien</HEAD> 79359243Sobrien<BODY> 79459243Sobrien<A HREF="TOPFILEHERE">Up</A> 79559243Sobrien<H2>The <I>tcsh</I> mailing lists</H2> 79659243SobrienThere are three <I>tcsh</I> mailing lists: 79759243Sobrien<DL> 79859243Sobrien<DT> 79959243Sobrien<I>tcsh@mx.gw.com</I> 80059243Sobrien<DD> 80159243SobrienThe <I>tcsh</I> maintainers and testers' mailing list. 80259243Sobrien<DT> 80359243Sobrien<I>tcsh-diffs@mx.gw.com</I> 80459243Sobrien<DD> 80559243SobrienThe same as <I>tcsh@mx.gw.com</I>, plus diffs for each new 80659243Sobrienpatchlevel of <I>tcsh</I>. 80759243Sobrien<DT> 80859243Sobrien<I>tcsh-bugs@mx.gw.com</I> 80959243Sobrien<DD> 81059243SobrienBug reports. 81159243Sobrien</DL> 81259243SobrienYou can subscribe to any of these lists by sending mail to 81359243Sobrien<I><A HREF="mailto:listserv@mx.gw.com">listserv@mx.gw.com</A></I> with the 81459243Sobrientext "subscribe <list name> <your name>" on a line by 81559243Sobrienitself in the body. <list name> is the name of the mailing list, 81659243Sobrienwithout "@mx.gw.com", and <your name> is your real name, not your 81759243Sobrienemail address. You can also ask the list server for help by sending 81859243Sobrienonly the word "help". 81959243Sobrien<P> 82059243Sobrien<A HREF="TOPFILEHERE">Up</A> 82159243Sobrien</BODY> 82259243SobrienEND 82383098Smp: # -*- perl -*- 82459243Sobrien 82559243Sobrien# Emulate #!/usr/local/bin/perl on systems without #! 82659243Sobrien 82761515Sobrieneval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 82861515Sobrien& eval 'exec perl -S $0 $argv:q' if 0; 82959243Sobrien 83059243Sobrien# Setup 83159243Sobrien 83259243Sobrien# Location: doesn't work with relative URLs, so we need to know where to find 83359243Sobrien# the top and section files. 83459243Sobrien# If the search engine is in /cgi-bin, we need a hard-coded URL. 83559243Sobrien# If the search engine is in the same directory, we can figure it out from CGI 83659243Sobrien# environment variables. 83759243Sobrien 83859243Sobrien$root = ROOTHERE; 83959243Sobrien$topfile = 'TOPFILEHERE'; 84059243Sobrien@name = ( 84159243Sobrien'NAMEHERE' 84259243Sobrien); 84359243Sobrien 84459243Sobrien# Do the search 84559243Sobrien 84659243Sobrien$input = $ENV{'QUERY_STRING'}; 84759243Sobrien$input =~ s/^input=//; 84859243Sobrien$input =~ s/\+/ /g; 84959243Sobrienprint "Status: 302 Found\n"; 85059243Sobrienif ($input ne '' && ($key = (grep(/^$input/, @name))[0] || 85159243Sobrien (grep(/^$input/i, @name))[0] || 85259243Sobrien (grep( /$input/i, @name))[0] )) { 85359243Sobrien $key =~ /\t([^\t]*)$/; 85459243Sobrien print "Location: $root$1\n\n"; 85559243Sobrien} else { 85659243Sobrien print "Location: $root$topfile\n\n"; 85759243Sobrien} 85859243SobrienEND 859