#!/usr/local/bin/perl -s

# Generate NROFF source for text representation of the PNG spec
# Formatting follows Internet Draft (RFC) requirements
# Usage: makenroff [-rfc] [-w3c] <master >output

# Write nroff header
print ".de PF\n";     # PF macro changes page length to 63 lines
print ".pl 63v\n"; 
print ".wh 8\n";      # clear the trap
print "..\n"; 
print ".de PG\n";     # PG macro sets a trap to change page length
print ".wh 8 PF\n";   # after we have written the header for page 2.
print ".nr FM 5v\n";  # footer margin (last text line to page bottom)
print ".wh 9\n";      # clear the trap
print "..\n"; 
print ".wh 9 PG\n"; 
print ".pl 60v\n";    # page 1 has only 60 lines to footer
print ".po 0\n";      # page offset (left margin) is zero
print ".ll 7.2i\n";   # line length
print ".lt 7.2i\n";   # line length of headers and footers
print ".nr LL 7.2i\n";   # line length register for MS macros
print ".nr LT 7.2i\n";   # line length register of headers and footers
# right and center footers are set here, document supplies the rest
print ".ds RF FORMFEED[Page%]\n"; 
print ".ds CF\n"; 
print ".hy 0\n";        # do not hyphenate anything
print ".ad l\n";        # adjust left, leave ragged right margin
print ".in 0\n";        # indent

$Chapter = 0;
$Section = 0;
$Paragraph = 0;

$skip_blank = 1;
$saving_pre_text = 0;
$if_nest_ok = 0;
$if_nest_fail = 0;
$li_level = 0;
$escape_leading_dots = 1;

while (<STDIN>) {
	&process_line($_);
}

exit;

