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