1: # -*- perl -*- 2 3# tcsh.man2html, Dave Schweisguth <dcs@proton.chem.yale.edu> 4# 5# Notes: 6# 7# Always puts all files in the directory tcsh.html, creating it if necessary. 8# tcsh.html/top.html is the entry point, and tcsh.html/index.html is a symlink 9# to tcsh.html/top.html so one needn't specify a file at all if working through 10# a typically configured server. 11# 12# Designed for tcsh manpage. Guaranteed not to work on manpages not written 13# in the exact same style of nroff -man, i.e. any other manpage. 14# 15# Makes links FROM items which are both a) in particular sections (see 16# Configuration) and b) marked with .B or .I. Makes links TO items which 17# are marked with \fB ... \fR or \fI ... \fR. 18# 19# Designed with X Mosaic in mind and tested lightly with lynx. I've punted on 20# HTML's lack of a .PD equivalent and lynx's different <menu> handling. 21 22# Emulate #!/usr/local/bin/perl on systems without #! 23 24eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 25& eval 'exec perl -S $0 $argv:q' if 0; 26 27### Constants 28 29# Setup 30 31($whatami = $0) =~ s|.*/||; # `basename $0` 32$isatty = -t STDIN; 33 34# Configuration 35 36$index = 0; # Don't make a searchable index CGI script 37$cgibin = 0; # Look for $cgifile in $dir, not $cgibindir 38$shortfiles = 0; # Use long filenames 39$single = 0; # Make single page instead of top and sections 40 41$host = ''; # host:port part of server URL *** 42$updir = ''; # Directories between $host and $dir *** 43$dir = 'tcsh'; # Directory in which to put the pieces * 44$cgifile = 'tcsh.cgi'; # CGI script name ** 45$cgibindir = 'cgi-bin'; # CGI directory *** 46$headerfile = 'header'; # HTML file for initial comments * 47$indexfile = 'index'; # Symlink to $topfile * 48$listsfile = 'lists'; # Mailing list description HTML file * 49$outfile = 'tcsh.man'; # Default input file and copy of input file 50$script = $whatami; # Copy of script; filename length must be OK 51$topfile = 'top'; # Top-level HTML file * 52 53# * .htm or .html suffix added later 54# ** Only used with -i or -c 55# *** Only used with -c 56 57# Sections to inline in the top page 58 59%inline_me = ('NAME', 1, 60 'SYNOPSIS', 1); 61 62# Sections in which to put name anchors and the font in which to look for 63# links to those anchors 64 65%link_me = ('Editor commands', 'I', 66 'Builtin commands', 'I', 67 'Special aliases', 'I', 68 'Special shell variables', 'B', 69 'ENVIRONMENT', 'B', 70 'FILES', 'I'); 71 72### Arguments and error-checking 73 74# Parse args 75 76while ($#ARGV > -1 && (($first, $rest) = ($ARGV[0] =~ /^-(.)(.*)/))) { 77 # Perl 5 lossage alert 78 if ($first =~ /[CdDGh]/) { # Switches with arguments 79 shift; 80 $arg = $rest ne '' ? $rest : $ARGV[0] ne '' ? shift : 81 &usage("$whatami: -$first requires an argument.\n"); 82 } elsif ($rest ne '') { 83 $ARGV[0] = "-$rest"; 84 } else { 85 shift; 86 } 87 if ($first eq '1') { $single = 1; } 88 elsif ($first eq 'c') { $cgibin = 1; } 89 elsif ($first eq 'C') { $cgibindir = $arg; } 90 elsif ($first eq 'd') { $updir = $arg; } 91 elsif ($first eq 'D') { $dir = $arg; } 92 elsif ($first eq 'G') { $cgifile = $arg; } 93 elsif ($first eq 'h') { $host = $arg; } 94 elsif ($first eq 'i') { $index = 1; } 95 elsif ($first eq 's') { $shortfiles = 1; } 96 elsif ($first eq 'u') { &usage(0); } 97 else { &usage("$whatami: -$first is not an option.\n"); } 98} 99 100if (@ARGV == 0) { 101 if ($isatty) { 102 $infile = $outfile; # Default input file if interactive 103 } else { 104 $infile = 'STDIN'; # Read STDIN if no args and not a tty 105 } 106} elsif (@ARGV == 1) { 107 $infile = $ARGV[0]; 108} else { 109 &usage("$whatami: Please specify one and only one file.\n"); 110} 111 112$index = $index || $cgibin; # $index is true if $cgibin is true 113 114if ($cgibin && ! $host) { 115 die "$whatami: Must specify host with -h if using -c.\n"; 116} 117 118# Decide on HTML suffix and append it to filenames 119 120$html = $shortfiles ? 'htm' : 'html'; # Max 3-character extension 121$dir .= ".$html"; # Directory in which to put the pieces 122$headerfile .= ".$html"; # HTML file for initial comments 123$topfile .= ".$html"; # Top-level HTML file (or moved notice) 124$indexfile .= ".$html"; # Symlink to $topfile 125$listsfile .= ".$html"; # Mailing list description HTML file 126 127# Check for input file 128 129unless ($infile eq 'STDIN') { 130 die "$whatami: $infile doesn't exist!\n" unless -e $infile; 131 die "$whatami: $infile is unreadable!\n" unless -r _; 132 die "$whatami: $infile is empty!\n" unless -s _; 133} 134 135# Check for output directory and create if necessary 136 137if (-e $dir) { 138 -d _ || die "$whatami: $dir is not a directory!\n"; 139 -r _ && -w _ && -x _ || die "$whatami: $dir is inaccessible!\n" 140} else { 141 mkdir($dir, 0755) || die "$whatami: Can't create $dir!\n"; 142} 143 144# Slurp manpage 145 146if ($infile eq 'STDIN') { 147 @man = <STDIN>; 148} else { 149 open(MAN, $infile) || die "$whatami: Error opening $infile!\n"; 150 @man = <MAN>; 151 close MAN; 152} 153 154# Print manpage to HTML directory (can't use cp if we're reading from STDIN) 155 156open(MAN, ">$dir/$outfile") || die "$whatami: Can't open $dir/$outfile!\n"; 157print MAN @man; 158close MAN; 159 160# Copy script to HTML directory 161 162(system("cp $0 $dir") >> 8) && die "$whatami: Can't copy $0 to $dir!\n"; 163 164# Link top.html to index.html in case someone looks at tcsh.html/ 165 166system("rm -f $dir/$indexfile"); # Some systems can't ln -sf 167(system("ln -s $topfile $dir/$indexfile") >> 8) 168 && die "$whatami: Can't link $topfile to $dir/$indexfile!\n"; 169 170### Get title and section headings 171 172$comment = 0; # 0 for text, 1 for ignored text 173@sectionlines = (0); # First line of section 174@sectiontypes = (0); # H or S 175@sectiontexts = ('Header'); # Text of section heading 176@sectionfiles = ($headerfile); # Filename in which to store section 177%name = (); # Array of name anchors 178@name = () if $index; # Ordered array of name anchors 179$font = ''; # '' to not make names, 'B' or 'I' to do so 180 181$line = 0; 182foreach (@man) { 183 if (/^\.ig/) { # Start ignoring 184 $comment = 1; 185 } elsif (/^\.\./) { # Stop ignoring 186 $comment = 0; 187 } elsif (! $comment) { # Not in .ig'ed section; do stuff 188 189 # nroff special characters 190 191 s/\\-/-/g; # \- 192 s/\\^//g; # \^ 193 s/^\\'/'/; # leading ' escape 194 s/^\\(\s)/$1/; # leading space escape 195 s/\\(e|\\)/\\/g; # \e, \\; must do this after other escapes 196 197 # HTML special characters; deal with these before adding more 198 199 s/&/&\;/g; 200 s/>/>\;/g; 201 s/</<\;/g; 202 203 # Get title 204 205 if (/^\.TH\s+(\w+)\s+(\w+)\s+\"([^\"]*)\"\s+\"([^\"]*)\"/) { 206 $title = "$1($2) $4 ($3) $1($2)"; 207 } 208 209 # Build per-section info arrays 210 211 if (($type, $text) = /^\.S([HS])\s+\"?([^\"]*)\"?/) { 212 213 push(@sectionlines, $line); # Index of first line of section 214 push(@sectiontypes, $type eq 'H' ? 0 : 1); # Type of section 215 $text =~ s/\s*$//; # Remove trailing whitespace 216 push(@sectiontexts, $text); # Title of section (key for href) 217 $text =~ s/\s*\(\+\)$//; # Remove (+) 218 if ($shortfiles) { 219 $file = $#sectionlines; # Short filenames; use number 220 } else { 221 $file = $text; # Long filenames; use title 222 $file =~ s/[\s\/]+/_/g; # Replace whitespace and / with _ 223 } 224 $file .= ".$html" unless $single; 225 push(@sectionfiles, $file); # File in which to store section 226 $name{"$text B"} = ($single ? '#' : '') . $file; 227 # Index entry for &make_hrefs 228 push(@name, "$text\t" . $name{"$text B"}) if $index; 229 # Index entry for CGI script 230 # Look for anchors in the rest of this section if $link_me{$text} 231 # is non-null, and mark them with the font which is its value 232 233 $font = $link_me{$text}; 234 } 235 &make_name(*name, *font, *file, *index, *_) if $font; 236 } 237 $line++; 238} 239 240### Make top page 241 242open(TOP, ">$dir/$topfile"); 243select TOP; 244 245# Top page header 246 247print <<EOP; 248<HEAD> 249<TITLE>$title</TITLE> 250</HEAD> 251<BODY> 252<A NAME="top"></A> 253<H1>$title</H1> 254<HR> 255EOP 256 257# FORM block, if we're making an index 258 259$action = $cgibin ? "http://$host/$cgibindir/$cgifile" : $cgifile; 260 261print <<EOP if $index; 262<FORM METHOD="GET" ACTION="$action"> 263Go directly to a section, command or variable: <INPUT NAME="input"> 264</FORM> 265EOP 266 267# Table of contents 268 269print <<EOP; 270<H2> 271EOP 272 273foreach $section (1 .. $#sectionlines) { 274 if ($sectiontypes[$section - 1] < $sectiontypes[$section]) { 275 print "</H2> <menu>\n"; # Indent, smaller font 276 } elsif ($sectiontypes[$section - 1] > $sectiontypes[$section]) { 277 print "</menu> <H2>\n"; # Outdent, larger font 278 } 279 if ($inline_me{$sectiontexts[$section]}) { # Section is in %inline_me 280 281 # Print section inline 282 283 print "$sectiontexts[$section]\n"; 284 print "</H2> <menu>\n"; # Indent, smaller font 285 &printsectionbody(*man, *sectionlines, *section, *name); 286 print "</menu> <H2>\n"; # Outdent, larger font 287 } else { 288 289 # Print link to section 290 291 print "<A HREF=\"", $single ? '#' : '', 292 "$sectionfiles[$section]\">$sectiontexts[$section]</A><BR>\n"; 293 } 294} 295 296print <<EOP; 297</H2> 298EOP 299 300print "<HR>\n" if $single; 301 302### Make sections 303 304foreach $section (0 .. $#sectionlines) { 305 306 # Skip inlined sections 307 308 next if $inline_me{$sectiontexts[$section]}; 309 310 if ($single) { 311 312 # Header 313 314 print <<EOP if $section; # Skip header section 315<H2><A NAME="$sectionfiles[$section]">$sectiontexts[$section]</A></H2> 316<menu> 317EOP 318 &printsectionbody(*man, *sectionlines, *section, *name); 319 print <<EOP if $section; # Skip header section 320<A HREF="#top">Table of Contents</A> 321</menu> 322EOP 323 324 } else { 325 326 # Make pointer line for header and trailer 327 328 $pointers = "<A HREF=\"$topfile\">Up</A>"; 329 $pointers .= "\n<A HREF=\"$sectionfiles[$section + 1]\">Next</A>" 330 if ($section < $#sectionlines) && 331 ! $inline_me{$sectiontexts[$section + 1]}; 332 $pointers .= "\n<A HREF=\"$sectionfiles[$section - 1]\">Previous</A>" 333 if ($section > 1) && # section 0 is initial comments 334 ! $inline_me{$sectiontexts[$section - 1]}; 335 336 # Header 337 338 open(OUT, ">$dir/$sectionfiles[$section]"); 339 select OUT; 340 print <<EOP; 341<HEAD> 342<TITLE>$sectiontexts[$section]</TITLE> 343</HEAD> 344<BODY> 345$pointers 346<H2>$sectiontexts[$section]</H2> 347EOP 348 &printsectionbody(*man, *sectionlines, *section, *name); 349 350 # Trailer 351 352 print <<EOP; 353$pointers 354</BODY> 355EOP 356 357 } 358} 359 360select TOP unless $single; 361 362# Top page trailer 363 364print <<EOP; 365</H2> 366<HR> 367Here are the <A HREF="$outfile">nroff manpage</A> (175K) 368from which this HTML version was generated, 369the <A HREF="$script">Perl script</A> which did the conversion 370and the <A HREF="ftp://ftp.astron.com/pub/tcsh/"> 371complete source code</A> for <I>tcsh</I>. 372<HR> 373<I>tcsh</I> is maintained by 374Christos Zoulas <A HREF="mailto:christos\@astron.com"><christos\@astron.com></A> 375and the <A HREF="$listsfile"><I>tcsh</I> maintainers' mailing list</A>. 376Dave Schweisguth <A HREF="mailto:dcs\@proton.chem.yale.edu"><dcs\@proton.chem.yale.edu></A> 377wrote the manpage and the HTML conversion script. 378</BODY> 379EOP 380 381close TOP; 382 383### Make lists page 384 385open(LISTS, ">$dir/$listsfile"); 386select LISTS; 387while(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 388 s/TOPFILEHERE/$topfile/; 389 print; 390} 391close LISTS; 392 393### Make search script 394 395if ($index) { 396 397 # URL of $dir; see comments in search script 398 399 $root = $cgibin 400 ? "'http://$host/" . ($updir ? "$updir/" : '') . "$dir/'" 401 : '"http://$ENV{\'SERVER_NAME\'}:$ENV{\'SERVER_PORT\'}" . (($_ = $ENV{\'SCRIPT_NAME\'}) =~ s|[^/]*$||, $_)'; 402 403 # String for passing @name to search script 404 405 $name = join("',\n'", @name); 406 407 open(TOP, ">$dir/$cgifile"); 408 select TOP; 409 while(($_ = <DATA>) ne "END\n") { # Text stored after __END__ 410 s/ROOTHERE/$root/; 411 s/NAMEHERE/$name/; 412 s/TOPFILEHERE/$topfile/; 413 print; 414 } 415 close TOP; 416 chmod(0755, "$dir/$cgifile") || 417 die "$whatami: Can't chmod 0755 $dir/$cgifile!\n"; 418 warn "$whatami: Don't forget to move $dir/$cgifile to /$cgibindir.\n" 419 if $cgibin; 420} 421 422### That's all, folks 423 424exit; 425 426### Subroutines 427 428# Process and print the body of a section 429 430sub printsectionbody { 431 432 local(*man, *sectionlines, *sline, *name) = @_; # Number of section 433 local($sfirst, $slast, @paralines, @paratypes, $comment, $dl, $pline, 434 $comment, $pfirst, $plast, @para, @tag, $changeindent); 435 436 # Define section boundaries 437 438 $sfirst = $sectionlines[$sline] + 1; 439 if ($sline == $#sectionlines) { 440 $slast = $#man; 441 } else { 442 $slast = $sectionlines[$sline + 1] - 1; 443 } 444 445 # Find paragraph markers, ignoring those between '.ig' and '..' 446 447 if ($man[$sfirst] =~ /^\.[PIT]P/) { 448 @paralines = (); 449 @paratypes = (); 450 } else { 451 @paralines = ($sfirst - 1); # .P follows .S[HS] by default 452 @paratypes = ('P'); 453 } 454 $comment = 0; 455 foreach ($sfirst .. $slast) { 456 if ($man[$_] =~ /^\.ig/) { # Start ignoring 457 $comment = 1; 458 } elsif ($man[$_] =~ /^\.\./) { # Stop ignoring 459 $comment = 0; 460 } elsif (! $comment && $man[$_] =~ /^\.([PIT])P/) { 461 push(@paralines, $_); 462 push(@paratypes, $1); 463 } 464 } 465 466 # Process paragraphs 467 468 $changeindent = 0; 469 $dl = 0; 470 foreach $pline (0 .. $#paralines) { 471 472 @para = (); 473 $comment = 0; 474 475 # Define para boundaries 476 477 $pfirst = $paralines[$pline] + 1; 478 if ($pline == $#paralines) { 479 $plast = $slast; 480 } else { 481 $plast = $paralines[$pline + 1] - 1; 482 } 483 484 foreach (@man[$pfirst .. $plast]) { 485 if (/^\.ig/) { # nroff begin ignore 486 if ($comment == 0) { 487 $comment = 2; 488 push(@para, "<!--\n"); 489 } elsif ($comment == 1) { 490 $comment = 2; 491 } elsif ($comment == 2) { 492 s/--/-/g; # Remove double-dashes in comments 493 push(@para, $_); 494 } 495 } elsif (/^\.\./) { # nroff end ignore 496 if ($comment == 0) { 497 ; 498 } elsif ($comment == 1) { 499 ; 500 } elsif ($comment == 2) { 501 $comment = 1; 502 } 503 } elsif (/^\.\\\"/) { # nroff comment 504 if ($comment == 0) { 505 $comment = 1; 506 push(@para, "<!--\n"); 507 s/^\.\\\"//; 508 } elsif ($comment == 1) { 509 s/^\.\\\"//; 510 } elsif ($comment == 2) { 511 ; 512 } 513 s/--/-/g; # Remove double-dashes in comments 514 push(@para, $_); 515 } else { # Nothing to do with comments 516 if ($comment == 0) { 517 ; 518 } elsif ($comment == 1) { 519 $comment = 0; 520 push(@para, "-->\n"); 521 } elsif ($comment == 2) { 522 s/--/-/g; # Remove double-dashes in comments 523 } 524 525 unless ($comment) { 526 527 if (/^\.TH/) { # Title; got this already 528 next; 529 } elsif (/^\.PD/) { # Para spacing; unimplemented 530 next; 531 } elsif (/^\.RS/) { # Indent (one width only) 532 $changeindent++; 533 next; 534 } elsif (/^\.RE/) { # Outdent 535 $changeindent--; 536 next; 537 } 538 539 # Line break 540 s/^\.br.*/<BR>/; 541 542 # More nroff special characters 543 544 s/^\\&\;//; # leading dot escape; save until 545 # now so leading dots aren't 546 # confused with ends of .igs 547 548 &make_hrefs(*name, *_); 549 } 550 push(@para, $_); 551 } 552 } 553 554 push(@para, "-->\n") if $comment; # Close open comment 555 556 # Print paragraph 557 558 if ($paratypes[$pline] eq 'P') { 559 &font(*para); 560 print @para; 561 } elsif ($paratypes[$pline] eq 'I') { 562 &font(*para); 563 print "<menu>\n", 564 @para, 565 "</menu>\n"; 566 } else { # T 567 @tag = shift(@para); 568 &font(*tag); 569 &font(*para); 570 print "<DL compact>\n" unless $dl; 571 print "<DT>\n", 572 @tag, 573 "<DD>\n", 574 @para; 575 if ($pline == $#paratypes || $paratypes[$pline + 1] ne 'T') { 576 # Perl 5 lossage alert 577 # Next para is not a definition list 578 $dl = 0; # Close open definition list 579 print "</DL>\n"; 580 } else { 581 $dl = 1; # Leave definition list open 582 } 583 } 584 print "<P>\n"; 585 586 # Indent/outdent the *next* para 587 588 while ($changeindent > 0) { 589 print "<menu>\n"; 590 $changeindent--; 591 } 592 while ($changeindent < 0) { 593 print "</menu>\n"; 594 $changeindent++; 595 } 596 } 597 1; 598} 599 600# Make one name anchor in a line; cue on fonts (.B or .I) but leave them alone 601 602sub make_name { 603 604 local(*name, *font, *file, *index, *line) = @_; 605 local($text); 606 607 if (($text) = ($line =~ /^\.[BI]\s+([^\s\\]+)/)) { # Found pattern 608 609 if ( 610 $text !~ /^-/ # Avoid lists of options 611 && (length($text) > 1 # and history escapes 612 || $text =~ /^[%:@]$/) # Special pleading for %, :, @ 613 && ! $name{"$text $font"} # Skip if there's one already 614 ) { 615 # Record link 616 617 $name{"$text $font"} = ($single ? '' : $file) . "#$text"; 618 push(@name, "$text\t" . $name{"$text $font"}) if $index; 619 620 # Put in the name anchor 621 622 $line =~ s/^(\.[BI]\s+)([^\s\\]+)/$1<A NAME=\"$text\">$2<\/A>/; 623 } 624 } 625 $line; 626} 627 628# Make all the href anchors in a line; cue on fonts (\fB ... \fR or 629# \fI ... \fR) but leave them alone 630 631sub make_hrefs { 632 633 local(*name, *line) = @_; 634 local(@pieces, $piece); 635 636 @pieces = split(/(\\f[BI][^\\]*\\fR)/, $line); 637 638 $piece = 0; 639 foreach (@pieces) { 640 if (/\\f([BI])([^\\]*)\\fR/ # Found a possibility 641 642 # It's not followed by (, i.e. it's not a manpage reference 643 644 && substr($pieces[$piece + 1], 0, 1) ne '(') { 645 $key = "$2 $1"; 646 if ($name{$key}) { # If there's a matching name 647 s/(\\f[BI])([^\\]*)(\\fR)/$1<A HREF=\"$name{$key}\">$2<\/A>$3/; 648 } 649 } 650 $piece++; 651 } 652 $line = join('', @pieces); 653} 654 655# Convert nroff font escapes to HTML 656# Expects comments and breaks to be in HTML form already 657 658sub font { 659 660 local(*para) = @_; 661 local($i, $j, @begin, @end, $part, @pieces, $bold, $italic); 662 663 return 0 if $#para == -1; # Ignore empty paragraphs 664 # Perl 5 lossage alert 665 666 # Find beginning and end of each part between HTML comments 667 668 $i = 0; 669 @begin = (); 670 @end = (); 671 foreach (@para) { 672 push(@begin, $i + 1) if /^-->/ || /^<BR>/; 673 push(@end, $i - 1) if /^<!--/ || /^<BR>/; 674 $i++; 675 } 676 if ($para[0] =~ /^<!--/ || $para[0] =~ /^<BR>/) { 677 shift(@end); 678 } else { 679 unshift(@begin, 0); # Begin at the beginning 680 } 681 if ($para[$#para] =~ /^-->/ || $para[$#para] =~ /^<BR>/) { 682 pop(@begin); 683 } else { 684 push(@end, $#para); # End at the end 685 } 686 687 # Fontify each part 688 689 $bold = $italic = 0; 690 foreach $i (0 .. $#begin) { 691 $part = join('', @para[$begin[$i] .. $end[$i]]); 692 $part =~ s/^\.([BI])\s+(.*)$/\\f$1$2\\fR/gm; # .B, .I 693 @pieces = split(/(\\f[BIR])/m, $part); 694 $part = ''; 695 foreach $j (@pieces) { 696 if ($j eq '\fB') { 697 if ($italic) { 698 $italic = 0; 699 $part .= '</I>'; 700 } 701 unless ($bold) { 702 $bold = 1; 703 $part .= '<B>'; 704 } 705 } elsif ($j eq '\fI') { 706 if ($bold) { 707 $bold = 0; 708 $part .= '</B>'; 709 } 710 unless ($italic) { 711 $italic = 1; 712 $part .= '<I>'; 713 } 714 } elsif ($j eq '\fR') { 715 if ($bold) { 716 $bold = 0; 717 $part .= '</B>'; 718 } elsif ($italic) { 719 $italic = 0; 720 $part .= '</I>'; 721 } 722 } else { 723 $part .= $j; 724 } 725 } 726 727 # Close bold/italic before break 728 729 if ($end[$i] == $#para || $para[$end[$i] + 1] =~ /^<BR>/) { 730 # Perl 5 lossage alert 731 if ($bold) { 732 $bold = 0; 733 $part =~ s/(\n)?$/<\/B>$1\n/; 734 } elsif ($italic) { 735 $italic = 0; 736 $part =~ s/(\n)?$/<\/I>$1\n/; 737 } 738 } 739 740 # Rebuild this section of @para 741 742 foreach $j ($begin[$i] .. $end[$i]) { 743 $part =~ s/^([^\n]*(\n|$))//; 744 $para[$j] = $1; 745 } 746 } 747 748 # Close bold/italic on last non-comment line 749 # Do this only here because fonts pass through comments 750 751 $para[$end[$#end]] =~ s/(\n)?$/<\/B>$1/ if $bold; 752 $para[$end[$#end]] =~ s/(\n)?$/<\/I>$1/ if $italic; 753} 754 755sub usage { 756 local ($message) = $_[0]; 757 758 warn $message if $message; 759 warn <<EOP; 760Usage: $whatami [-1icsu] [-C dir] [-d dir] [-h host] [file] 761Without [file], reads from tcsh.man or stdin. 762-1 Makes a single page instead of a table of contents and sections 763-i Makes a CGI searchable index script, tcsh.html/tcsh.cgi, intended 764 for a server which respects the .cgi extension in any directory. 765-c Like -i, but the CGI script is intended for a server which wants 766 scripts in /cgi-bin (or some other privileged directory separate 767 from the rest of the HTML) and must be moved there by hand. 768-C dir Uses /dir instead of /cgi-bin as the CGI bin dir. 769 Meaningless without -c. 770-d dir Uses /dir/tcsh.html instead of /tcsh.html as the HTML dir. 771 Meaningless without -c. 772-D dir Uses /dir.html instead of /tcsh.html as the HTML dir. 773 Meaningless without -c. 774-G name Uses name instead of tcsh.cgi as the name of the CGI script. 775 Meaningless without -c or -i. 776-h host Uses host as the host:port part of the URL to the entry point. 777 Meaningless without -c. 778-s Filenames are shorter (max 8 + 3) but less descriptive. 779-u This message 780EOP 781 exit !! $message; 782} 783 784### Inlined documents. Watch for *HERE tokens. 785 786__END__ 787<HEAD> 788<TITLE>The tcsh mailing lists</TITLE> 789</HEAD> 790<BODY> 791<A HREF="TOPFILEHERE">Up</A> 792<H2>The <I>tcsh</I> mailing lists</H2> 793There are three <I>tcsh</I> mailing lists: 794<DL> 795<DT> 796<I>tcsh@mailman.astron.com</I> 797<DD> 798The <I>tcsh</I> maintainers and testers' mailing list. 799<DT> 800<I>tcsh-bugs@astron.com</I> 801<DD> 802Open bug and user comment discussion. 803</DL> 804You can subscribe to either of these lists by visiting 805<I><A HREF="https://mailman.astron.com/">https://mailman.astron.com/</A></I> 806<P> 807To file a bug report or a feature suggestion (preferably 808with code), please visit 809<I><A HREF="https://bugs.astron.com/">https://bugs.astron.com/</A></I> 810<P> 811<A HREF="TOPFILEHERE">Up</A> 812</BODY> 813END 814: # -*- perl -*- 815 816# Emulate #!/usr/local/bin/perl on systems without #! 817 818eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 819& eval 'exec perl -S $0 $argv:q' if 0; 820 821# Setup 822 823# Location: doesn't work with relative URLs, so we need to know where to find 824# the top and section files. 825# If the search engine is in /cgi-bin, we need a hard-coded URL. 826# If the search engine is in the same directory, we can figure it out from CGI 827# environment variables. 828 829$root = ROOTHERE; 830$topfile = 'TOPFILEHERE'; 831@name = ( 832'NAMEHERE' 833); 834 835# Do the search 836 837$input = $ENV{'QUERY_STRING'}; 838$input =~ s/^input=//; 839$input =~ s/\+/ /g; 840print "Status: 302 Found\n"; 841if ($input ne '' && ($key = (grep(/^$input/, @name))[0] || 842 (grep(/^$input/i, @name))[0] || 843 (grep( /$input/i, @name))[0] )) { 844 $key =~ /\t([^\t]*)$/; 845 print "Location: $root$1\n\n"; 846} else { 847 print "Location: $root$topfile\n\n"; 848} 849END 850