#!/usr/bin/perl 
#
#
# Copyright (C) 1997-2009, R3vis Corporation.
# 
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA, or visit http://www.gnu.org/copyleft/lgpl.html.
#
# Original Contributor:
#   Wes Bethel, R3vis Corporation, Marin County, California
#   http://www.r3vis.com/
# Additional Contributor(s):
#
# The OpenRM project is located at http://openrm.sourceforge.net/.
# 
#

# usage: source2html cSourceFname outputIndexHTMLFile outputHTMLfile
#
# purpose:
# autogenerate HTML documentation from source files by extracting
# author-supplied information (comments) from the file marked by
# special tags.
#
# $Id: source2html.pl,v 1.5 2008/11/24 16:51:34 wes Exp $
# Version: $Name: v180-alpha-02 $
# $Revision: 1.5 $
# $Log: source2html.pl,v $
# Revision 1.5  2008/11/24 16:51:34  wes
# Replaced ormsg.gif with ormsg.png
#
# Revision 1.4  2007/10/26 11:28:18  wes
# Minor tweak in doDataType function to deal a little better with
# typedefs that are function prototypes. There is still more work to
# do here to make better looking output, but at least the code
# doesn't choke on function prototype typedefs
#
# Revision 1.3  2005/02/19 16:47:58  wes
# Distro sync and consolidation.
#
# Revision 1.2  2004/01/17 04:04:18  wes
# Updated copyright line for 2004.
#
# Revision 1.1.1.1  2003/01/28 02:15:23  wes
# Manual rebuild of rm150 repository.
#
# Revision 1.2  2000/04/20 16:15:59  wes
# JDB modifications.
#
# Revision 1.1.1.1  2000/02/28 21:29:40  wes
# OpenRM 1.2 Checkin
#
# Revision 1.1.1.1  2000/02/28 17:18:48  wes
# Initial entry - pre-RM120 release, source base for OpenRM 1.2.
#
#

#
# usage: source2html cSourceFname cLibrary outputIndexHTMLFile outputHTMLfile
#
# purpose:
# autogenerate HTML documentation from source files by extracting
# author-supplied information (comments) from the file marked by
# special tags.
#
#

# documentation tags
$nameTag="\@Name";
$docStartTag="\@dstart";
$docEndTag="\@dend";
$protoStartTag="\@pstart";
$protoEndTag="\@pend";
$argsStartTag="\@astart";
$argsEndTag="\@aend";

# variables
$sourceLibrary = "empty";
$sourceFName = "empty";
$sourceFD = "empty";
$destFName = "empty";
$destIndexFD = "empty";
$destContentFD = "empty";
$destContentFName = "empty";
$destContentLink = "empty";
$currentRoutineName = "empty";


sub
doLivesInString
{
    # add source file location info
    print destContentFD "<i>lib", $sourceLibrary, " library source file: ", $sourceFName, " </i><hr width=\"75%\">\n";
}


sub
doPreamble
{
#
# output simple HTML header
#
    print destContentFD "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n";
    print destContentFD "<html><head><title>OpenRM - ", uc($sourceLibrary), " Library (", $sourceFName, ")</title></head>\n";
    print destContentFD "<body bgcolor=white fgcolor=black>\n<table width=\"100%\" border=2 cellspacing=0 cellpadding=0 bgcolor=\"khaki\" valign=\"center\">\n";
    print destContentFD "<th><img src=\"./images/ormsg.png\">\n</th>\n</table>\n";
    print destContentFD "<spacer type=vertical size=15>\n";
    print destContentFD "<h2>Index of OpenRM - ", uc($sourceLibrary), " Library</h2>\n";
    print destContentFD "<spacer type=vertical size=15>\n";
}


sub
doEpilogue
{
#
# output a simple HTML footer
#
    print destContentFD "</body></html>";
}


