/contrib/tcsh/tcsh.man2html

https://bitbucket.org/freebsd/freebsd-head/ · Unknown · 850 lines · 692 code · 158 blank · 0 comment · 0 complexity · fc90b457ad7a8b413d31de35b250a768 MD5 · raw file

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