tcsh.man2html revision 59243
1218822Sdim#!/usr/local/bin/perl 238889Sjdp# $Id: tcsh.man2html,v 1.10 1997/10/29 17:27:04 christos Exp $ 3218822Sdim 4218822Sdim# tcsh.man2html, Dave Schweisguth <dcs@proton.chem.yale.edu> 5218822Sdim# 6218822Sdim# Notes: 7218822Sdim# 838889Sjdp# Always puts all files in the directory tcsh.html, creating it if necessary. 9218822Sdim# tcsh.html/top.html is the entry point, and tcsh.html/index.html is a symlink 10218822Sdim# to tcsh.html/top.html so one needn't specify a file at all if working through 11218822Sdim# a typically configured server. 12218822Sdim# 1338889Sjdp# Designed for tcsh manpage. Guaranteed not to work on manpages not written 14218822Sdim# in the exact same style of nroff -man, i.e. any other manpage. 15218822Sdim# 16218822Sdim# Makes links FROM items which are both a) in particular sections (see 17218822Sdim# Configuration) and b) marked with .B or .I. Makes links TO items which 18218822Sdim# are marked with \fB ... \fR or \fI ... \fR. 1938889Sjdp# 20218822Sdim# Designed with X Mosaic in mind and tested lightly with lynx. I've punted on 21218822Sdim# HTML's lack of a .PD equivalent and lynx's different <menu> handling. 22218822Sdim 23218822Sdim# Emulate #!/usr/local/bin/perl on systems without #! 24218822Sdim 25218822Sdimeval '(exit $?0)' && eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' 26218822Sdim& eval 'exec /usr/local/bin/perl -S $0 $argv:q' if 0; 27218822Sdim 28218822Sdim### Constants 29218822Sdim 30218822Sdim# Setup 31218822Sdim 32218822Sdim($whatami = $0) =~ s|.*/||; # `basename $0` 33218822Sdim$isatty = -t STDIN; 34218822Sdim 35218822Sdim# Configuration 36218822Sdim 37218822Sdim$index = 0; # Don't make a searchable index CGI script 38218822Sdim$cgibin = 0; # Look for $cgifile in $dir, not $cgibindir 39218822Sdim$shortfiles = 0; # Use long filenames 40218822Sdim$single = 0; # Make single page instead of top and sections 41218822Sdim 42218822Sdim$host = ''; # host:port part of server URL *** 43218822Sdim$updir = ''; # Directories between $host and $dir *** 44218822Sdim$dir = 'tcsh'; # Directory in which to put the pieces * 45218822Sdim$cgifile = 'tcsh.cgi'; # CGI script name ** 46218822Sdim$cgibindir = 'cgi-bin'; # CGI directory *** 47218822Sdim$headerfile = 'header'; # HTML file for initial comments * 48218822Sdim$indexfile = 'index'; # Symlink to $topfile * 49218822Sdim$listsfile = 'lists'; # Mailing list description HTML file * 50218822Sdim$outfile = 'tcsh.man'; # Default input file and copy of input file 51218822Sdim$script = $whatami; # Copy of script; filename length must be OK 52218822Sdim$topfile = 'top'; # Top-level HTML file * 53218822Sdim 54218822Sdim# * .htm or .html suffix added later 55218822Sdim# ** Only used with -i or -c 56218822Sdim# *** Only used with -c 57218822Sdim 58218822Sdim# Sections to inline in the top page 59218822Sdim 60218822Sdim%inline_me = ('NAME', 1, 61218822Sdim 'SYNOPSIS', 1); 62218822Sdim 63218822Sdim# Sections in which to put name anchors and the font in which to look for 64218822Sdim# links to those anchors 65218822Sdim 66218822Sdim%link_me = ('Editor commands', 'I', 67218822Sdim 'Builtin commands', 'I', 68218822Sdim 'Special aliases', 'I', 69218822Sdim 'Special shell variables', 'B', 70218822Sdim 'ENVIRONMENT', 'B', 71218822Sdim 'FILES', 'I'); 72218822Sdim 73218822Sdim### Arguments and error-checking 74218822Sdim 75218822Sdim# Parse args 76218822Sdim 77218822Sdimwhile ($#ARGV > -1 && (($first, $rest) = ($ARGV[0] =~ /^-(.)(.*)/))) { 78218822Sdim # Perl 5 lossage alert 79218822Sdim if ($first =~ /[CdDGh]/) { # Switches with arguments 80218822Sdim shift; 81218822Sdim $arg = $rest ne '' ? $rest : $ARGV[0] ne '' ? shift : 82218822Sdim &usage("$whatami: -$first requires an argument.\n"); 83218822Sdim } elsif ($rest ne '') { 8477298Sobrien $ARGV[0] = "-$rest"; 8577298Sobrien } else { 86218822Sdim shift; 87218822Sdim } 88218822Sdim if ($first eq '1') { $single = 1; } 89218822Sdim elsif ($first eq 'c') { $cgibin = 1; } 90218822Sdim elsif ($first eq 'C') { $cgibindir = $arg; } 91218822Sdim elsif ($first eq 'd') { $updir = $arg; } 92218822Sdim elsif ($first eq 'D') { $dir = $arg; } 93218822Sdim elsif ($first eq 'G') { $cgifile = $arg; } 94218822Sdim elsif ($first eq 'h') { $host = $arg; } 95218822Sdim elsif ($first eq 'i') { $index = 1; } 96218822Sdim elsif ($first eq 's') { $shortfiles = 1; } 97218822Sdim elsif ($first eq 'u') { &usage(0); } 98218822Sdim else { &usage("$whatami: -$first is not an option.\n"); } 99218822Sdim} 100218822Sdim 101218822Sdimif (@ARGV == 0) { 102218822Sdim if ($isatty) { 103218822Sdim $infile = $outfile; # Default input file if interactive 104218822Sdim } else { 105218822Sdim $infile = 'STDIN'; # Read STDIN if no args and not a tty 106218822Sdim } 107218822Sdim} elsif (@ARGV == 1) { 108218822Sdim $infile = $ARGV[0]; 109218822Sdim} else { 110218822Sdim &usage("$whatami: Please specify one and only one file.\n"); 111218822Sdim} 112218822Sdim 113218822Sdim$index = $index || $cgibin; # $index is true if $cgibin is true 114218822Sdim 115218822Sdimif ($cgibin && ! $host) { 116218822Sdim die "$whatami: Must specify host with -h if using -c.\n"; 117218822Sdim} 118218822Sdim 119218822Sdim# Decide on HTML suffix and append it to filenames 120218822Sdim 121218822Sdim$html = $shortfiles ? 'htm' : 'html'; # Max 3-character extension 122218822Sdim$dir .= ".$html"; # Directory in which to put the pieces 123218822Sdim$headerfile .= ".$html"; # HTML file for initial comments 124218822Sdim$topfile .= ".$html"; # Top-level HTML file (or moved notice) 125218822Sdim$indexfile .= ".$html"; # Symlink to $topfile 126218822Sdim$listsfile .= ".$html"; # Mailing list description HTML file 127218822Sdim 128218822Sdim# Check for input file 129218822Sdim 130218822Sdimunless ($infile eq 'STDIN') { 131218822Sdim die "$whatami: $infile doesn't exist!\n" unless -e $infile; 132218822Sdim die "$whatami: $infile is unreadable!\n" unless -r _; 133218822Sdim die "$whatami: $infile is empty!\n" unless -s _; 134218822Sdim} 135218822Sdim 136218822Sdim# Check for output directory and create if necessary 137218822Sdim 138218822Sdimif (-e $dir) { 139218822Sdim -d _ || die "$whatami: $dir is not a directory!\n"; 140218822Sdim -r _ && -w _ && -x _ || die "$whatami: $dir is inaccessible!\n" 141218822Sdim} else { 142218822Sdim mkdir($dir, 0755) || die "$whatami: Can't create $dir!\n"; 143218822Sdim} 144218822Sdim 145218822Sdim# Slurp manpage 146218822Sdim 147218822Sdimif ($infile eq 'STDIN') { 148218822Sdim @man = <STDIN>; 149218822Sdim} else { 150218822Sdim open(MAN, $infile) || die "$whatami: Error opening $infile!\n"; 151218822Sdim @man = <MAN>; 152218822Sdim close MAN; 153218822Sdim} 154218822Sdim 155218822Sdim# Print manpage to HTML directory (can't use cp if we're reading from STDIN) 156218822Sdim 157218822Sdimopen(MAN, ">$dir/$outfile") || die "$whatami: Can't open $dir/$outfile!\n"; 158218822Sdimprint MAN @man; 159218822Sdimclose MAN; 160218822Sdim 161218822Sdim# Copy script to HTML directory 162218822Sdim 163218822Sdim(system("cp $0 $dir") >> 8) && die "$whatami: Can't copy $0 to $dir!\n"; 164218822Sdim 165218822Sdim# Link top.html to index.html in case someone looks at tcsh.html/ 166218822Sdim 167218822Sdimsystem("rm -f $dir/$indexfile"); # Some systems can't ln -sf 168218822Sdim(system("ln -s $topfile $dir/$indexfile") >> 8) 169218822Sdim && die "$whatami: Can't link $topfile to $dir/$indexfile!\n"; 170218822Sdim 171218822Sdim### Get title and section headings 172218822Sdim 173218822Sdim$comment = 0; # 0 for text, 1 for ignored text 174218822Sdim@sectionlines = (0); # First line of section 175218822Sdim@sectiontypes = (0); # H or S 176218822Sdim@sectiontexts = ('Header'); # Text of section heading 177218822Sdim@sectionfiles = ($headerfile); # Filename in which to store section 178218822Sdim%name = (); # Array of name anchors 179218822Sdim@name = () if $index; # Ordered array of name anchors 180218822Sdim$font = ''; # '' to not make names, 'B' or 'I' to do so 181218822Sdim 182218822Sdim$line = 0; 183218822Sdimforeach (@man) { 184218822Sdim if (/^\.ig/) { # Start ignoring 185218822Sdim $comment = 1; 186218822Sdim } elsif (/^\.\./) { # Stop ignoring 187218822Sdim $comment = 0; 188218822Sdim } elsif (! $comment) { # Not in .ig'ed section; do stuff 189218822Sdim 190218822Sdim # nroff special characters 191218822Sdim 192218822Sdim s/\\-/-/g; # \- 193218822Sdim s/\\^//g; # \^ 194218822Sdim s/^\\'/'/; # leading ' escape 195218822Sdim s/^\\(\s)/$1/; # leading space escape 196218822Sdim s/\\(e|\\)/\\/g; # \e, \\; must do this after other escapes 197218822Sdim 198218822Sdim # HTML special characters; deal with these before adding more 199218822Sdim 200218822Sdim s/&/&\;/g; 201218822Sdim s/>/>\;/g; 202218822Sdim s/</<\;/g; 203218822Sdim 204218822Sdim # Get title 205218822Sdim 206218822Sdim if (/^\.TH\s+(\w+)\s+(\w+)\s+\"([^\"]*)\"\s+\"([^\"]*)\"/) { 207218822Sdim $title = "$1($2) $4 ($3) $1($2)"; 208218822Sdim } 209218822Sdim 210218822Sdim # Build per-section info arrays 211218822Sdim 212218822Sdim if (($type, $text) = /^\.S([HS])\s+\"?([^\"]*)\"?/) { 213218822Sdim 214218822Sdim push(@sectionlines, $line); # Index of first line of section 215218822Sdim push(@sectiontypes, $type eq 'H' ? 0 : 1); # Type of section 216218822Sdim $text =~ s/\s*$//; # Remove trailing whitespace 217218822Sdim push(@sectiontexts, $text); # Title of section (key for href) 218218822Sdim $text =~ s/\s*\(\+\)$//; # Remove (+) 219218822Sdim if ($shortfiles) { 220218822Sdim $file = $#sectionlines; # Short filenames; use number 221218822Sdim } else { 222218822Sdim $file = $text; # Long filenames; use title 223218822Sdim $file =~ s/[\s\/]+/_/g; # Replace whitespace and / with _ 224218822Sdim } 225218822Sdim $file .= ".$html" unless $single; 226218822Sdim push(@sectionfiles, $file); # File in which to store section 227218822Sdim $name{"$text B"} = ($single ? '#' : '') . $file; 228218822Sdim # Index entry for &make_hrefs 229218822Sdim push(@name, "$text\t" . $name{"$text B"}) if $index; 230218822Sdim # Index entry for CGI script 231218822Sdim # Look for anchors in the rest of this section if $link_me{$text} 232218822Sdim # is non-null, and mark them with the font which is its value 233218822Sdim 234218822Sdim $font = $link_me{$text}; 235218822Sdim } 236218822Sdim &make_name(*name, *font, *file, *index, *_) if $font; 237218822Sdim } 238218822Sdim $line++; 239218822Sdim} 240218822Sdim 241218822Sdim### Make top page 242218822Sdim 24377298Sobrienopen(TOP, ">$dir/$topfile"); 244218822Sdimselect TOP; 245218822Sdim 246218822Sdim# Top page header 247218822Sdim 248218822Sdimprint <<EOP; 24977298Sobrien<HEAD> 25077298Sobrien<TITLE>$title</TITLE> 251218822Sdim</HEAD> 252218822Sdim<BODY> 253218822Sdim<A NAME="top"></A> 254218822Sdim<H1>$title</H1> 255218822Sdim<HR> 256218822SdimEOP 257218822Sdim 258218822Sdim# FORM block, if we're making an index 25977298Sobrien 26077298Sobrien$action = $cgibin ? "http://$host/$cgibindir/$cgifile" : $cgifile; 261218822Sdim 262218822Sdimprint <<EOP if $index; 263218822Sdim<FORM METHOD="GET" ACTION="$action"> 264218822SdimGo directly to a section, command or variable: <INPUT NAME="input"> 265218822Sdim</FORM> 266218822SdimEOP 267218822Sdim 268218822Sdim# Table of contents 269218822Sdim 270218822Sdimprint <<EOP; 271218822Sdim<H2> 272218822SdimEOP 273218822Sdim 274130561Sobrienforeach $section (1 .. $#sectionlines) { 275218822Sdim if ($sectiontypes[$section - 1] < $sectiontypes[$section]) { 276130561Sobrien print "</H2> <menu>\n"; # Indent, smaller font 277218822Sdim } elsif ($sectiontypes[$section - 1] > $sectiontypes[$section]) { 278218822Sdim print "</menu> <H2>\n"; # Outdent, larger font 279218822Sdim } 280218822Sdim if ($inline_me{$sectiontexts[$section]}) { # Section is in %inline_me 281218822Sdim 282218822Sdim # Print section inline 283130561Sobrien 284218822Sdim print "$sectiontexts[$section]\n"; 28538889Sjdp print "</H2> <menu>\n"; # Indent, smaller font 286218822Sdim &printsectionbody(*man, *sectionlines, *section, *name); 287218822Sdim print "</menu> <H2>\n"; # Outdent, larger font 288218822Sdim } else { 289218822Sdim 290218822Sdim # Print link to section 291218822Sdim 292218822Sdim print "<A HREF=\"", $single ? '#' : '', 293218822Sdim "$sectionfiles[$section]\">$sectiontexts[$section]</A><BR>\n"; 294218822Sdim } 295218822Sdim} 296218822Sdim 297218822Sdimprint <<EOP; 298218822Sdim</H2> 299218822SdimEOP 300218822Sdim 301218822Sdimprint "<HR>\n" if $single; 302218822Sdim 303218822Sdim### Make sections 304218822Sdim 305218822Sdimforeach $section (0 .. $#sectionlines) { 306218822Sdim 307218822Sdim # Skip inlined sections 308218822Sdim 309218822Sdim next if $inline_me{$sectiontexts[$section]}; 310218822Sdim 311218822Sdim if ($single) { 312218822Sdim 313218822Sdim # Header 314218822Sdim 315218822Sdim print <<EOP if $section; # Skip header section 316218822Sdim<H2><A NAME="$sectionfiles[$section]">$sectiontexts[$section]</A></H2> 317218822Sdim<menu> 318218822SdimEOP 319218822Sdim &printsectionbody(*man, *sectionlines, *section, *name); 320218822Sdim print <<EOP if $section; # Skip header section 321218822Sdim<A HREF="#top">Table of Contents</A> 322218822Sdim</menu> 323218822SdimEOP 324218822Sdim 325218822Sdim } else { 326218822Sdim 327218822Sdim # Make pointer line for header and trailer 32838889Sjdp 32938889Sjdp $pointers = "<A HREF=\"$topfile\">Up</A>"; 330218822Sdim $pointers .= "\n<A HREF=\"$sectionfiles[$section + 1]\">Next</A>" 331218822Sdim if ($section < $#sectionlines) && 332218822Sdim ! $inline_me{$sectiontexts[$section + 1]}; 333218822Sdim $pointers .= "\n<A HREF=\"$sectionfiles[$section - 1]\">Previous</A>" 334218822Sdim if ($section > 1) && # section 0 is initial comments 335218822Sdim ! $inline_me{$sectiontexts[$section - 1]}; 336218822Sdim 337218822Sdim # Header 338218822Sdim 339218822Sdim open(OUT, ">$dir/$sectionfiles[$section]"); 340218822Sdim select OUT; 341218822Sdim print <<EOP; 342218822Sdim<HEAD> 343218822Sdim<TITLE>$sectiontexts[$section]</TITLE> 344218822Sdim</HEAD> 345218822Sdim<BODY> 346218822Sdim$pointers 347218822Sdim<H2>$sectiontexts[$section]</H2> 348218822SdimEOP 349218822Sdim &printsectionbody(*man, *sectionlines, *section, *name); 350218822Sdim 351218822Sdim # Trailer 352218822Sdim 353218822Sdim print <<EOP; 354218822Sdim$pointers 355218822Sdim</BODY> 356218822SdimEOP 357218822Sdim 358218822Sdim } 359218822Sdim} 360218822Sdim 361218822Sdimselect TOP unless $single; 362218822Sdim 363218822Sdim# Top page trailer 364218822Sdim 365218822Sdimprint <<EOP; 366218822Sdim</H2> 367218822Sdim<HR> 368218822SdimHere are the <A HREF="$outfile">nroff manpage</A> (175K) 369218822Sdimfrom which this HTML version was generated, 370218822Sdimthe <A HREF="$script">Perl script</A> which did the conversion 371218822Sdimand the <A HREF="file://ftp.astron.com/pub/tcsh/"> 372218822Sdimcomplete source code</A> for <I>tcsh</I>. 373218822Sdim<HR> 374218822Sdim<I>tcsh</I> is maintained by 375218822SdimChristos Zoulas <A HREF="mailto:christos\@gw.com"><christos\@gw.com></A> 376218822Sdimand the <A HREF="$listsfile"><I>tcsh</I> maintainers' mailing list</A>. 377218822SdimDave Schweisguth <A HREF="mailto:dcs\@proton.chem.yale.edu"><dcs\@proton.chem.yale.edu></A> 378218822Sdimwrote the manpage and the HTML conversion script. 379218822Sdim</BODY> 38094536SobrienEOP 381218822Sdim 382218822Sdimclose TOP; 383218822Sdim 384218822Sdim### Make lists page 385218822Sdim 386218822Sdimopen(LISTS, ">$dir/$listsfile"); 387218822Sdimselect LISTS; 388218822Sdimwhile(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 389218822Sdim s/TOPFILEHERE/$topfile/; 39038889Sjdp print; 39138889Sjdp} 39238889Sjdpclose LISTS; 393218822Sdim 394218822Sdim### Make search script 395218822Sdim 396218822Sdimif ($index) { 397218822Sdim 398218822Sdim # URL of $dir; see comments in search script 399218822Sdim 400218822Sdim $root = $cgibin 401218822Sdim ? "'http://$host/" . ($updir ? "$updir/" : '') . "$dir/'" 402218822Sdim : '"http://$ENV{\'SERVER_NAME\'}:$ENV{\'SERVER_PORT\'}" . (($_ = $ENV{\'SCRIPT_NAME\'}) =~ s|[^/]*$||, $_)'; 403218822Sdim 404218822Sdim # String for passing @name to search script 405218822Sdim 406218822Sdim $name = join("',\n'", @name); 407218822Sdim 408218822Sdim open(TOP, ">$dir/$cgifile"); 409218822Sdim select TOP; 410218822Sdim while(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 411218822Sdim s/ROOTHERE/$root/; 412218822Sdim s/NAMEHERE/$name/; 413218822Sdim s/TOPFILEHERE/$topfile/; 414218822Sdim print; 415218822Sdim } 416218822Sdim close TOP; 417218822Sdim chmod(0755, "$dir/$cgifile") || 418218822Sdim die "$whatami: Can't chmod 0755 $dir/$cgifile!\n"; 419218822Sdim warn "$whatami: Don't forget to move $dir/$cgifile to /$cgibindir.\n" 420218822Sdim if $cgibin; 421218822Sdim} 422218822Sdim 423218822Sdim### That's all, folks 424218822Sdim 425218822Sdimexit; 426218822Sdim 427218822Sdim### Subroutines 428218822Sdim 429218822Sdim# Process and print the body of a section 430218822Sdim 431218822Sdimsub printsectionbody { 432218822Sdim 433218822Sdim local(*man, *sectionlines, *sline, *name) = @_; # Number of section 434218822Sdim local($sfirst, $slast, @paralines, @paratypes, $comment, $dl, $pline, 435218822Sdim $comment, $pfirst, $plast, @para, @tag, $changeindent); 436218822Sdim 437218822Sdim # Define section boundaries 438218822Sdim 439218822Sdim $sfirst = $sectionlines[$sline] + 1; 440218822Sdim if ($sline == $#sectionlines) { 441218822Sdim $slast = $#man; 442218822Sdim } else { 443218822Sdim $slast = $sectionlines[$sline + 1] - 1; 444218822Sdim } 445218822Sdim 446218822Sdim # Find paragraph markers, ignoring those between '.ig' and '..' 447218822Sdim 448218822Sdim if ($man[$sfirst] =~ /^\.[PIT]P/) { 449218822Sdim @paralines = (); 450218822Sdim @paratypes = (); 451218822Sdim } else { 452218822Sdim @paralines = ($sfirst - 1); # .P follows .S[HS] by default 453218822Sdim @paratypes = ('P'); 454218822Sdim } 455218822Sdim $comment = 0; 456218822Sdim foreach ($sfirst .. $slast) { 457218822Sdim if ($man[$_] =~ /^\.ig/) { # Start ignoring 458218822Sdim $comment = 1; 459218822Sdim } elsif ($man[$_] =~ /^\.\./) { # Stop ignoring 460218822Sdim $comment = 0; 461218822Sdim } elsif (! $comment && $man[$_] =~ /^\.([PIT])P/) { 462218822Sdim push(@paralines, $_); 463218822Sdim push(@paratypes, $1); 464218822Sdim } 465218822Sdim } 466218822Sdim 467218822Sdim # Process paragraphs 468218822Sdim 469218822Sdim $changeindent = 0; 47038889Sjdp $dl = 0; 471218822Sdim foreach $pline (0 .. $#paralines) { 472218822Sdim 473218822Sdim @para = (); 474218822Sdim $comment = 0; 475218822Sdim 476218822Sdim # Define para boundaries 477218822Sdim 478218822Sdim $pfirst = $paralines[$pline] + 1; 479218822Sdim if ($pline == $#paralines) { 480218822Sdim $plast = $slast; 481218822Sdim } else { 482218822Sdim $plast = $paralines[$pline + 1] - 1; 483218822Sdim } 484218822Sdim 48538889Sjdp foreach (@man[$pfirst .. $plast]) { 486218822Sdim if (/^\.ig/) { # nroff begin ignore 487218822Sdim if ($comment == 0) { 488218822Sdim $comment = 2; 48938889Sjdp push(@para, "<!--\n"); 490218822Sdim } elsif ($comment == 1) { 491218822Sdim $comment = 2; 492218822Sdim } elsif ($comment == 2) { 493218822Sdim s/--/-/g; # Remove double-dashes in comments 494218822Sdim push(@para, $_); 495218822Sdim } 496218822Sdim } elsif (/^\.\./) { # nroff end ignore 497218822Sdim if ($comment == 0) { 498218822Sdim ; 499218822Sdim } elsif ($comment == 1) { 500218822Sdim ; 501218822Sdim } elsif ($comment == 2) { 502218822Sdim $comment = 1; 503218822Sdim } 504218822Sdim } elsif (/^\.\\\"/) { # nroff comment 505218822Sdim if ($comment == 0) { 506218822Sdim $comment = 1; 507218822Sdim push(@para, "<!--\n"); 508218822Sdim s/^\.\\\"//; 509218822Sdim } elsif ($comment == 1) { 510218822Sdim s/^\.\\\"//; 511218822Sdim } elsif ($comment == 2) { 512218822Sdim ; 513218822Sdim } 514218822Sdim s/--/-/g; # Remove double-dashes in comments 515218822Sdim push(@para, $_); 516218822Sdim } else { # Nothing to do with comments 517218822Sdim if ($comment == 0) { 518218822Sdim ; 519218822Sdim } elsif ($comment == 1) { 520218822Sdim $comment = 0; 521218822Sdim push(@para, "-->\n"); 522218822Sdim } elsif ($comment == 2) { 523218822Sdim s/--/-/g; # Remove double-dashes in comments 524218822Sdim } 525218822Sdim 526218822Sdim unless ($comment) { 527218822Sdim 528218822Sdim if (/^\.TH/) { # Title; got this already 529218822Sdim next; 530218822Sdim } elsif (/^\.PD/) { # Para spacing; unimplemented 531218822Sdim next; 532218822Sdim } elsif (/^\.RS/) { # Indent (one width only) 533218822Sdim $changeindent++; 534218822Sdim next; 535218822Sdim } elsif (/^\.RE/) { # Outdent 536218822Sdim $changeindent--; 537218822Sdim next; 538218822Sdim } 539218822Sdim 540218822Sdim # Line break 541218822Sdim 542218822Sdim s/^\.br.*/<BR>/; 543218822Sdim 544218822Sdim # More nroff special characters 545218822Sdim 546218822Sdim s/^\\&\;//; # leading dot escape; save until 547218822Sdim # now so leading dots aren't 548218822Sdim # confused with ends of .igs 549218822Sdim 550218822Sdim &make_hrefs(*name, *_); 551218822Sdim } 552218822Sdim push(@para, $_); 553218822Sdim } 554218822Sdim } 555218822Sdim 556218822Sdim push(@para, "-->\n") if $comment; # Close open comment 557218822Sdim 558218822Sdim # Print paragraph 559218822Sdim 560218822Sdim if ($paratypes[$pline] eq 'P') { 561218822Sdim &font(*para); 562218822Sdim print @para; 563218822Sdim } elsif ($paratypes[$pline] eq 'I') { 564218822Sdim &font(*para); 565218822Sdim print "<menu>\n", 566218822Sdim @para, 567218822Sdim "</menu>\n"; 568218822Sdim } else { # T 569218822Sdim @tag = shift(@para); 570218822Sdim &font(*tag); 571218822Sdim &font(*para); 572218822Sdim print "<DL compact>\n" unless $dl; 573218822Sdim print "<DT>\n", 574218822Sdim @tag, 575218822Sdim "<DD>\n", 576218822Sdim @para; 577218822Sdim if ($pline == $#paratypes || $paratypes[$pline + 1] ne 'T') { 578218822Sdim # Perl 5 lossage alert 579218822Sdim # Next para is not a definition list 580218822Sdim $dl = 0; # Close open definition list 581218822Sdim print "</DL>\n"; 582218822Sdim } else { 583218822Sdim $dl = 1; # Leave definition list open 584218822Sdim } 585218822Sdim } 586218822Sdim print "<P>\n"; 587218822Sdim 588218822Sdim # Indent/outdent the *next* para 589218822Sdim 590218822Sdim while ($changeindent > 0) { 591218822Sdim print "<menu>\n"; 592218822Sdim $changeindent--; 593218822Sdim } 594218822Sdim while ($changeindent < 0) { 595218822Sdim print "</menu>\n"; 596218822Sdim $changeindent++; 597218822Sdim } 598218822Sdim } 599218822Sdim 1; 600218822Sdim} 601218822Sdim 602218822Sdim# Make one name anchor in a line; cue on fonts (.B or .I) but leave them alone 603218822Sdim 604218822Sdimsub make_name { 605218822Sdim 606218822Sdim local(*name, *font, *file, *index, *line) = @_; 607218822Sdim local($text); 608218822Sdim 609218822Sdim if (($text) = ($line =~ /^\.[BI]\s+([^\s\\]+)/)) { # Found pattern 610218822Sdim 611218822Sdim if ( 612218822Sdim $text !~ /^-/ # Avoid lists of options 613218822Sdim && (length($text) > 1 # and history escapes 614218822Sdim || $text =~ /^[%:@]$/) # Special pleading for %, :, @ 615218822Sdim && ! $name{"$text $font"} # Skip if there's one already 616218822Sdim ) { 617218822Sdim # Record link 618218822Sdim 619218822Sdim $name{"$text $font"} = ($single ? '' : $file) . "#$text"; 620218822Sdim push(@name, "$text\t" . $name{"$text $font"}) if $index; 621218822Sdim 622218822Sdim # Put in the name anchor 623218822Sdim 624218822Sdim $line =~ s/^(\.[BI]\s+)([^\s\\]+)/$1<A NAME=\"$text\">$2<\/A>/; 625218822Sdim } 626218822Sdim } 627218822Sdim $line; 628218822Sdim} 629218822Sdim 630218822Sdim# Make all the href anchors in a line; cue on fonts (\fB ... \fR or 631218822Sdim# \fI ... \fR) but leave them alone 632218822Sdim 633218822Sdimsub make_hrefs { 634218822Sdim 635218822Sdim local(*name, *line) = @_; 636218822Sdim local(@pieces, $piece); 637218822Sdim 638218822Sdim @pieces = split(/(\\f[BI][^\\]*\\fR)/, $line); 639218822Sdim 640218822Sdim $piece = 0; 641218822Sdim foreach (@pieces) { 642218822Sdim if (/\\f([BI])([^\\]*)\\fR/ # Found a possibility 643218822Sdim 644218822Sdim # It's not followed by (, i.e. it's not a manpage reference 645218822Sdim 646218822Sdim && substr($pieces[$piece + 1], 0, 1) ne '(') { 647218822Sdim $key = "$2 $1"; 648218822Sdim if ($name{$key}) { # If there's a matching name 649218822Sdim s/(\\f[BI])([^\\]*)(\\fR)/$1<A HREF=\"$name{$key}\">$2<\/A>$3/; 650218822Sdim } 651218822Sdim } 652218822Sdim $piece++; 653218822Sdim } 654218822Sdim $line = join('', @pieces); 655218822Sdim} 656218822Sdim 657218822Sdim# Convert nroff font escapes to HTML 658218822Sdim# Expects comments and breaks to be in HTML form already 659218822Sdim 660218822Sdimsub font { 661218822Sdim 662218822Sdim local(*para) = @_; 663218822Sdim local($i, $j, @begin, @end, $part, @pieces, $bold, $italic); 664218822Sdim 665218822Sdim return 0 if $#para == -1; # Ignore empty paragraphs 666218822Sdim # Perl 5 lossage alert 667218822Sdim 668218822Sdim # Find beginning and end of each part between HTML comments 669218822Sdim 670218822Sdim $i = 0; 671218822Sdim @begin = (); 672218822Sdim @end = (); 673218822Sdim foreach (@para) { 674218822Sdim push(@begin, $i + 1) if /^-->/ || /^<BR>/; 675218822Sdim push(@end, $i - 1) if /^<!--/ || /^<BR>/; 676218822Sdim $i++; 677218822Sdim } 678218822Sdim if ($para[0] =~ /^<!--/ || $para[0] =~ /^<BR>/) { 679218822Sdim shift(@end); 680218822Sdim } else { 681218822Sdim unshift(@begin, 0); # Begin at the beginning 682218822Sdim } 683218822Sdim if ($para[$#para] =~ /^-->/ || $para[$#para] =~ /^<BR>/) { 684218822Sdim pop(@begin); 685218822Sdim } else { 686218822Sdim push(@end, $#para); # End at the end 687218822Sdim } 688218822Sdim 689218822Sdim # Fontify each part 690218822Sdim 691218822Sdim $bold = $italic = 0; 692218822Sdim foreach $i (0 .. $#begin) { 693218822Sdim $* = 1; 694218822Sdim $part = join('', @para[$begin[$i] .. $end[$i]]); 695218822Sdim $part =~ s/^\.([BI])\s+(.*)$/\\f$1$2\\fR/g; # .B, .I 696218822Sdim @pieces = split(/(\\f[BIR])/, $part); 697218822Sdim $part = ''; 698218822Sdim foreach $j (@pieces) { 699218822Sdim if ($j eq '\fB') { 700218822Sdim if ($italic) { 701218822Sdim $italic = 0; 702218822Sdim $part .= '</I>'; 703218822Sdim } 704218822Sdim unless ($bold) { 705218822Sdim $bold = 1; 706218822Sdim $part .= '<B>'; 707218822Sdim } 708218822Sdim } elsif ($j eq '\fI') { 709218822Sdim if ($bold) { 710218822Sdim $bold = 0; 711218822Sdim $part .= '</B>'; 712218822Sdim } 713218822Sdim unless ($italic) { 714218822Sdim $italic = 1; 715218822Sdim $part .= '<I>'; 716218822Sdim } 717218822Sdim } elsif ($j eq '\fR') { 718218822Sdim if ($bold) { 719218822Sdim $bold = 0; 720218822Sdim $part .= '</B>'; 721218822Sdim } elsif ($italic) { 722218822Sdim $italic = 0; 723218822Sdim $part .= '</I>'; 724218822Sdim } 725218822Sdim } else { 726218822Sdim $part .= $j; 727218822Sdim } 728218822Sdim } 72994536Sobrien $* = 0; 73038889Sjdp 73138889Sjdp # Close bold/italic before break 73238889Sjdp 733218822Sdim if ($end[$i] == $#para || $para[$end[$i] + 1] =~ /^<BR>/) { 73438889Sjdp # Perl 5 lossage alert 73538889Sjdp if ($bold) { 73638889Sjdp $bold = 0; 73738889Sjdp $part =~ s/(\n)?$/<\/B>$1\n/; 73838889Sjdp } elsif ($italic) { 73938889Sjdp $italic = 0; 740218822Sdim $part =~ s/(\n)?$/<\/I>$1\n/; 741218822Sdim } 74238889Sjdp } 743218822Sdim 74438889Sjdp # Rebuild this section of @para 745218822Sdim 746218822Sdim foreach $j ($begin[$i] .. $end[$i]) { 747218822Sdim $part =~ s/^([^\n]*(\n|$))//; 74838889Sjdp $para[$j] = $1; 74938889Sjdp } 75038889Sjdp } 75138889Sjdp 75238889Sjdp # Close bold/italic on last non-comment line 75338889Sjdp # Do this only here because fonts pass through comments 75438889Sjdp 75538889Sjdp $para[$end[$#end]] =~ s/(\n)?$/<\/B>$1/ if $bold; 75638889Sjdp $para[$end[$#end]] =~ s/(\n)?$/<\/I>$1/ if $italic; 757218822Sdim} 75838889Sjdp 75938889Sjdpsub usage { 76038889Sjdp local ($message) = $_[0]; 76138889Sjdp 76238889Sjdp warn $message if $message; 76338889Sjdp warn <<EOP; 76438889SjdpUsage: $whatami [-1icsu] [-C dir] [-d dir] [-h host] [file] 76538889SjdpWithout [file], reads from tcsh.man or stdin. 76638889Sjdp-1 Makes a single page instead of a table of contents and sections 76738889Sjdp-i Makes a CGI searchable index script, tcsh.html/tcsh.cgi, intended 768218822Sdim for a server which respects the .cgi extension in any directory. 769218822Sdim-c Like -i, but the CGI script is intended for a server which wants 770218822Sdim scripts in /cgi-bin (or some other privileged directory separate 771218822Sdim from the rest of the HTML) and must be moved there by hand. 772218822Sdim-C dir Uses /dir instead of /cgi-bin as the CGI bin dir. 773218822Sdim Meaningless without -c. 774218822Sdim-d dir Uses /dir/tcsh.html instead of /tcsh.html as the HTML dir. 775218822Sdim Meaningless without -c. 776218822Sdim-D dir Uses /dir.html instead of /tcsh.html as the HTML dir. 777218822Sdim Meaningless without -c. 778218822Sdim-G name Uses name instead of tcsh.cgi as the name of the CGI script. 779218822Sdim Meaningless without -c or -i. 780218822Sdim-h host Uses host as the host:port part of the URL to the entry point. 781218822Sdim Meaningless without -c. 782218822Sdim-s Filenames are shorter (max 8 + 3) but less descriptive. 783218822Sdim-u This message 784218822SdimEOP 785218822Sdim exit !! $message; 786218822Sdim} 787218822Sdim 788218822Sdim### Inlined documents. Watch for *HERE tokens. 789218822Sdim 790218822Sdim__END__ 791218822Sdim<HEAD> 79238889Sjdp<TITLE>The tcsh mailing lists</TITLE> 793218822Sdim</HEAD> 794218822Sdim<BODY> 79538889Sjdp<A HREF="TOPFILEHERE">Up</A> 796218822Sdim<H2>The <I>tcsh</I> mailing lists</H2> 79738889SjdpThere are three <I>tcsh</I> mailing lists: 798218822Sdim<DL> 799218822Sdim<DT> 800218822Sdim<I>tcsh@mx.gw.com</I> 801218822Sdim<DD> 802218822SdimThe <I>tcsh</I> maintainers and testers' mailing list. 803218822Sdim<DT> 804218822Sdim<I>tcsh-diffs@mx.gw.com</I> 805218822Sdim<DD> 806218822SdimThe same as <I>tcsh@mx.gw.com</I>, plus diffs for each new 807218822Sdimpatchlevel of <I>tcsh</I>. 808218822Sdim<DT> 809218822Sdim<I>tcsh-bugs@mx.gw.com</I> 810218822Sdim<DD> 811218822SdimBug reports. 812218822Sdim</DL> 813218822SdimYou can subscribe to any of these lists by sending mail to 814218822Sdim<I><A HREF="mailto:listserv@mx.gw.com">listserv@mx.gw.com</A></I> with the 815218822Sdimtext "subscribe <list name> <your name>" on a line by 816218822Sdimitself in the body. <list name> is the name of the mailing list, 817218822Sdimwithout "@mx.gw.com", and <your name> is your real name, not your 818218822Sdimemail address. You can also ask the list server for help by sending 819218822Sdimonly the word "help". 820218822Sdim<P> 821218822Sdim<A HREF="TOPFILEHERE">Up</A> 822218822Sdim</BODY> 823218822SdimEND 824218822Sdim#!/usr/local/bin/perl 825218822Sdim 826218822Sdim# Emulate #!/usr/local/bin/perl on systems without #! 827218822Sdim 828218822Sdimeval '(exit $?0)' && eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' 829218822Sdim& eval 'exec /usr/local/bin/perl -S $0 $argv:q' if 0; 830218822Sdim 831218822Sdim# Setup 832218822Sdim 833218822Sdim# Location: doesn't work with relative URLs, so we need to know where to find 834218822Sdim# the top and section files. 835218822Sdim# If the search engine is in /cgi-bin, we need a hard-coded URL. 836218822Sdim# If the search engine is in the same directory, we can figure it out from CGI 837218822Sdim# environment variables. 838218822Sdim 839218822Sdim$root = ROOTHERE; 840218822Sdim$topfile = 'TOPFILEHERE'; 841218822Sdim@name = ( 842218822Sdim'NAMEHERE' 84338889Sjdp); 844218822Sdim 845218822Sdim# Do the search 846218822Sdim 847218822Sdim$input = $ENV{'QUERY_STRING'}; 848218822Sdim$input =~ s/^input=//; 849218822Sdim$input =~ s/\+/ /g; 850218822Sdimprint "Status: 302 Found\n"; 851218822Sdimif ($input ne '' && ($key = (grep(/^$input/, @name))[0] || 852218822Sdim (grep(/^$input/i, @name))[0] || 853218822Sdim (grep( /$input/i, @name))[0] )) { 854218822Sdim $key =~ /\t([^\t]*)$/; 855218822Sdim print "Location: $root$1\n\n"; 856218822Sdim} else { 857218822Sdim print "Location: $root$topfile\n\n"; 858218822Sdim} 859218822SdimEND 860218822Sdim