sub
doDatatype
{
# if we're here, then we have a public datatype to document.
# public datatypes are distinguished as being defined as follows:
#
# typedef (struct) RM*
#
# public datatypes are documented via a copy of their definition
#
    @fields = split(/\s+/, $line);

    # setup the hyperlink in the index file
    foreach $i (@fields)
    {
	if ($i =~ /RM*/)
	{
# 10/2007. Had to add some code to remove parens/stars here with the
# addition of some typedefs for functions in RMaux.
	    $j = $i;
	    $j =~ s/[^\w]//g;
# new	    
	    print destIndexFD $sourceLibrary, " $j <li> <a href=\"", $destContentLink, "#", $i, "\"> ", $i, " </a>\n";
#old
#	    print destIndexFD $sourceLibrary, " $i <li> <a href=\"", $destContentLink, "#", $i, "\"> ", $i, " </a>\n";
	    print destContentFD "<a name=\"", $i, "\"><b>", $i, "</b>\n";
	    break;
	}

    }
    # dump the datatype definition into content file
    print destContentFD "<pre>\n";
    while (!($line =~ /\}/))
    {
	print destContentFD $line;
	$line = <sourceFD>;
    }
    print destContentFD $line;
    print destContentFD "</pre>\n";
    doLivesInString();
    print destContentFD "<br>\n";


}


sub
doName
{
#
# if we're here, then a line containing $nameTag was encountered.
# the input line read from $sourceFD is split so that we can pull the name out
# the format of the documentation in the source file looks like:
# 
# @Name <function_name>, so once we find @Name the function name is next
#
# the split-out name is saved for error reporting in $currentRoutineName
# in the event that the tag-pairs are not as expected
# 
    @fields = split (/\s+/, $line);
    my $j = 0;

    foreach $i (@fields)
    {
	if ($i =~ /$nameTag/i)
	{
	    $currentRoutineName = $fields[$j + 1];
	    dumpNameTag($fields[$j + 1]);
	    break;
	}
	$j++;
    }
}


sub
dumpNameTag
{
# 
# input is a string containing the routine name, passed in from doName()
# this just writes out the temp file, with the first two entries being 
# the library name and the function name, used for sorting out the docs 
#
    print destIndexFD $sourceLibrary, " @_ <li> <a href=\"", $destContentLink, "#", @_, "\"> ", @_, " </a>\n";
    print destContentFD "<a name=\"" ,@_, "\"> \n";
}


sub
doProto
{
#
# if we're here, then a line containing $protoStartTag was encountered.
# first, we read in the next line - that means that we throw away
# the line containing $protoEndTag.
#
    $line = <sourceFD>;

    # while the input line DOES NOT contain the $docEndTag, continue reading input and dumping it out.
    print destContentFD "<pre><b>\n";

    while (!($line =~ /$protoEndTag/i))
    {
	print destContentFD $line;
	$line = <sourceFD>;

	if (eof(sourceFD))
	{
	    print "in routine ", $currentRoutineName, " the ", $protoEndTag, " appears to be missing\n";
	    die; 
	}
    }
    print destContentFD "</b></pre>\n";
}


sub
doArgs
{
#
# if we're here, then a line containing $argsStartTag was encountered.
# first, we read in the next line - that means that we throw away
# the line containing $argsEndTag.
#
    $line = <sourceFD>;

    # while the input line DOES NOT contain the $docEndTag, continue reading input and dumping it out.
    print destContentFD "<pre>\n";

    while (!($line =~ /$argsEndTag/i))
    {
	print destContentFD $line;
	$line = <sourceFD>;

	if (eof(sourceFD))
	{
	    print "in routine ", $currentRoutineName, " the ", $argsEndTag, " appears to be missing\n";
	    die; 
	}
    }
    print destContentFD "</pre>\n";
}


