Blob Blame History Raw
#
#  Html2Html.pm
#
#  $Id: Html2Html.pm,v 1.4 2001/08/31 23:09:10 sano Exp $
#
#  Convert parsed linuxdoc-sgml to html.
# 	- Split files; match references, generate TOC and navigation
# 	aids, etc.
#
#  Rules based on html2html.l
#
package LinuxDocTools::Html2Html;

use FileHandle;
use LinuxDocTools::Lang;

# Externally visible variables
$html2html = {};

# Initialize: set splitlevel, extension, images, filename,
#                 filenumber, label, header, footer, toclevel,
#                 tmpbase, debug.
# Usage:
#   &{$html2html->{init}}(split,ext,img,filename,filenum,label,hdr,ftr,toc,tmpbase, debug);
#       split level:	 0 - super page mode
#        		 1 - big page mode
#        		 2 - small page mode
$html2html->{init} = sub {
    $splitlevel = shift;
    SWITCH: {
        $super_page_mode = 0, $big_page_mode = 1, last SWITCH
            if ($splitlevel == 1);
        $super_page_mode = 0, $big_page_mode = 0, last SWITCH
            if ($splitlevel == 2);
    }

    $fileext = shift;
    $use_imgs = shift;
    $firstname = shift;
    $filecount = 1 + shift;
    $lprec = shift;

    $header = shift;
    $footer = shift;

    $toclevel = shift;
    if ($toclevel == -1) {
    	if ($splitlevel == 0) {
		$toclevel = 0;
	} else {
		$toclevel = 2;
	}
    }

    $tmpbase = shift;
    $content_file = $tmpbase . ".content";

    $debug = shift;

    $nextlabel = Xlat ("Next");
    $prevlabel = Xlat ("Previous");
    $toclabel = Xlat ("Contents");
};

# Package variables
$big_page_mode = 0;             # '-2' subsection splitting
$super_page_mode = 1;		# One page vs. page/section
$chapter_mode = 0;              # <article> vs. <report>
$current = "";                  # State of section/subsection/etc.
$filenum = 1;                   # Current output file number
$filecount = 1;
$firstname = "$$";              # Base name for file
$headbuf = "";                  # Buffer for URL's
$fileext = "html";       	# "html" vs. "htm" for 8.3
$in_appendix = 0;               # n.n vs. a.n section numbers
$in_section_list = 0;           # List of sections flag
$language = "";                 # Default English; use '-Lname'
# $lprec{label}                 # Label record
$nextlabel = "";		# Link string
$outfh = STDOUT;		# Output filehandle
$outname = "";			# Output file name
$prevlabel = "";		# Link string
$refname = "";                  # Ref string
$sectname = "";                 # Section name
$secnr = 0;                     # Section count
$ssectname = "";                # Subsection name
$ssecnr = 0;                    # Subsection count
$skipnewline = 0;               # Flag to ignore new line
$toclabel = "";			# Link string
$titlename = "";                # Title of document
$use_imgs = 0;                  # '-img' pictorial links
$urlname = "";                  # Name for url links
$header = "";
$footer = "";
$toclevel = -1;
$tmpbase = "/tmp/sgmltmp" . $$;
$debug = 0;
$content_file = $tmpbase . ".content.init";

# Ruleset
$html2html->{rules} = {};		# Individual parsing rules

$html2html->{rules}->{'^<@@appendix>.*$'} = sub {
    $in_appendix = 1; $secnr = 0; $ssecnr = 0;
};

$html2html->{rules}->{'^<@@url>(.*)$'} = sub {
    $skipnewline = 1; $urlname = $1; $headbuf = qq(<A HREF="$1">);
};

$html2html->{rules}->{'^<@@urlnam>(.*)$'} = sub { 
    $headbuf = $headbuf . "$urlname</A>"; 
};

$html2html->{rules}->{'^<@@endurl>.*$'} = sub {
    $skipnewline = -1; $outfh->print($headbuf); $headbuf = "";
};

$html2html->{rules}->{'^<@@title>(.*)$'} = sub {
    $titlename = $1; &heading(STDOUT); print(STDOUT "<H1>$1</H1>\n\n");
};

