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