#!/usr/bin/perl
# SPDX-License-Identifier: MIT
#
#	man2html (yet another one)
#	written by Jan Engelhardt, 2011
#
#	Most of the man2html converters on the net are either totally
#	outdated or more complex than I needed.

use Text::CSV_XS;
use strict;

my $csv = Text::CSV_XS->new({eol => $/, sep_char => ' '});
my $mode = 0;
my @index;

while (<>) {
	chomp($_);
	my($cmd) = split(/\s/, $_);

	if ($cmd eq ".\\\"" || $cmd eq ".RS" || $cmd eq ".RE") {
		;
	} elsif ($cmd eq ".TH") {
		header($_);
	} elsif ($cmd eq ".SH") {
		p_end();
		push(@index, [1, substr($_, 4)]);
		print "<h1><a name=\"", $#index, "\"></a>",
		      ehtml(substr($_, 4)), "</h1>\n\n";
	} elsif ($cmd eq ".SS") {
		p_end();
		push(@index, [2, substr($_, 4)]);
		print "<h2><a name=\"", $#index, "\"></a>",
		      ehtml(substr($_, 4)), "</h2>\n\n";
	} elsif ($cmd eq ".br") {
		print "<br />\n";
	} elsif ($_ eq ".B") {
		p_start();
		chomp(my $text = <>);
		print "<b>", ehtml($text), "</b> ";
		tp_adv();
	} elsif ($cmd eq ".B") {
		p_start();
		print "<b>", ehtml(stripq(substr($_, 3))), "</b> ";
		tp_adv();
	} elsif ($cmd eq ".BR") {
		p_start();
		my(undef, $text1, $text2) = csv_split($_);
		print "<b>", ehtml($text1), "</b>", ehtml($text2), " ";
		tp_adv();
	} elsif ($cmd eq ".BI") {
		p_start();
		my(undef, $text1, $text2) = csv_split($_);
		print "<b>", ehtml($text1), "</b><i>", ehtml($text2), "</i> ";
		tp_adv();
	} elsif ($cmd eq ".IR") {
		p_start();
		my(undef, $text1, $text2) = csv_split($_);
		print "<i>", ehtml($text1), "</i>", ehtml($text2), " ";
		tp_adv();
	} elsif ($_ eq ".I") {
		p_start();
		chomp(my $text = <>);
		print "<i>", ehtml($text), "</i> ";
		tp_adv();
	} elsif ($cmd eq ".I") {
		p_start();
		print "<i>", ehtml(stripq(substr($_, 3))), "</i> ";
		tp_adv();
	} elsif ($cmd eq ".P" || $cmd eq ".PP") {
		p_end();
		pp_start();
	} elsif ($cmd eq ".TP") {
		p_end();
		tp_start();
	} elsif ($cmd eq ".IP") {
		p_end();
		ip_start();
	} elsif ($cmd eq ".nf") {
		print "<table><tr><td class=\"pre\">";
	} elsif ($cmd eq ".fi") {
		print "</td></tr></table>";
	} elsif ($cmd eq ".ns") {
		tp_adv();
	} elsif ($_ ne "") {
		p_start();
		print ehtml($_), "\n";
		tp_adv();
	} else {
		print "<br />\n<br />\n";
	}
}

p_end();

if (scalar(@index) > 0) {
	my $level = 0;
	print "<h1>Index</h1>\n\n";
	for (my $idx = 0; $idx <= $#index; ++$idx) {
		my $entry = $index[$idx];
		if ($level < $entry->[0]) {
			print "<ol>\n";
			++$level;
		} elsif ($level > $entry->[0]) {
			print "</ol>\n";
			--$level;
		}
		print "<li><a href=\"#$idx\">", ehtml($entry->[1]),
		      "</a></li>";
	}
	print "</ol>\n";
}

print "</body>\n";
print "</html>\n";

sub csv_split
{
	my $a = shift @_;
	if ($csv->parse($a)) {
		return $csv->fields();
	}
}

sub p_end
{
	if ($mode > 0) {
		print "</p>\n\n";
		$mode = 0;
	}
}

sub p_start
{
	if ($mode == 0) {
		pp_start();
	}
}

sub pp_start
{
	if ($mode != 1) {
		p_end();
		print "<p class=\"pp j\">";
		$mode = 1;
	}
}

sub tp_start
{
	if ($mode != 2) {
		p_end();
		print "<p class=\"tp1\">";
		$mode = 2;
	}
}

sub tp_adv
{
	if ($mode == 2) {
		ip_start();
	}
}

sub ip_start
{
	if ($mode != 3) {
		p_end();
		print "<p class=\"tp2 j\">";
		$mode = 3;
	}
}

sub ehtml
{
	my $s = shift @_;

	# unman
	$s =~ s/\\-/-/gs;

	# html
	$s =~ s/&/&amp;/gs;
	$s =~ s/</&lt;/gs;
	$s =~ s/>/&gt;/gs;
	if ($_[1]) {
		$s =~ s/\"/&quot;/gs;
	}

	# unman2
	$s =~ s{\\fI(.*?)\\f[RP]}{<i>$1</i>}gs;
	$s =~ s{\\fB(.*?)\\f[RP]}{<b>$1</b>}gs;

	return $s;
}

sub stripq
{
	my $s = shift @_;
	$s =~ s/^\s+//gs;
	$s =~ s/^\"(.*)\"$/$1/gs;
	return $s;
}

sub header
{
	my(undef, $name, $section, $date, $author, $title) =
		csv_split(shift @_);
	print "<html>\n";
	print "<head>\n";
	print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
	print "<title>", ehtml($name), "(", ehtml($section), ") - ", ehtml($title), "</title>\n";
	print <<EOF;
<style type="text/css">
h1 { font-size: 100%; margin-top: 2em; margin-bottom: 0; }
h2 { font-size: 100%; margin-left: 4ex; margin-top: 2em; margin-bottom: 0; }
p { margin-top: 1ex; margin-bottom: 1ex; }
.j { text-align: justify; }
.pp { margin-left: 8ex; }
.tp1 { margin-left: 12ex; }
.tp2 { margin-left: 16ex; }
.pre { font-family: monospace; }
</style>
</head>

<body>

<table width="98%">
	<tr>
EOF
	print "\t\t<td>", ehtml($name), "(", ehtml($section), ")</td>\n";
	print "\t\t<td align=\"center\">", ehtml($author), "</td>\n\n";
	print "\t\t<td>", ehtml($name), "(", ehtml($section), ")</td>\n\n";
	print "\t\t</tr>\n</table>\n\n";
}