$html2html->{rules}->{'^<@@head>(.*)$'} = sub { 
    $skipnewline = 1; $headbuf = $1; 
};

$html2html->{rules}->{'^<@@part>.*$'} = sub { $current = "PART"; };

$html2html->{rules}->{'^<@@endhead>.*$'} = sub {
    SWITCH: {
    $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH 
        if ($current eq "PART");
    $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH 
        if ($current eq "CHAPTER");
    $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH 
        if ($current eq "SECTION");
    $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH 
        if ($current eq "SUBSECT");
    $outfh->print("<H3>$headbuf</H3>\n\n"), last SWITCH;
    }
    $current = ""; $headbuf = ""; $skipnewline = 0;
};

$html2html->{rules}->{'^<@@chapt>(.*)$'} = sub {
    $chapter_mode = 1; $skipnewline = 1; $sectname = $1;
    &start_chapter($sectname);
};

$html2html->{rules}->{'^<@@sect>(.*)$'} = sub {
    $skipnewline = 1; $ssectname = $1;
    if ($chapter_mode) {
        &start_section($ssectname);
    } else {
        $sectname = $ssectname; &start_chapter($ssectname);
    }
};

$html2html->{rules}->{'^<@@ssect>(.*)$'} = sub {
    $skipnewline = 1; $ssectname = $1;
    if (!$chapter_mode) {
        &start_section($ssectname);
    } else {
        $current = ""; $headbuf = $ssectname;
    }
};

$html2html->{rules}->{'^<@@endchapt>.*$'} = sub {
    STDOUT->print("</UL>\n") if ($in_section_list);
    if ($outfh->fileno != STDOUT->fileno) {
        &footing($outfh) if (!$super_page_mode);
        $outfh->close; $outfh = STDOUT;
    }
};

$html2html->{rules}->{'^<@@endsect>.*$'} = sub {
    STDOUT->print("</UL>\n") if (!$chapter_mode && $in_section_list);
    if (($outfh->fileno != STDOUT->fileno) 
           && ((!$chapter_mode) || (!$big_page_mode))) {
        &footing($outfh) if (!$super_page_mode);
        $outfh->close; $outfh = STDOUT;
    }
};

$html2html->{rules}->{'^<@@endssect>.*$'} = sub {
    if (($outfh->fileno != STDOUT->fileno) 
           && (!$chapter_mode) && (!$big_page_mode) && (!$super_page_mode)) {
        &footing($outfh); $outfh->close; $outfh = STDOUT;
    }
};

$html2html->{rules}->{'^<@@enddoc>.*$'} = sub { };

$html2html->{rules}->{'^<@@label>(.*)$'} = sub {
    if (!defined($lprec->{$1})) {
        STDERR->print(qq(html2html: Problem with label "$1"\n)); next;
    }
    if ($skipnewline) {
        $headbuf = sprintf(qq(<A NAME="%s"></A> %s), $1, $headbuf);
    } else {
        $outfh->print(qq(<A NAME="$1"></A> ));
    }
};

$html2html->{rules}->{'^<@@ref>(.*)$'} = sub {
    my $tmp;

    $refname = $1;
    if (!defined($lprec->{$1})) {
        STDERR->print(qq(html2html: Problem with ref "$1"\n));
        $skipnewline++; next;
    }
    SWITCH: {
    $tmp = qq(<A HREF="#$1">), last SWITCH 
        if ($lprec->{$1} == $filenum - 1);
    $tmp = qq(<A HREF="$firstname.$fileext#$1">), last SWITCH
        if ($lprec->{$1} == 0);
    $tmp = qq(<A HREF="$firstname-$lprec->{$1}.$fileext#$1">),
            last SWITCH;
    }
    if ($skipnewline) {
        $headbuf = "$headbuf$tmp";
    } else {
        $headbuf = $tmp;
    }
    $skipnewline++;
};

$html2html->{rules}->{'^<@@refnam>.*$'} = sub { 
    $headbuf = "$headbuf$refname</A>\n"; 
};

