183098Smp: # -*- perl -*- 2232633Smp# $tcsh: tcsh.man2html,v 1.15 2011/02/05 16:15:56 christos 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 $part = join('', @para[$begin[$i] .. $end[$i]]); 693232633Smp $part =~ s/^\.([BI])\s+(.*)$/\\f$1$2\\fR/gm; # .B, .I 694232633Smp @pieces = split(/(\\f[BIR])/m, $part); 69559243Sobrien $part = ''; 69659243Sobrien foreach $j (@pieces) { 69759243Sobrien if ($j eq '\fB') { 69859243Sobrien if ($italic) { 69959243Sobrien $italic = 0; 70059243Sobrien $part .= '</I>'; 70159243Sobrien } 70259243Sobrien unless ($bold) { 70359243Sobrien $bold = 1; 70459243Sobrien $part .= '<B>'; 70559243Sobrien } 70659243Sobrien } elsif ($j eq '\fI') { 70759243Sobrien if ($bold) { 70859243Sobrien $bold = 0; 70959243Sobrien $part .= '</B>'; 71059243Sobrien } 71159243Sobrien unless ($italic) { 71259243Sobrien $italic = 1; 71359243Sobrien $part .= '<I>'; 71459243Sobrien } 71559243Sobrien } elsif ($j eq '\fR') { 71659243Sobrien if ($bold) { 71759243Sobrien $bold = 0; 71859243Sobrien $part .= '</B>'; 71959243Sobrien } elsif ($italic) { 72059243Sobrien $italic = 0; 72159243Sobrien $part .= '</I>'; 72259243Sobrien } 72359243Sobrien } else { 72459243Sobrien $part .= $j; 72559243Sobrien } 72659243Sobrien } 72759243Sobrien 72859243Sobrien # Close bold/italic before break 72959243Sobrien 73059243Sobrien if ($end[$i] == $#para || $para[$end[$i] + 1] =~ /^<BR>/) { 73159243Sobrien # Perl 5 lossage alert 73259243Sobrien if ($bold) { 73359243Sobrien $bold = 0; 73459243Sobrien $part =~ s/(\n)?$/<\/B>$1\n/; 73559243Sobrien } elsif ($italic) { 73659243Sobrien $italic = 0; 73759243Sobrien $part =~ s/(\n)?$/<\/I>$1\n/; 73859243Sobrien } 73959243Sobrien } 74059243Sobrien 74159243Sobrien # Rebuild this section of @para 74259243Sobrien 74359243Sobrien foreach $j ($begin[$i] .. $end[$i]) { 74459243Sobrien $part =~ s/^([^\n]*(\n|$))//; 74559243Sobrien $para[$j] = $1; 74659243Sobrien } 74759243Sobrien } 74859243Sobrien 74959243Sobrien # Close bold/italic on last non-comment line 75059243Sobrien # Do this only here because fonts pass through comments 75159243Sobrien 75259243Sobrien $para[$end[$#end]] =~ s/(\n)?$/<\/B>$1/ if $bold; 75359243Sobrien $para[$end[$#end]] =~ s/(\n)?$/<\/I>$1/ if $italic; 75459243Sobrien} 75559243Sobrien 75659243Sobriensub usage { 75759243Sobrien local ($message) = $_[0]; 75859243Sobrien 75959243Sobrien warn $message if $message; 76059243Sobrien warn <<EOP; 76159243SobrienUsage: $whatami [-1icsu] [-C dir] [-d dir] [-h host] [file] 76259243SobrienWithout [file], reads from tcsh.man or stdin. 76359243Sobrien-1 Makes a single page instead of a table of contents and sections 76459243Sobrien-i Makes a CGI searchable index script, tcsh.html/tcsh.cgi, intended 76559243Sobrien for a server which respects the .cgi extension in any directory. 76659243Sobrien-c Like -i, but the CGI script is intended for a server which wants 76759243Sobrien scripts in /cgi-bin (or some other privileged directory separate 76859243Sobrien from the rest of the HTML) and must be moved there by hand. 76959243Sobrien-C dir Uses /dir instead of /cgi-bin as the CGI bin dir. 77059243Sobrien Meaningless without -c. 77159243Sobrien-d dir Uses /dir/tcsh.html instead of /tcsh.html as the HTML dir. 77259243Sobrien Meaningless without -c. 77359243Sobrien-D dir Uses /dir.html instead of /tcsh.html as the HTML dir. 77459243Sobrien Meaningless without -c. 77559243Sobrien-G name Uses name instead of tcsh.cgi as the name of the CGI script. 77659243Sobrien Meaningless without -c or -i. 77759243Sobrien-h host Uses host as the host:port part of the URL to the entry point. 77859243Sobrien Meaningless without -c. 77959243Sobrien-s Filenames are shorter (max 8 + 3) but less descriptive. 78059243Sobrien-u This message 78159243SobrienEOP 78259243Sobrien exit !! $message; 78359243Sobrien} 78459243Sobrien 78559243Sobrien### Inlined documents. Watch for *HERE tokens. 78659243Sobrien 78759243Sobrien__END__ 78859243Sobrien<HEAD> 78959243Sobrien<TITLE>The tcsh mailing lists</TITLE> 79059243Sobrien</HEAD> 79159243Sobrien<BODY> 79259243Sobrien<A HREF="TOPFILEHERE">Up</A> 79359243Sobrien<H2>The <I>tcsh</I> mailing lists</H2> 79459243SobrienThere are three <I>tcsh</I> mailing lists: 79559243Sobrien<DL> 79659243Sobrien<DT> 79759243Sobrien<I>tcsh@mx.gw.com</I> 79859243Sobrien<DD> 79959243SobrienThe <I>tcsh</I> maintainers and testers' mailing list. 80059243Sobrien<DT> 80159243Sobrien<I>tcsh-bugs@mx.gw.com</I> 80259243Sobrien<DD> 803145479SmpOpen bug and user comment discussion. 80459243Sobrien</DL> 805145479SmpYou can subscribe to either of these lists by visiting 806145479Smp<I><A HREF="http://mx.gw.com/">http://mx.gw.com/</A></I> 80759243Sobrien<P> 808145479SmpTo file a bug report or a feature suggestion (preferably 809145479Smpwith code), please visit 810145479Smp<I><A HREF="http://bugs.gw.com/">http://bugs.gw.com/</A></I> 811145479Smp<P> 81259243Sobrien<A HREF="TOPFILEHERE">Up</A> 81359243Sobrien</BODY> 81459243SobrienEND 81583098Smp: # -*- perl -*- 81659243Sobrien 81759243Sobrien# Emulate #!/usr/local/bin/perl on systems without #! 81859243Sobrien 81961515Sobrieneval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 82061515Sobrien& eval 'exec perl -S $0 $argv:q' if 0; 82159243Sobrien 82259243Sobrien# Setup 82359243Sobrien 82459243Sobrien# Location: doesn't work with relative URLs, so we need to know where to find 82559243Sobrien# the top and section files. 82659243Sobrien# If the search engine is in /cgi-bin, we need a hard-coded URL. 82759243Sobrien# If the search engine is in the same directory, we can figure it out from CGI 82859243Sobrien# environment variables. 82959243Sobrien 83059243Sobrien$root = ROOTHERE; 83159243Sobrien$topfile = 'TOPFILEHERE'; 83259243Sobrien@name = ( 83359243Sobrien'NAMEHERE' 83459243Sobrien); 83559243Sobrien 83659243Sobrien# Do the search 83759243Sobrien 83859243Sobrien$input = $ENV{'QUERY_STRING'}; 83959243Sobrien$input =~ s/^input=//; 84059243Sobrien$input =~ s/\+/ /g; 84159243Sobrienprint "Status: 302 Found\n"; 84259243Sobrienif ($input ne '' && ($key = (grep(/^$input/, @name))[0] || 84359243Sobrien (grep(/^$input/i, @name))[0] || 84459243Sobrien (grep( /$input/i, @name))[0] )) { 84559243Sobrien $key =~ /\t([^\t]*)$/; 84659243Sobrien print "Location: $root$1\n\n"; 84759243Sobrien} else { 84859243Sobrien print "Location: $root$topfile\n\n"; 84959243Sobrien} 85059243SobrienEND 851