#!/usr/local/bin/perl
# Perl script to convert nroff / sgml help files to HHW project

# (c) 1997-2002 B. D. Ripley
# Not unlike parts of nr2hlp and R's Sd2Rd (those parts written by BDR)

# check index of last arg (should be at least 1 arg)
die &usage unless $#ARGV >= 0;

$topic = $ARGV[0];

if($#ARGV > 1) {
    shift;
    @helpfiles = @ARGV;
} else {
    if($#ARGV == 1)
    {
	## Try to map the usual OS wildcards
	$filespec = $ARGV[1];
	$filespec =~ s/\./\\./;
	$filespec =~ s/\?/./;
	$filespec =~ s/\*/\.*/;
    } else {
	## default spec is *.d
	$filespec='^.*\.d$'; # ' extra
    }
    opendir(LISDIR, ".") or die "Can't ls *.d this directory";
    @helpfiles = grep(m!$filespec!, readdir(LISDIR));
    closedir(LISDIR);
}

my @lines;
%htmlfiles;
%ahtmlfiles;
%titles, %titles2fun;

open CSSFILE, ">S+chm.css" or die "can't open S+chm.css";
print CSSFILE <<END;
body { font-size: 10pt ; font-family: Arial, SansSerif }
h1   { font-size: 150% }
h2   { font-size: 120% } 
samp { font-size: small; font-family: "Courier New", Monospaced }
code { font-family: "Courier New", Monospaced }
tt   { font-family: "Courier New", Monospaced }
pre  { margin-top: 5; margin-bottom: 5; font-family: "Courier New", Monospaced}
END
close CSSFILE;

%libfuns;

## pass 1, find the objects in this library section
print "finding all the documented objects in these files\n";
foreach $nrfile (sort @helpfiles)
{
    open(NRFILE, $nrfile) || next;
    @lines = <NRFILE>;
    close(NRFILE);
## peek at the first line of the file, then dispatch to
## S3-style (nroff) or S4-style (SGML spec).
    if(@lines[0] =~ /^<!doctype/) { doS4fun(); } else { doS3fun(); }
}

## pass 2, process the files
print "processing the files\n";
foreach $nrfile (sort @helpfiles)
{
    open(NRFILE, $nrfile) || next;
    @lines = <NRFILE>;
    close(NRFILE);
## peek at the first line of the file, then dispatch to
## S3-style (nroff) or S4-style (SGML spec).
    if(@lines[0] =~ /^<!doctype/) { doS4(); } else { doS3(); }
    close OUTFILE;
}

make_hhp($topic);
make_toc($topic);
make_hhk($topic);

if($^O eq "MSWin32") {
    print("running hhc\n");
    system("hhc.exe $topic.hhp");
}

exit 0;

sub usage
{
    print STDERR "Usage: [perl] S2html topicname [filespec]\n";
}


sub header {
  my $name = $_[0];

  print OUTFILE <<END;
<html>
<head>
<link rel="stylesheet" type="text/css" href="S+chm.css">
</head>
<body bgcolor="#FFFFFF">
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
END
    print OUTFILE "<param name=\"Keyword\" value=\"$name\">\n";
    print OUTFILE "<param name=\"ALink Name\" value=\"$name\">\n</object>\n";
}

sub alias {
    my $name=$_[0];
    print OUTFILE "<object type=\"application/x-oleobject\" classid=\"clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e\">";
    print OUTFILE "<param name=\"Keyword\" value=\"$name\">\n";
    print OUTFILE "<param name=\"ALink Name\" value=\"$name\">\n</object>\n";
}

sub footer {
    JScript() if $nlink > 0;
    print  OUTFILE "</body>\n</html>\n";
}

sub doS3fun {
    foreach $_ (@lines) {
	chop;
	if (/^\.FN/) {
	    my @word = split;
	    $fun = $word[1];
	    $libfuns{$fun} = $fun;
	    last;
	}
    }
}

sub doS4fun {
    foreach $_ (@lines) {
	chop;
	if (/<s-topic>(.*)<\/s-topic>/) {
	    $fun = $1;
	    $libfuns{$fun} = $fun;
	    last;
	}
    }
}

sub doS3 {    
    $braceLevel = 0;
    $inReferences = 0;
    $inVerbatim = 0;
    $inTitle = 0;
    $inSeeAlso = 0;
    $inCode = 0;
    $isDataSet = 0;
    $underlineNext = 0;
    $output = "";
    $nlink = 0;
    @ends;
    my @alias;

    my $fun;
    my $hadArgs = 0;
    foreach $_ (@lines) {
	chop;
	$Title = $_ if $inTitle && !/^\./;
	&substitute unless /^\./;
	my @word = split;

	if (/^\s*$/) { &output("\n"); }
	if (/^[^.]/) {
	    if ($underlineNext) {
		$_ = "<em>" . $_ ."</em>";
		$underlineNext = 0;
	    }
	    &output($_);
	}

	if (/^\.\\\"/o) {
	    s/^\.\\\"/<!-- /;
	    &output($_ . " -->");
	}

	if (/^\.BG D/) {
	    $isDataSet = 1;
	}
	if (/^\.FN/) {
	    if($fun) {
		push @alias, $word[1];
	    } else {
		$tfun = $fun = $word[1];
		$funhtml = $fun . ".html";
		$funhtml =~ s/</_/g;
		open OUTFILE, "> $funhtml" or die
		    "Can't open file '$funhtml' for writing\n";
		$htmlfiles{$word[1]} = "$funhtml";
	    }
	    $ahtmlfiles{$word[1]} = "$funhtml";
	}
	if (/^\.TL/) {
	    &header($fun);
	    foreach $f (@alias) { &alias($f); }
	    &section(0, "<title>", "</title>");
	    $inTitle = 1;
	    $inVerbatim = 1;
	}
	if (/^\.RA/) {
	    &section(0, "<h2>REQUIRED ARGUMENTS:</h2>\n<dl>", "</dl>");
	    $hadArgs = 1;
	}
	if (/^\.OA/) {
	    &section(0, "<h2>OPTIONAL ARGUMENTS:</h2>\n<dl>", "</dl>");
	    $hadArgs = 1;
	}
	if (/^\.AG/) {
	    $arg = $_;
	    $arg =~ s/^\.AG\s//;
	    if (!$hadArgs) {
		&section(0, "<h2>ARGUMENTS:</h2>\n<dl>", "</dl>");
		$hadArgs = 1;
	    }
	    &section(1, "<dt><b>$arg</b></dt><dd>", "</dd>");
	}
	if (/^\.CS/) {
	    &section(0, "<h2>USAGE:</h2>\n<pre>", "</pre>");
	    $inVerbatim = 1;
	}
	if (/^\.DN/) { &section(0, "<h2>DESCRIPTION:</h2>\n<p>"); }
	if (/^\.DT/) { &section(0, "<h2>DETAILS:</h2>\n<p>"); }
	if (/^\.EX/) {
	    &section(0, "<h2>EXAMPLES:</h2>\n<pre>", "</pre>");
	    $inVerbatim = 1;
	}
	if (/^\.(IP|PP)/) { &output("<p>\n"); }
	if (/^\.KW/) {
	    &section(0, "");
	    &output("<!-- s-keyword $word[1] -->");
	}
	if (/^\.RC/) {
	    &section(1, "<dt><b>" . join(" ", @word[1..$#word]) . "</b></dt><dd>",
		     "</dd>");
	}
	if (/^\.RT/) {
	    &section(0, "<h2>VALUE:</h2>\n<dl>", "</dl>");
	    $output = "";
	}
	if (/^\.SA/) {
	    &section(0, "<h2>SEE ALSO:</h2>");
	    $inSeeAlso = 1;
	}
	if (/^\.SE/) { &section(0, "<h2>SIDE EFFECTS:</h2>"); }
	if (/^\.SH/) {
	    if ($word[1] =~ /REFERENCE/) {
		&section(0, "<h2>REFERENCES:</h2>");
		$inReferences = 1;
	    } else {
		# This line may be of the form .SH "A B C"
		($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
		&section(0, "<h2>$tmp:</h2>");
	    }
	}
	if (/^\.sp/) { output("\n"); }
	if (/^\.WR/) {
	    &section(0, "");
	    &footer;
	    $titles{$fun} = $Title;
	    foreach $f (@alias) { $titles{$f} = $Title; }
	    $titles2fun{$Title} = $fun;
	}
	if (/^\.AO/) {
	    output("Arguments for function <tt>$word[1]()</tt> can also be");
	    output("supplied to this function.");
	}
	if (/^\.GE/) {
	    output("This is a generic function.");
	    output("Functions with names beginning in <tt>$fun.</tt> will be");
	    output("methods for this function.");
	    output("Classes with methods for this function include:");
	}
	if (/^\.GR/) {
	    output("Graphical parameters (see <tt>par</tt>) may also");
	    output("be supplied as arguments to this function.");
	}
	if (/^\.ME/) {
	    output("This function is a method for the generic function");
	    output("<tt>$word[1]()</tt> for class <tt>\"$word[2]\"</tt>.");
	    output("It can be invoked by calling <tt>$word[1](x)</tt> for an");
	    output("object <tt>x</tt> of the appropriate class, or directly by");
	    output("calling <tt>$word[1].$word[2](x)</tt> regardless of the");
	    output("class of the object.");
	}
	if (/^\.NA/) { output("Missing values (<tt>NA</tt>s) are allowed."); }
	if (/^\.Tl/) {
	    output("In addition, the high-level graphics control arguments");
	    output("described under <tt>par</tt> and the arguments to");
	    output("<tt>title</tt> may be supplied to this function.");
	}
	if (/^\.ul/) { $underlineNext = 1; }
	## End
    }
}

sub substitute {
    s/&/&amp;/go;
    if (!$inVerbatim) {
	s/\\\(aa/'/g;		# extra ' for highlight matching
	s/\\\(em&mdash;//g;	# em dash
	s/\\\(tm/ (TM) /g;	# Trademark
	s/\\\(mu/ x /g;		# multiply sign
	s/\\\(\*a/&alpha;/g;	# greek
	s/\\\(\*b/&beta;/g;
	s/\\\(\*e/&epsilon;/g;
	s/\\\(\*l/&lambda;/g;
	s/\\\(\*m/&mu;/g;
	s/\\\(\*p/&pi;/g;
	s/\\\(\*s/&sigma;/g;
    }
    s/</&lt;/go;
    s/>/&gt;/go;
    s/\\fI(.*?)\\fP/<em>$1<\/em>/g;
    s/\\fI(.*?)\\fR/<em>$1<\/em>/g;
    s/\\fB(.*?)\\fP/<b>$1<\/b>/g;
    s/\\fB(.*?)\\fR/<b>$1<\/b>/g;
    if($inCode && s/\'/<\/tt>/) {
	$inCode = 0;
    }
    if ($inSeeAlso) {
	while(s/\`([^\']*)\'/<a foobar><tt>$1<\/tt><\/a>/) {
	    if(defined $libfuns{$1}) {
		$replace = "href=\"" . $1 . ".html" . "\"";
	    } else {
		$nlink++;
		$replace = mklink($1);
	    }
	    s/foobar/$replace/;
	}
    } elsif (!$inVerbatim) {
	if(s/\`([^\']*)$/<tt>$1/) {
	    $inCode = 1;
	}
	s/\`([^\']*)\'$/<tt>$1<\/tt>/g;
	s/\`([^\']*)\'([^\'])/<tt>$1<\/tt>$2/g;
    }
    if ($inReferences) {
	s/([0-9])-([0-9])/$1&ndash;$2/g;
    }
}

sub section {
    my($level, $text, $end) = @_;
    while($braceLevel > $level) {
	my $end = pop @ends;
	print OUTFILE  "$end\n" if length($end) > 0;
	print OUTFILE "\n";
	$braceLevel--;
    }
    if($inTitle) {
	print OUTFILE "<table width=\"100%\" border=\"0\" cellspacing=\"0\"\n";
	print OUTFILE "cellpadding=\"0\" bgcolor=\"#CCCCCC\">\n<tr>\n";
	print OUTFILE "<td width=\"50%\"><tt>$tfun</tt></td>\n";
	print OUTFILE "<td width=\"50%\"><div align=\"right\"><font face=\"Times New Roman, Times, serif\">Library section $topic</font></div>\n</td></tr></table>\n";
	print OUTFILE "<h1>$Title</h1>\n\n";
	$inTitle = 0;
    }
    print OUTFILE "$text\n" if $text;
    $braceLevel = $level + 1;
    $inReferences = 0;
    $inVerbatim = 0;
    $inSeeAlso = 0;
    push @ends, $end;
}

sub output {
    my($text) = @_;
    print OUTFILE "$text\n";
}


## ---------------------------- S4 section -------------------------

my $skipping = 0;
my $nextskipping = 0;
my $text = "";
my $fun;
my $InArgs = 0;


sub doS4 {
    $nlink = 0;
    $nalias = 0;
    undef @aliases;
    foreach $_ (@lines) {
	# skip header
	if (/^<!doctype/) {
	    $skipping = 1;
	    $nextskipping = 1 unless />\s*$/s;
	}
	if($skipping && /^>/) { $nextskipping = 0;}
	# skip comments
	$skipping = $nextskipping = 1 if (/^\s*<\!-- /);
	if($skipping && /-->\s*$/) { $nextskipping = 0;}
	if(!$skipping) {
	    $text = $text . $_;
	}
	$skipping = $nextskipping;
    }

    ($type, $text, $rest) = get_group($text); # s-function-doc or whatever
    if($type ne "function-doc" && $type ne "method-doc") {
	die "Document class `s-$type' is not supported";
    }

    chomp $text;

    while(length($text) > 0) {
	($type, $body, $text) = get_group($text);
	process_group($type, $body);
    }
    footer();
    foreach $f (@aliases) { $titles{$f} = $title2; }
}

sub get_group
{
    my $text = $_[0];
    my $body;
    my $rest;

    die "not at beginning of a group in |$text|" unless
	$text =~ /^\s*<s-(.+?)>/s;
    my $type = $1;
    my $tt = $type;
    $tt =~ s/([a-zA-Z-]+).*/$1/;
    if($text =~ /^\s*<s-\Q$type\E>(.*?)<\/s-$tt>(.*)/s) {
	$body = $1;
	$rest = $2;
    } else {
	warn "no match for `s-$tt' in file `$nrfile'\n";
	$text =~ /^\s*<s-\Q$type\E>\s*(.*)/s;
	$body = $1;
	$rest = "";
    }
    ($type, $body, $rest);
}

sub process_group
{
    my $type = $_[0];
    my $text = $_[1];

    if($InArgs && ($type =~ /^args/) != 1) {
	print OUTFILE "</dl>\n\n";
	$InArgs = 0;
    }

    $text =~ s/^\n*//;
    $text =~ s/\n*$//;

    if ($type eq "topics") {
	process_sub_groups($text, "topic");

    } elsif ($type eq "title") {
	# conversion to .sgml adds a trailing space
	my $title = $text;
	$title =~ s/ +$//o;
	$title2 = $title;
	$title2 =~ s/<.*?>//go;
	$titles{$fun} = $title2;
	$titles2fun{$title2} = $fun;
	print OUTFILE "<title>$title</title>\n\n";
	print OUTFILE "<table width=\"100%\" border=\"0\" cellspacing=\"0\"\n";
	print OUTFILE "cellpadding=\"0\" bgcolor=\"#CCCCCC\">\n<tr>\n";
	print OUTFILE "<td width=\"50%\"><tt>$fun</tt></td>\n";
	print OUTFILE "<td width=\"50%\"><div align=\"right\"><font face=\"Times New Roman, Times, serif\">Library section $topic</font></div>\n</td></tr></table>\n";
	print OUTFILE "<h1>$title</h1>\n\n";
    } elsif ($type eq "description") {
	print OUTFILE "<h2>DESCRIPTION:</h2>\n<p>\n", sub4($text), "\n\n";

    } elsif ($type eq "usage") {
	## new-style usage is not catered for here: no examples seen
	## it will be passed through verbatim.
	if ($text =~ /^\s*<s-old-style-usage>\s*(.*?)\s*<\/s-old-style-usage>/s) {
	    $text = $1;
	}
	print OUTFILE "<h2>USAGE:</h2>\n<pre>\n", verbsub($text),
	"\n</pre>\n\n";

    } elsif ($type eq "args" || $type eq "args-optional"
	     || $type eq "args-required" ) {
	print OUTFILE "</dl>\n\n" if $InArgs;
	print OUTFILE "<h2>ARGUMENTS:</h2>\n<dl>\n" if $type eq "args";
	print OUTFILE "<h2>REQUIRED ARGUMENTS:</h2>\n<dl>\n"
	    if $type eq "args-required";
	print OUTFILE "<h2>OPTIONAL ARGUMENTS:</h2>\n<dl>\n"
	    if $type eq "args-optional";
	$InArgs = 1;
	## some files seem to have text before args
	my $pre = $text =~ /^\s*<s-arg/;
	if($pre != 1) {
	    my $pre;
	    if($text =~ s/^\s*(.*?)(<s-arg)/$2/s) {
		$pre = $1;
	    } else {
		## There are no <s-arg> groups!
		$pre = $text;
		$text = "";
	    }
	    print OUTFILE sub4($pre), "\n";
	}
	process_sub_groups($text, "arg");

    } elsif ($type eq "value") {
	print OUTFILE "<h2>VALUE:</h2>\n<dl>\n";
	my $t;
	my @groups = split /<s-return-component /, $text;
	foreach $t (@groups) {
	    if ($t =~ /name=\"(.*?)\">\s*(.*)<\/s-return-component>/s) {
		my $name=$1;
		$t = $2;
		print OUTFILE "<dt><b>$1</b></dt><dd>\n", sub4($t),
		"</dd>\n";
	    } else {
		print OUTFILE sub4($t), "\n";
	    }
	}
	print OUTFILE "</dl>\n";

    } elsif ($type eq "details") {
	print OUTFILE "<h2>DETAILS:</h2>\n<p>\n", sub4($text), "\n\n";

    } elsif ($type eq "see") {
 	print OUTFILE "<h2>SEE ALSO</h2>\n", makelinks($text), "\n\n";

    } elsif ($type eq "examples") {
	print OUTFILE "<h2>EXAMPLES:</h2>\n<pre>";
	process_sub_groups($text, "example");
	print OUTFILE "</pre>\n";

    } elsif ($type eq "note" || $type eq "notes") {
	print OUTFILE "<h2>uc($type):\n", sub4($text), "\n\n";

    } elsif ($type eq "bugs") {
 	print OUTFILE "<h2>BUGS:</h2>\n", sub4($text), "\n\n";

    } elsif ($type eq "references") {
	print OUTFILE "<h2>REFERENCES:</h2>\n", inref(sub4($text)), "\n\n";

    } elsif ($type =~ /^section\s+name\s*=\s*(.*)/) {
	my $name = $1;
	$name =~ s/\s*\"(.*?)\"/$1/o;
	$name =~ s/^\s*//o;
	if ($name =~ /^reference$/io) {
	    print OUTFILE "<h2>REFERENCES:</h2>\n", inref(sub4($text)), "\n\n";
	} elsif ($name =~ /^source$/io) {
	    print OUTFILE "<h2>SOURCE:</h2>\n", inref(sub4($text)), "\n\n";
	} else {
	    $name = uc($name);
	    $name =~ s/^([a-z])/\U$1/;
	    print OUTFILE "<h2>$name:</h2>\n", sub4($text), "\n\n";
	}

    } elsif ($type eq "docclass") {
	print OUTFILE "<!-- docclass is $text -->\n";

    } elsif ($type eq "warnings") {
	process_sub_groups($text, "warning");

    } elsif ($type eq "warning") {
	print OUTFILE "<h2>WARNING:</h2>\n", sub4($text), "\n\n";

    } elsif ($type eq "background") {
	print OUTFILE "<h2>BACKGROUND:</h2>\n", sub4($text), "\n\n";

    } elsif ($type eq "side-effects") {
	print OUTFILE "<h2>SIDE EFFECTS:</h2>\n", sub4($text), "\n\n";

    } elsif ($type eq "author") {
	print OUTFILE "<h2>AUTHOR:</h2>\n", sub4($text), "\n\n";

    } elsif ($type eq "keywords") {
	process_sub_groups($text, "keyword");

    } else {
	warn "unknown SGML entity `$type' in file `$nrfile'\n";
	print OUTFILE "%type:\n%$text\n";
    }
}

sub process_sub_groups{
    my $text = $_[0];
    my $topic = $_[1];

    while(length($text) > 0) {
	($type, $body, $text) = get_group($text);
	die "invalid subgroup" unless $type =~ /^$topic/;
	process_sub_group($type, $body);
    }
}

sub process_sub_group
{
    my $topic = $_[0];
    my $text = $_[1];
    my $example = 0;

    $text =~ s/^\n*//;
    $text =~ s/\n*$//;
    if ($type eq "topic") {
	$text =~ s/^\s*//; $text =~ s/\s*$//;
	if($nalias == 0) {
	    $nalias = 1;
	    $fun = $text;
	    $funhtml = $fun . ".html";
	    $funhtml =~ s/</_/g;
	    open OUTFILE, "> $funhtml" or die
		"Can't open file '$funhtml' for writing\n";
	    $htmlfiles{$fun} = "$funhtml";
	    header($fun);
	    print OUTFILE "\n";
	    $ahtmlfiles{$fun} = "$funhtml";
	} else {
	    push @aliases, $text;
	    &alias($text);
	    $ahtmlfiles{$text} = "$funhtml";
	}
    } elsif ($type eq "warning") {
	print OUTFILE "<h2>WARNING:</h2>\n", sub4($text), "\n\n";
    } elsif ($type eq "keyword") {
	print OUTFILE "<!-- keyword $text -->\n";
    } elsif ($type =~ /^example/) {
	if ($nexample++ > 0) { print OUTFILE "\n"; }
	print OUTFILE verbsub($text), "\n";
    } elsif ($type =~ /^arg/) {
	$type =~ /^arg\s+name\s*=\s*(.*)/;
	my $name = $1;
	$name =~ s/\s*\"(.*?)\"/$1/o;
	$name =~ s/\s*(\w*)\s*/$1/o;
#	$name =~ s/\.\.\./\\dots/;
	print OUTFILE "<dt><b>$name</b></dt><dd>\n", sub4($text),
	"\n</dd>\n";
    } else {
	warn "unknown SGML entity `$type' in file `$nrfile'\n";
	print OUTFILE "%type:\n%$text\n";
    }
}

sub inref {
    my $text = $_[0];
    $text =~ s/([0-9])-([0-9])/$1&ndash;$2/go;
    $text;
}

sub verbsub {
    my $text = $_[0];
    $text =~ s/&#38;/&amp;/go;
    $text =~ s/</&lt;/go;
    $text =~ s/>/&gt;/go;
    $text;
}

sub sub4 {
    my $text = $_[0];

    ## These tags can have id's
    $text =~ s+<s-expression(.*?)>(.*?)</s-expression>+<tt>$2</tt>+go;
    $text =~ s+<s-object(.*?)>(.*?)</s-object>+<tt>$2</tt>+go;
    $text =~ s+<s-function(.*?)>(.*?)</s-function>+<tt>$2</tt>+go;
    $text =~ s+<s-class(.*?)>(.*?)</s-class>+<tt>$2</tt>+go;
    $text =~ s+<s-method(.*?)>(.*?)</s-method>+<tt>$2</tt>+go;
    $text =~ s+<s-dataset(.*?)>(.*?)</s-dataset>+<tt>$2</tt>+go;
    ## I have never seen these used
    $text =~ s+<s-expref(.*?)>(.*?)</s-expref>+<tt>$2</tt>+go;
    $text =~ s+<s-objref(.*?)>(.*?)</s-objref>+<tt>$2</tt>+go;
    $text =~ s+<s-function-ref(.*?)>(.*?)</s-function-ref>+<tt>$2</tt>+go;
    $text =~ s+<s-clsref(.*?)>(.*?)</s-clsref>+<tt>$2</tt>+go;
    $text =~ s+<s-mthref(.*?)>(.*?)</s-mthref>+<tt>$2</tt>+go;
    $text =~ s+<s-datref(.*?)>(.*?)</s-datref>+<tt>$2</tt>+go;
    $text =~ s+<s-chpref(.*?)>(.*?)</s-chpref>+<tt>$2</tt>+go;

    $text =~ s+<it>(.*?)</it>+<em>$1</em>+go;
    $text =~ s+<sl>(.*?)</sl>+<em>$1</em>+go;
    $text =~ s+<em>(.*?)</em>+<em>$1</em>+go;
    # not clear what to do with <sf>
    $text =~ s+<sf>(.*?)</sf>+<b>$1</b>+go;
    $text =~ s+<bf>(.*?)</bf>+<b>$1</b>+go;
#    $text =~ s+<url>(.*?)</url>+<tt>$1</tt>+go;
    $text =~ s/&#38;/&amp;/go;
    $text =~ s/&rsqb;/]/go;
    $text =~ s/&lsqb;/[/go;
    $text =~ s/<url url\s*=\s*\"(.*?)\">/<a href=\"$1\"><tt>$1<\/tt><\/a>/gso;
# process <descrip>
    $text =~ s+<descrip>+<dl>+go;
    $text =~ s+</descrip>+</dl>+go;
    $text =~ s+<descrip>(.*?)</descrip>+<dl>$1</dl>+go;
    $text =~ s+<tag/(.*?)/(.*?)\n?(?=<tag|</dl)+<dt><tt>$1</tt></dt>\n<dd>$2</dd>\n\n+gso;
    $text;
}

sub makelinks {
    my $text = $_[0];

#    $text =~ s+<s-function name="(.*?)">(.*?)</s-function>+<a href="$2.html"}><tt>$2</tt></a>+g;
    while($text =~ s+<s-function name="(.*?)">(.*?)</s-function>+<a foobar}><tt>$2</tt></a>+) {
        if(defined $libfuns{$2}) {
	    $replace = "href=\"" . $2 . ".html" . "\"";
	} else {
	    $nlink++;
	    $replace = mklink($2);
	}
	$text =~ s/foobar/$replace/;
    }
    $text;
}

## ---------------------------- hhp section -------------------------

sub make_hhp {
    my $topic = $_[0];

    print "making HHW project file\n";
    open hhpfile, ">$topic.hhp"
	or die "Couldn't open the chm project file\n";
    print hhpfile "[OPTIONS]\n",
    "Contents file=$topic.hhc\n",
    "Compiled file=$topic.chm\n",
    "Display compile progress=No\n",
    "Index file=$topic.hhk\n",
    "Binary Index=YES\n",
    "Full-text search=Yes\n",
    "\n\n[FILES]\n";
    foreach $f (sort values %htmlfiles) {
	print hhpfile "$f\n";
    }
    close hhpfile;
}

sub make_hhk {
    my $topic = $_[0];

    open hhkfile, ">$topic.hhk"
	or die "Couldn't open the chm hhk file";
    print hhkfile <<END;
<html>
<body>
<!-- Sitemap 1.0 -->
<object type="text/site properties">
<param name="SiteType" value="index">
</object>
<ul>
END
    foreach $fun (sort keys %ahtmlfiles) {
	print hhkfile
	    "<li><object type=\"text/sitemap\">\n",
	    "<param name=\"Name\" value=\"",
	    $fun, ":      ", $titles{$fun},
	    "\">\n<param name=\"Local\" value=\"",
	    $ahtmlfiles{$fun},
	    "\">\n</object>\n";
    }
    print hhkfile "</ul>\n</body></html>\n";
    close hhkfile;
}

sub foldorder {uc($a) cmp uc($b) or $a cmp $b;}


sub make_toc {
    my $topic = $_[0];

    open tocfile, "> $topic.hhc"
	or die "Couldn't open the chm toc file";
    print tocfile
	"<html><body>\n<ul>\n";
    print tocfile
	"<li> <object type=\"text/sitemap\">\n",
	"<param name=\"Name\" value=\"Library $topic:\">\n",
	"</object>\n";
    print tocfile "<ul>\n";   # contents of a book
    foreach $title (sort foldorder keys %titles2fun) {
	print tocfile
	    "<li> <object type=\"text/sitemap\">\n",
	    "<param name=\"Name\" value=\"$title\">\n",
	    "<param name=\"Local\" value=\"$htmlfiles{$titles2fun{$title}}\">\n",
	    "</object>\n";
    }
    print tocfile "</ul>\n";  # end of a book
    print tocfile "</ul>\n</body></html>\n";
    close tocfile;
}

sub mklink {
    "onclick=\"findlink('" . $_[0] . "')\" " .
	"style=\"text-decoration: underline; color: blue; cursor: hand\"";
}

sub JScript {
    print OUTFILE <<END;
<script Language="JScript">
function findlink(fn) {
var Y, link;
Y = location.href.lastIndexOf("\\\\") + 1;
link = location.href.substring(0, Y);
link = link + "..\\\\..\\\\cmd\\\\Splus.chm::/" + fn + ".html";
location.href = link;
}
</script>
END
}

### Local Variables: ***
### mode: perl ***
### perl-indent-level: 4 ***
### End: ***