$html2html->{rules}->{'^<@@endref>.*$'} = sub {
    if ($skipnewline == 1) {
        $outfh->print($headbuf); $skipnewline = -1;
    } elsif ($skipnewline == 2) {
        $skipnewline--;
    } else {
        STDERR->print("html2html: Problem with endref\n");
        $skipnewline--;
    }
};

# Default parsing rule
$html2html->{defaultrule} = sub {
    $skipnewline++ if ($skipnewline < 0);
    if ($skipnewline) {
        chop; $headbuf = "$headbuf$_";
    } else {
        $outfh->print($_);
    }
};

# Finalize parsing process
$html2html->{finish} = sub {
    # Finish footers
    if ($outfh->fileno != STDOUT->fileno) {
	if (!$super_page_mode) {
          &footing($outfh);
          $outfh->close;
	}
    }
    #
    if ($super_page_mode) {
	if ($toclevel > 0) { STDOUT->print("\n<HR>\n"); }
        $outfh->close if ($outfh->fileno != STDOUT->fileno);
	if ( -r $content_file ) {
          open CONTENT,  "<$content_file"
              or die "Can't open content file\n";
          while (<CONTENT>) {
              STDOUT->print($_);
          }
          close CONTENT;
          unlink $content_file if (! $debug);
	}
    }
    # Finish the TOC; ensure "next" points to the first page.
    &browse_links(STDOUT, 1, 0) if (!$super_page_mode);
    #
    # add Footer
    if ( -r "$footer" ) {
       open FTRFILE, "<$footer" or die "Cannot open footer file\n";
       while (<FTRFILE>) {
         STDOUT->print($_);
       }
       close FTRFILE;
    } else {
       STDOUT->print("</BODY>\n</HTML>\n");
    }
};


###################################################################
# Secondary Functions
###################################################################

