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/&/&amp\;/g;
201218822Sdim	s/>/&gt\;/g;
202218822Sdim	s/</&lt\;/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">&lt;christos\@gw.com&gt;</A>
376218822Sdimand the <A HREF="$listsfile"><I>tcsh</I> maintainers' mailing list</A>.
377218822SdimDave Schweisguth <A HREF="mailto:dcs\@proton.chem.yale.edu">&lt;dcs\@proton.chem.yale.edu&gt;</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/^\\&amp\;//;	    # 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 &lt;list name&gt; &lt;your name&gt;" on a line by
816218822Sdimitself in the body. &lt;list name&gt; is the name of the mailing list,
817218822Sdimwithout "@mx.gw.com", and &lt;your name&gt; 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