sub
doDoc
{
# 
# if we're here, then a line containing $docStartTag was encountered.
# first, we read in the next line - that means that we throw away
# the line containing $docStartTag.
#
    my $inParagraph = 0;
    my $wordCount = 0;
    $line = <sourceFD>;
#
# while the input line DOES NOT contain the $docEndTag, continue
# reading input and dumping it out.
#
# as this particular script is generating HTML, it looks for 
# "paragraph boundaries."  a paragraph boundary is defined as one or 
# more blank lines. a <P></P> pair is generated on paragraph boundaries.
#

    # start a paragraph, and eat any blank lines prior to processing.
    print destContentFD "<menu><P>\n";
    @fields = split (/\s+/, $line);
    $wordCount = scalar(@fields);
    while ($wordCount == 0)
    {
	$line = <sourceFD>;
	@fields = split (/\s+/, $line);
	$wordCount = scalar(@fields);
    }

    # we enter the loop inside a paragraph and with a non-zero $wordCount.
    while (!($line =~ /$docEndTag/i))
    {
	@fields = split (/\s+/, $line);
	$wordCount = scalar(@fields);

	if ($wordCount == 0)
	{
	    while ($wordCount == 0)
	    {
		$line = <sourceFD>;
		@fields = split (/\s+/, $line);
		$wordCount = scalar(@fields);
	    }

	    if (!($line =~ /$docEndTag/i))
	    {
		print destContentFD "</P>\n";
		print destContentFD "<P>\n";
	    }
	}
	else
	{
	    print destContentFD $line;
	    $line = <sourceFD>;
	}

	if (eof(sourceFD))
	{
	    print "in routine ", $currentRoutineName, " the ", $docEndTag, " appears to be missing\n";
	    die; 
	}
    }
    print destContentFD "</P></menu>\n";
    doLivesInString();
}


# begin of main()
{
    my $funcInfo = 0, my $dataInfo = 0;

    # open the source file
    open (sourceFD, "< $ARGV[0]") or die "ERROR: cannot open the input file.";
    $sourceFName = $ARGV[0];

    # derive the library and determine how deep library is in the RM tree
    @fields = split(/\//, $ARGV[1]);
    $sourceLibrary = $fields[$#fields];

    # open the output index and content files
    $destFName = ("../" x $#fields) . "doc/HTML/" . $ARGV[2];
    $destContentFName = ("../" x $#fields) . "doc/HTML/" . $ARGV[3];
    $destContentLink = "./" . $ARGV[3];
    open (destIndexFD, ">>$destFName") or die "ERROR: cannot open the output index file $destFName";
    open (destContentFD, ">$destContentFName") or die "ERROR: cannot open the output content file.";

    # do a quick pass to check for signs of documentation
    while ($line = <sourceFD>)
    {
	if (($line =~ /typedef/) && ($line =~ / RM/) && (!($line =~ PRIVATE)))
	{
	    $dataInfo++;
	}
	if ($line =~ /$nameTag/i)
	{
	    $funcInfo++;
	}
    }

    # if documentation exists then generate an HTML document for the file
    if ($dataInfo + $funcInfo)
    {
	doPreamble();

	# do a pass to get any datatype documentation
	if ($dataInfo)
	{
	    seek(sourceFD, 0, 0) or die "ERROR: cannot rewind input file for datatype documentation collection.";
	    while ($line = <sourceFD>)
	    {
		if (($line =~ /typedef/) && ($line =~ / RM/) && (!($line =~ PRIVATE))) # check for typedefs with RM prefixed name
		{
		    doDatatype($line);
		}
	    }
	}

	# do a pass to get any function documentation
	if ($funcInfo)
	{
	    seek(sourceFD, 0, 0) or die "ERROR: cannot rewind input file for function documentation collection.";
	    while ($line = <sourceFD>)
	    {
		if ($line =~ /$nameTag/i)
		{
		    doName($line);
		}
		if ($line =~ /$docStartTag/i)
		{
		    doDoc();
		}
		if ($line =~ /$protoStartTag/i)
		{
		    doProto();
		}
		if ($line =~ /$argsStartTag/i)
		{
		    doArgs();
		}
	    }
	}
	doEpilogue();
	close(destIndexFD);
	close(destContentFD);
    }
    else # nuke the bogus HTML file if empty
    {
	close(destIndexFD);
	close(destContentFD);
	if (-z $destContentFName)
	{
	    system("\\rm $destContentFName");	
	}
    }
}
# EOF


