<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">###############################################################################
#
#   Package: NaturalDocs::Builder::HTML
#
###############################################################################
#
#   A package that generates output in HTML.
#
#   All functions are called with Package-&gt;Function() notation.
#
###############################################################################

# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
# Natural Docs is licensed under the GPL


use strict;
use integer;

package NaturalDocs::Builder::HTML;

use base 'NaturalDocs::Builder::HTMLBase';


###############################################################################
# Group: Implemented Interface Functions


#
#   Function: INIT
#
#   Registers the package with &lt;NaturalDocs::Builder&gt;.
#
sub INIT
    {
    NaturalDocs::Builder-&gt;Add(__PACKAGE__);
    };


#
#   Function: CommandLineOption
#
#   Returns the option to follow -o to use this package.  In this case, "html".
#
sub CommandLineOption
    {
    return 'HTML';
    };


#
#   Function: BuildFile
#
#   Builds the output file from the parsed source file.
#
#   Parameters:
#
#       sourcefile       - The &lt;FileName&gt; of the source file.
#       parsedFile      - An arrayref of the source file as &lt;NaturalDocs::Parser::ParsedTopic&gt; objects.
#
sub BuildFile #(sourceFile, parsedFile)
    {
    my ($self, $sourceFile, $parsedFile) = @_;

    my $outputFile = $self-&gt;OutputFileOf($sourceFile);


    # 99.99% of the time the output directory will already exist, so this will actually be more efficient.  It only won't exist
    # if a new file was added in a new subdirectory and this is the first time that file was ever parsed.
    if (!open(OUTPUTFILEHANDLE, '&gt;' . $outputFile))
        {
        NaturalDocs::File-&gt;CreatePath( NaturalDocs::File-&gt;NoFileName($outputFile) );

        open(OUTPUTFILEHANDLE, '&gt;' . $outputFile)
            or die "Couldn't create output file " . $outputFile . "\n";
        };

    print OUTPUTFILEHANDLE


        '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
            . '"http://www.w3.org/TR/REC-html40/strict.dtd"&gt;' . "\n\n"

        . '&lt;html&gt;&lt;head&gt;'

            . (NaturalDocs::Settings-&gt;CharSet() ?
                '&lt;meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings-&gt;CharSet() . '"&gt;' : '')

            . '&lt;title&gt;'
                . $self-&gt;BuildTitle($sourceFile)
            . '&lt;/title&gt;'

            . '&lt;link rel="stylesheet" type="text/css" href="' . $self-&gt;MakeRelativeURL($outputFile, $self-&gt;MainCSSFile(), 1) . '"&gt;'

            . '&lt;script language=JavaScript src="' . $self-&gt;MakeRelativeURL($outputFile, $self-&gt;MainJavaScriptFile(), 1) . '"&gt;'
                . '&lt;/script&gt;'
            . '&lt;script language=JavaScript src="' . $self-&gt;MakeRelativeURL($outputFile, $self-&gt;SearchDataJavaScriptFile(), 1) . '"&gt;'
                . '&lt;/script&gt;'

        . '&lt;/head&gt;&lt;body class="ContentPage" onLoad="NDOnLoad()"&gt;'
            . $self-&gt;OpeningBrowserStyles()

            . $self-&gt;StandardComments()

            . "\n\n\n"
                . $self-&gt;BuildContent($sourceFile, $parsedFile)
            . "\n\n\n"
                . $self-&gt;BuildFooter()
            . "\n\n\n"
                . $self-&gt;BuildMenu($sourceFile, undef)
            . "\n\n\n"
                . $self-&gt;BuildToolTips()
            . "\n\n\n"
                . '&lt;div id=MSearchResultsWindow&gt;'
                    . '&lt;iframe src="" frameborder=0 name=MSearchResults id=MSearchResults&gt;&lt;/iframe&gt;'
                    . '&lt;a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose&gt;Close&lt;/a&gt;'
                . '&lt;/div&gt;'
            . "\n\n\n"

            . $self-&gt;ClosingBrowserStyles()
        . '&lt;/body&gt;&lt;/html&gt;';


    close(OUTPUTFILEHANDLE);
    };


#
#   Function: BuildIndex
#
#   Builds an index for the passed type.
#
#   Parameters:
#
#       type  - The &lt;TopicType&gt; to limit the index to, or undef if none.
#
sub BuildIndex #(type)
    {
    my ($self, $type) = @_;

    my $indexTitle = $self-&gt;IndexTitleOf($type);

    my $startIndexPage =

        '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
            . '"http://www.w3.org/TR/REC-html40/strict.dtd"&gt;' . "\n\n"

        . '&lt;html&gt;&lt;head&gt;'

            . (NaturalDocs::Settings-&gt;CharSet() ?
                '&lt;meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings-&gt;CharSet() . '"&gt;' : '')

            . '&lt;title&gt;'
                . $indexTitle;

                if (defined NaturalDocs::Menu-&gt;Title())
                    {  $startIndexPage .= ' - ' . $self-&gt;StringToHTML(NaturalDocs::Menu-&gt;Title());  };

            $startIndexPage .=
            '&lt;/title&gt;'

            . '&lt;link rel="stylesheet" type="text/css" href="' . $self-&gt;MakeRelativeURL($self-&gt;IndexDirectory(),
                                                                                                                       $self-&gt;MainCSSFile()) . '"&gt;'

            . '&lt;script language=JavaScript src="' . $self-&gt;MakeRelativeURL($self-&gt;IndexDirectory(),
                                                                                                        $self-&gt;MainJavaScriptFile()) . '"&gt;&lt;/script&gt;'
            . '&lt;script language=JavaScript src="' . $self-&gt;MakeRelativeURL($self-&gt;IndexDirectory(),
                                                                                                        $self-&gt;SearchDataJavaScriptFile()) . '"&gt;'
                . '&lt;/script&gt;'

        . '&lt;/head&gt;&lt;body class="IndexPage" onLoad="NDOnLoad()"&gt;'
            . $self-&gt;OpeningBrowserStyles()

        . $self-&gt;StandardComments()

        . "\n\n\n"

        . '&lt;div id=Index&gt;'
            . '&lt;div class=IPageTitle&gt;'
                . $indexTitle
            . '&lt;/div&gt;';

    my $endIndexPage =
            '&lt;/div&gt;&lt;!--Index--&gt;'

            . "\n\n\n"
                . $self-&gt;BuildFooter()
            . "\n\n\n"
                . $self-&gt;BuildMenu(undef, $type)
            . "\n\n\n"
                . '&lt;div id=MSearchResultsWindow&gt;'
                    . '&lt;iframe src="" frameborder=0 name=MSearchResults id=MSearchResults&gt;&lt;/iframe&gt;'
                    . '&lt;a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose&gt;Close&lt;/a&gt;'
                . '&lt;/div&gt;'
            . "\n\n\n"

            . $self-&gt;ClosingBrowserStyles()
        . '&lt;/body&gt;&lt;/html&gt;';


    my $startSearchResultsPage =

        '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
            . '"http://www.w3.org/TR/REC-html40/strict.dtd"&gt;' . "\n\n"

        . '&lt;html&gt;&lt;head&gt;'

            . (NaturalDocs::Settings-&gt;CharSet() ?
                '&lt;meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings-&gt;CharSet() . '"&gt;' : '')

            . '&lt;link rel="stylesheet" type="text/css" href="' . $self-&gt;MakeRelativeURL($self-&gt;SearchResultsDirectory(),
                                                                                                                       $self-&gt;MainCSSFile()) . '"&gt;'

            . '&lt;script language=JavaScript src="' . $self-&gt;MakeRelativeURL($self-&gt;SearchResultsDirectory(),
                                                                                                        $self-&gt;MainJavaScriptFile()) . '"&gt;&lt;/script&gt;'

        . '&lt;/head&gt;&lt;body class="PopupSearchResultsPage" onLoad="NDOnLoad()"&gt;'
            . $self-&gt;OpeningBrowserStyles()

        . $self-&gt;StandardComments()

        . "\n\n\n"

        . '&lt;div id=Index&gt;';


    my $endSearchResultsPage =
        '&lt;/div&gt;'
        . $self-&gt;ClosingBrowserStyles()
   . '&lt;/body&gt;&lt;/html&gt;';

    my $indexContent = NaturalDocs::SymbolTable-&gt;Index($type);
    my $pageCount = $self-&gt;BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage,
                                                                  $startSearchResultsPage, $endSearchResultsPage);
    $self-&gt;PurgeIndexFiles($type, $indexContent, $pageCount + 1);
    };


#
#   Function: UpdateMenu
#
#   Updates the menu in all the output files that weren't rebuilt.  Also generates index.html.
#
sub UpdateMenu
    {
    my $self = shift;


    # Update the menu on unbuilt files.

    my $filesToUpdate = NaturalDocs::Project-&gt;UnbuiltFilesWithContent();

    foreach my $sourceFile (keys %$filesToUpdate)
        {
        $self-&gt;UpdateFile($sourceFile);
        };


    # Update the menu on unchanged index files.

    my $indexes = NaturalDocs::Menu-&gt;Indexes();

    foreach my $index (keys %$indexes)
        {
        if (!NaturalDocs::SymbolTable-&gt;IndexChanged($index))
            {
            $self-&gt;UpdateIndex($index);
            };
        };


    # Update index.html

    my $firstMenuEntry = $self-&gt;FindFirstFile();
    my $indexFile = NaturalDocs::File-&gt;JoinPaths( NaturalDocs::Settings-&gt;OutputDirectoryOf($self), 'index.html' );

    # We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu.
    if (defined $firstMenuEntry)
        {
        open(INDEXFILEHANDLE, '&gt;' . $indexFile)
            or die "Couldn't create output file " . $indexFile . ".\n";

        print INDEXFILEHANDLE
        '&lt;html&gt;&lt;head&gt;'
             . '&lt;meta http-equiv="Refresh" CONTENT="0; URL='
                 . $self-&gt;MakeRelativeURL( NaturalDocs::File-&gt;JoinPaths( NaturalDocs::Settings-&gt;OutputDirectoryOf($self), 'index.html'),
                                                        $self-&gt;OutputFileOf($firstMenuEntry-&gt;Target()), 1 ) . '"&gt;'
        . '&lt;/head&gt;&lt;/html&gt;';

        close INDEXFILEHANDLE;
        }

    elsif (-e $indexFile)
        {
        unlink($indexFile);
        };
    };



###############################################################################
# Group: Support Functions


#
#   Function: UpdateFile
#
#   Updates an output file.  Replaces the menu, HTML title, and footer.  It opens the output file, makes the changes, and saves it
#   back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
#
#   Parameters:
#
#       sourceFile - The source &lt;FileName&gt;.
#
#   Dependencies:
#
#       - Requires &lt;Builder::BuildMenu()&gt; to surround its content with the exact strings "&lt;div id=Menu&gt;" and "&lt;/div&gt;&lt;!--Menu--&gt;".
#       - Requires &lt;Builder::BuildFooter()&gt; to surround its content with the exact strings "&lt;div id=Footer&gt;" and
#         "&lt;/div&gt;&lt;!--Footer--&gt;".
#
sub UpdateFile #(sourceFile)
    {
    my ($self, $sourceFile) = @_;

    my $outputFile = $self-&gt;OutputFileOf($sourceFile);

    if (open(OUTPUTFILEHANDLE, '&lt;' . $outputFile))
        {
        my $content;

        read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
        close(OUTPUTFILEHANDLE);


        $content =~ s{&lt;title&gt;[^&lt;]*&lt;\/title&gt;}{'&lt;title&gt;' . $self-&gt;BuildTitle($sourceFile) . '&lt;/title&gt;'}e;

        $content =~ s/&lt;div id=Menu&gt;.*?&lt;\/div&gt;&lt;!--Menu--&gt;/$self-&gt;BuildMenu($sourceFile, undef)/es;

        $content =~ s/&lt;div id=Footer&gt;.*?&lt;\/div&gt;&lt;!--Footer--&gt;/$self-&gt;BuildFooter()/e;


        open(OUTPUTFILEHANDLE, '&gt;' . $outputFile);
        print OUTPUTFILEHANDLE $content;
        close(OUTPUTFILEHANDLE);
        };
    };


#
#   Function: UpdateIndex
#
#   Updates an index's output file.  Replaces the menu and footer.  It opens the output file, makes the changes, and saves it
#   back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
#
#   Parameters:
#
#       type - The index &lt;TopicType&gt;, or undef if none.
#
sub UpdateIndex #(type)
    {
    my ($self, $type) = @_;

    my $page = 1;

    my $outputFile = $self-&gt;IndexFileOf($type, $page);

    my $newMenu = $self-&gt;BuildMenu(undef, $type);
    my $newFooter = $self-&gt;BuildFooter();

    while (-e $outputFile)
        {
        open(OUTPUTFILEHANDLE, '&lt;' . $outputFile)
            or die "Couldn't open output file " . $outputFile . ".\n";

        my $content;

        read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
        close(OUTPUTFILEHANDLE);


        $content =~ s/&lt;div id=Menu&gt;.*?&lt;\/div&gt;&lt;!--Menu--&gt;/$newMenu/es;

        $content =~ s/&lt;div id=Footer&gt;.*&lt;\/div&gt;&lt;!--Footer--&gt;/$newFooter/e;


        open(OUTPUTFILEHANDLE, '&gt;' . $outputFile)
            or die "Couldn't save output file " . $outputFile . ".\n";

        print OUTPUTFILEHANDLE $content;
        close(OUTPUTFILEHANDLE);

        $page++;
        $outputFile = $self-&gt;IndexFileOf($type, $page);
        };
    };


1;
</pre></body></html>