# Print standard links
sub browse_links {
    my ($outfh, $myfilenum, $top) = @_;

    return if ($super_page_mode);

    $outfh->print("<HR>\n") unless ($top);

    # NOTE: For pages where a next or prev button isn't appropriate, include
    # the graphic anyway - just don't make it a link. That way, the mouse
    # position of each button is unchanged from page to page.
    # Use the passed myfilenum since filenum may already be incremented

    # Next link (first)
    my $next = $use_imgs  
                  ? qq(<IMG SRC="next.png" ALT="$nextlabel">)
                  : qq($nextlabel);
    $next = qq(<A HREF="$firstname-$myfilenum.$fileext">$next</A>)
       if ($myfilenum < $filecount);
    $next = join "", $next, "\n";
    $outfh->print($next);

    # Previous link
    my $prev = $use_imgs  
                  ? qq(<IMG SRC="prev.png" ALT="$prevlabel">)
                  : qq($prevlabel);
    $prev = join "", qq(<A HREF="$firstname-), ($myfilenum - 2),
                     qq(.$fileext">$prev</A>)
       if ($myfilenum >= 3);
    $prev = join "", $prev, "\n";
    $outfh->print($prev);

    # Table of contents link
    my $toc = $use_imgs 
                ? qq(<IMG SRC="toc.png" ALT="$toclabel">)
                : qq($toclabel);
    $toc = join "", qq(<A HREF="$firstname.$fileext#toc),
                    &section_num($secnr, 0), qq(">$toc</A>)
       if ($outfh->fileno != STDOUT->fileno);
    $toc = join "", $toc, "\n";
    $outfh->print($toc);

    print($outfh "<HR>\n") if ($top);
}

# Print end-of-file markup
sub footing {
    my $outfh = shift;
    &browse_links($outfh, $filenum, 0);
    if ( -r "$footer" ) {
       open FTRFILE, "<$footer" or die "Cannot open footer file\n";
       while (<FTRFILE>) {
         $outfh->print($_);
       }
       close FTRFILE;
    } else {
       $outfh->print("</BODY>\n</HTML>\n");
    }
}

# Print top-of-file markup
sub heading {
    my $outfh = shift; my $match;

    # Emit 3.2 HTML until somebody comes up with a better idea - CdG
    if ( -r "$header" ) {
       open HDRFILE, "<$header" or die "Cannot open header file\n";
       while (<HDRFILE>) {
         $outfh->print($_);
       }
       close HDRFILE;
    } else {
      $outfh->print(
        qq(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n));
      $outfh->print("<HTML>\n<HEAD>\n");
    }
    open VERSFILE, "<$main::DataDir/VERSION" or die "Cannot open version file\n";
    $version = <VERSFILE>;
    close VERSFILE;
    chop $version;
    $outfh->print(
      " <META NAME=\"GENERATOR\" CONTENT=\"LinuxDoc-Tools $version\">\n");

    $outfh->print(" <TITLE>");
    $match = $titlename;
    $match =~ s/<[^>]*>//g;
    $outfh->print($match);
    if ($secnr > 0) {
        $match = $sectname;
        $match =~ s/<[^>]*>//g;
        $outfh->print(": $match");
    }
    if ($ssecnr > 0) {
        $match = $ssectname;
        $match =~ s/<[^>]*>//g;
        $outfh->print(": $match");
    }
    $outfh->print("</TITLE>\n");

    if (!$super_page_mode) {
      #
      #  <LINK> Information for next, previous, contents, etc...
      #
      $outfh->print(qq( <LINK HREF="$firstname-$filenum.$fileext" REL=next>),"\n")
         if ($filenum < $filecount);
      my $prev;
      $prev = join "", qq( <LINK HREF="$firstname-), ($filenum - 2),
                     qq(.$fileext" REL=previous>)
	 if ($filenum >= 3);
      $outfh->print($prev,"\n");

      #
      #  Table of contents link
      #
      my $toc ;
      $toc = join "", qq( <LINK HREF="$firstname.$fileext#toc),
                    &section_num($secnr, 0), qq(" REL=contents>)
	if ($outfh->fileno != STDOUT->fileno);
      $outfh->print($toc,"\n");
    } # (!$super_page_mode)

    $outfh->print("</HEAD>\n<BODY>\n");
    &browse_links($outfh, $filenum, 1);
}

# Return the section and subsection as a dotted string
sub section_num {
    my ($sec, $ssec) = @_;
    my $l = "A";

    if ($in_appendix) {
        $sec--;
        while ($sec) { $l++; $sec--; }
        return("$l.$ssec") if ($ssec > 0);
        return("$l");
    } else {
        return("$sec.$ssec") if ($ssec > 0);
        return("$sec");
    }
}

# Create a chapter head; start a new file, etc.
sub start_chapter {
    my $sectname = shift;

    if (!$super_page_mode && $outfh->fileno != STDOUT->fileno) {
        &footing($outfh); $outfh->close;
    }
    $current = "SECTION"; $secnr++; $ssecnr = 0;
    if ($super_page_mode) {
        $outname = $content_file;
        $outfh = new FileHandle ">>$outname"
            or die qq(html2html: Fatal: Could not open file "$outname"\n);
        if ($toclevel > 0) {
          $headbuf = sprintf(
                             qq(<A NAME="s%s">%s.</A> <A HREF="#toc%s">%s</A>),
                             &section_num($secnr, 0), &section_num($secnr, 0),
                             &section_num($secnr, 0),
                             $sectname);
          STDOUT->printf(
            qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s#s%s">%s</A></H2>\n\n),
               &section_num($secnr, 0), &section_num($secnr, 0),
               "$firstname.$fileext", &section_num($secnr, 0), $sectname);
        } else {
          $headbuf = sprintf(
                             qq(<A NAME="s%s">%s. %s</A>),
                             &section_num($secnr, 0), &section_num($secnr, 0),
                             $sectname);
	}
    } else {
        $outname = "$firstname-$filenum.$fileext"; $filenum++;
        $outfh = new FileHandle ">$outname"
            or die qq(html2html: Fatal: Could not open file "$outname"\n);
        &heading($outfh);
        if ($toclevel > 0) {
          $headbuf = sprintf(
                             qq(<A NAME="s%s">%s.</A> <A HREF="%s#toc%s">%s</A>),
                             &section_num($secnr, 0), &section_num($secnr, 0),
                             "$firstname.$fileext", &section_num($secnr, 0),
                             $sectname);
          STDOUT->printf(
            qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s">%s</A></H2>\n\n),
               &section_num($secnr, 0), &section_num($secnr, 0),
               $outname, $sectname);
        } else {
          $headbuf = sprintf(
                             qq(<A NAME="s%s">%s. %s</A>),
                             &section_num($secnr, 0), &section_num($secnr, 0),
                             $sectname);
	}
    }
    $in_section_list = 0;
}

# Create a section; start a new file, etc.
sub start_section {
    my $ssectname = shift;
    
    $current = "SUBSECT"; $ssecnr++;
    if ($toclevel > 1) {
       if (!$in_section_list) {
           STDOUT->print("<UL>\n"); $in_section_list = 1;
       }
    }
    if ($super_page_mode) {
	if ($outfh->fileno != STDOUT->fileno && !$chapter_mode) {
	    $outfh->close;
	}
        $outname = $content_file;
        $outfh = new FileHandle ">>$outname"
            or die qq(html2html: Fatal: Could not open file "$outname"\n);
       if ($toclevel > 1) {
          $headbuf = sprintf(qq(<A NAME="ss%s">%s</A> <A HREF="#toc%s">%s</A>\n),
                                &section_num($secnr, $ssecnr),
                                &section_num($secnr, $ssecnr),
                                &section_num($secnr, $ssecnr),
                                $ssectname);
          STDOUT->printf(
            qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
                   &section_num($secnr, $ssecnr), 
                   &section_num($secnr, $ssecnr), 
                   "$firstname.$fileext",
                   &section_num($secnr, $ssecnr), 
                   $ssectname);
       } else {
          $headbuf = sprintf(qq(<A NAME="ss%s">%s %s</A>\n),
                                &section_num($secnr, $ssecnr),
                                &section_num($secnr, $ssecnr),
                                $ssectname);
       }
    } else {
        if (!$big_page_mode) {
            if ($outfh->fileno != STDOUT->fileno) {
                &footing($outfh); $outfh->close;
            }
            $outname = "$firstname-$filenum.$fileext"; $filenum++;
            $outfh = new FileHandle ">$outname"
                or die qq(html2html: Fatal: Could not open file "$outname"\n);
            heading($outfh);
    
            # Since only one section is on any page, 
            # don't use # so that when we
            # jump to this page, we see the browse 
            # links at the top of the page. 
            if ($toclevel > 1) {
               $headbuf = sprintf("%s <A HREF=\"%s#toc%s\">%s</A>",
                                  &section_num($secnr, $ssecnr), 
            			  "$firstname.$fileext",
                                  &section_num($secnr, $ssecnr), 
                                  $ssectname);
               STDOUT->printf(
                   qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s">%s</A>\n),
                   &section_num($secnr, $ssecnr),
                   &section_num($secnr, $ssecnr),
                   $outname, $ssectname);
            } else {
               $headbuf = sprintf("%s %s</A>",
                                  &section_num($secnr, $ssecnr), 
                                  $ssectname);
	    }
        } else {
            # Since many sections are on one page, we need to use #
            if ($toclevel > 1) {
               $headbuf = sprintf(
                     qq(<A NAME="ss%s">%s</A> <A HREF="%s#toc%s">%s</A>\n),
                               &section_num($secnr, $ssecnr),
                               &section_num($secnr, $ssecnr),
		               "$firstname.$fileext",
                               &section_num($secnr, $ssecnr),
                               $ssectname);
               STDOUT->printf(
                   qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
                   &section_num($secnr, $ssecnr), 
                   &section_num($secnr, $ssecnr), 
                   $outname,
                   &section_num($secnr, $ssecnr), 
                   $ssectname);
            } else {
               $headbuf = sprintf(
                     qq(<A NAME="ss%s">%s %s</A>\n),
                               &section_num($secnr, $ssecnr),
                               &section_num($secnr, $ssecnr),
                               $ssectname);
	    }
        }
    }
}