sub process_line {
	local($line) = @_;

	# Handle conditional exclusion commands, doing nesting correctly
	local($skip_this_line) = 0;

	if ($line =~ /^<!-- IF RFC -->/i) {
	    if ($rfc && !$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- IF !RFC -->/i) {
	    if (!$rfc && !$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- IF W3C -->/i) {
	    if ($w3c && !$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- IF !W3C -->/i) {
	    if (!$w3c && !$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- ENDIF -->/i) {
	    if ($if_nest_fail) { $if_nest_fail--; }
	    else { $if_nest_ok--; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- NROFF/i) {
	    if (!$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	    $escape_leading_dots = 0;
	}
	if ($line =~ /^NROFF -->/i) {
	    if ($if_nest_fail) { $if_nest_fail--; }
	    else { $if_nest_ok--; }
	    $skip_this_line = 1;
	    $escape_leading_dots = 1;
	}
	if ($line =~ /^<!-- TEX/i) {
	    $if_nest_fail++;
	    $skip_this_line = 1;
	}
	if ($line =~ /^TEX -->/i) {
	    $if_nest_fail--;
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- IF !TEX -->/i) {
	    if (!$if_nest_fail) { $if_nest_ok++; }
	    else { $if_nest_fail++; }
	    $skip_this_line = 1;
	}
	if ($line =~ /^<!-- IF HTML -->/i) {
	    $if_nest_fail++;
	    $skip_this_line = 1;
	}

	if ($if_nest_fail || $skip_this_line) {
	    if ($if_nest_fail < 0 || $if_nest_ok < 0) {
		die "Bogus if/endif matching\n";
	    }
	    return;
	}

	# handle inclusion
	if ($line =~ /<!-- INCLUDE (\S+) -->/i) {
	    if (open(INPUT2, $1)) {
		while (<INPUT2>) {
		    &process_line($_);
		}
		close INPUT2;
	    } else {
		warn "Couldn't open $1: $!\n";
	    }
	    return;
	}

	# handle head/foot string setting
	if ($line =~ /<!-- HEADFOOT (..) (.+) -->/i) {
            $def = $1;
            $defined_value = $2;
	    print STDOUT ".ds $def $defined_value\n";
            warn "DEFINE $def=`$defined_value'" if $debug;
            return;
	}

        # Remove any leading blanks ahead of "<"
        $line =~ s|^[ ]+<|<|;

        # Double up backslashes
	$line =~ s|\\|\\\\|g;

	# Escape leading dots if not in an NROFF section
	if ($escape_leading_dots) {
	    $line =~ s|^\.|\\\&.|;
	}

	# handle H1 tag
	if ($line =~ /<H1>/i) {
	    print "\n.ce\n";
	}

	# handle H2 tag
	if ($line =~ /<H2>/i) {
	    # somewhat arbitrary: do not start chapter in bottom 12 lines
	    print ".ne 12\n";
	    print ".in 3\n";
	    print ".ti -3\n";
	    if ($line =~ /<.+NAME="([^>]+)">/i) {
		$Chapter++;
		$Section = 0;
		$Paragraph = 0;
		if ($PN) {$line = "<h2>s\|!$1!\|!\\n(PN!\|i; #</h2>\n";}
		else { $line =~ s|(<H2>[^>]+>)|$1$Chapter. |i; }
	    }
	}

	# handle H3 tag
	if ($line =~ /<H3>/i) {
	    print ".ne 4\n";
	    print ".in 6\n";
	    print ".ti -3\n";
	    if ($line =~ /<.+NAME="([^>]+)">/i) {
		$Section++;
		$Paragraph = 0;
		if ($PN) {$line = "<h3>s\|!$1!\|!\\n(PN!\|i; #</h3>\n";}
		else { $line =~ s|(<H3>[^>]+>)|$1$Chapter.$Section. |i;}
	    }
	}

	# handle H4 tag
	if ($line =~ /<H4>/i) {
	    print ".ne 4\n";
	    print ".in 9\n";
	    print ".ti -3\n";
	    if ($line =~ /<.+NAME="([^>]+)">/i) {
		$Paragraph++;
		if ($PN) {$line = "<h4>s\|!$1!\|!\\n(PN!\|i; #</h4>\n";}
		else { $line =~ s|(<H4>[^>]+>)|$1$Chapter.$Section.$Paragraph. |i;}
	    }
	}

	# handle DL, DT, DD tags
        if ($line =~ /<DL>/i) {
	    print ".in +3\n";
	}
	if ($line =~ /<DT>/i) {
            if ($skip_blank == 0) {print STDOUT "\n" ; }
            $skip_blank = 1;
	    print ".ne 3\n";
	    print ".ti -3\n";
        }
        if ($line =~ /<DD>/i) {
            if (! $skip_blank) {print STDOUT ".br\n" ; }
            $skip_blank = 1;
        }
	$line =~ s|<D[DLT]>[ ]*||i;
        if ($line =~ /<\/DL>/i)  {
	    print ".in -3\n";
            if ($skip_blank == 0) {print STDOUT "\n" ; }
            $skip_blank = 1;
        }

	# handle PRE tag
        if ($line =~ /<PRE>/i){
	    if ($skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	    print ".in +3\n";
	    print ".nf\n";
	    $line =~ s|<PRE>||i;
	    $saving_pre_text = 1;
	}
	
	# handle /PRE tag
        if ($line =~ /<\/PRE>/i){
	    $line =~ s|</PRE>||i;
	    $saving_pre_text = 0;
	    &dump_pre_text;
	    print ".in -3\n";
	    print ".fi\n";
	    if ($skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	}
	
	# handle UL tag
        if ($line =~ /<UL>/i){
	    $line =~ s|<UL>|.in +6|i;
	    $li_level++;
	    if ($li_level == 1 && $skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	}

	# handle /UL tag
        if ($line =~ /<\/UL>/i){
	    $line =~ s|</UL>||i;
	    print ".in -6\n";
	    if ($li_level == 1 && $skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	    $li_level--;
	}

	# handle OL tag
        if ($line =~ /<OL>/i){
	    $line =~ s|<OL>|.in +6|i;
	    $li_level++;
	    if ($li_level == 1 && $skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	}

	# handle /OL tag
        if ($line =~ /<\/OL>/i){
	    $line =~ s|</OL>||i;
	    print ".in -6\n";
	    if ($li_level == 1 && $skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	    $li_level--;
	}

	# handle LI tag
        if ($line =~ /<LI>/i){
	    $line =~ s|<LI>[ \t]*| * |i;
	    print ".ti -3\n";
        }

	# handle P tag
        if ($line =~ /<P>/i){
	    $line =~ s|<P>||i;
	    if ($skip_blank == 0) {print STDOUT "\n" ; }
	    $skip_blank = 1;
	}

	# handle BR tag
        if ($line =~ /<BR>/i){
	    print ".br\n";
	}

	# ignore TITLE line
        if ($line =~ /<TITLE>/i){
	    return;
	}

        # remove any remaining HTML tags, including other !-- commands
	# but distinguish whether line was all-blank beforehand

        $line =~ s|^[ \t]*$|==BLANK==|;

        $line =~ s|[ ]+<[^>]+>[ ]+| |g;
        $line =~ s|<[^>]+>||g;

# only need these if html tags are continued across lines
#        $line =~ s|<[^<]+$||;
#        $line =~ s|^[^>]+>||;

	# Handle html entities
        $line =~ s|&amp;|&|g;
        $line =~ s|&gt;|>|g;
        $line =~ s|&lt;|<|g;
        $line =~ s|&copy;|(c)|g;

	# Suppress any line that contains only HTML tags.
        $line =~ s|^[ ]+$||;
        if ($line =~ /^$/) {return;}

	# Restore any line that was really all-blank
        $line =~ s|^==BLANK==$||;

	# We suppress all but the first of successive blank lines.
        if (($line =~ /./) || ($skip_blank == 0)) {
	    if ($saving_pre_text) {
		push(@saved_pre_text, $line);
	    } else {
		print STDOUT $line;
	    }
	}
        if ($line =~ /^$/) {$skip_blank = 1;}
        else {$skip_blank = 0;}
}


# Dump out <PRE> text, adding .ne N lines to prevent the block from
# being broken across pages.  Blocks larger than 15 lines (a somewhat
# arbitrary threshold) are allowed to be split at blank lines, however.

sub dump_pre_text {
    if (@saved_pre_text) {
	$first_nb = 0;
	if (@saved_pre_text > 15) {
	    for ($i = 0; $i <= $#saved_pre_text; $i++) {
		if ($saved_pre_text[$i] eq "\n") {
		    $num_pre_lines = $i - $first_nb;
		    if ($num_pre_lines > 1) {
			print ".ne $num_pre_lines\n";
		    }
		    while ($first_nb <= $i) {
			print STDOUT $saved_pre_text[$first_nb++];
		    }
		}
	    }
	}
	$num_pre_lines = @saved_pre_text - $first_nb;
	if ($num_pre_lines > 1) {
	    print ".ne $num_pre_lines\n";
	}
	while ($first_nb < @saved_pre_text) {
	    print STDOUT $saved_pre_text[$first_nb++];
	}
	$#saved_pre_text = -1;
    }
}
