#!/usr/bin/perl -w
#
# =========================================================================
# Copyright 2003 Twenty First Century Communications, Inc.
# Copyright 2003 Carey Hall <carey.hall@tfcci.com>
#
# LICENCE:
#
#   This file is distributed under the terms of the BSD License (version
#   2). See the COPYING file, which should have been distributed with
#   this file, for details. If you did not receive the COPYING file, see:
#
#   http://www.jmglov.net/opensource/licences/bsd.txt
#
# mkdoxy.pl
#
# DESCRIPTION:
#
#    Makes Doxygen-like web page documentation for makefiles.
#
# USAGE:
#
#   See $usage
#
# EXAMPLES:
#
#   mkdoxy.pl /usr/local/apache2/htdocs/jedi/doc Makefile.*
#
# DEPENDENCIES:
#
#   Perl 5
#
# TODO:
#
#   - Everything this code is imperfect!!!
#
# MODIFICATIONS:
#
#   Carey Hall <carey.hall@tfcci.com   (2003/11/11): Initial revision
#   Josh Glover <josh.glover@tfcci.com (2003/11/11): Cleaned up
#   Carey Hall <carey.hall@tfcci.com   (2003/12/02): Script now 
# 	parses a make file looking for 'Sections'.  If a makefile is not
#	broken into sections then all target's and macro's are put within
#	the __No_Section__ header.
# =========================================================================


use strict;

use File::Copy;
use File::Basename;
use FileHandle;

my $usage = "mkdoxy.pl <path> <makefile1> [<makefile2> ...]\n".
            "\n".
            "  <path>       directory where output should be written\n".
            "  <makefileN>  makefile to parse\n";



#-------------------------------------------------------------------------------
# Name: ParseMK
#
# Desc: Parses a make file that is passed to it looking for lines that 
#       match the regex expression for a target and lines that match 
#	the regex expression for a macro.  This function then creates
#       a hash of hashes that holds the default value and comments 
#       associated with either the macro or target (There is a hash 
#       for the targets and one for the macro's).  
#
# Paramters: 
#       fh - Is a variable that holds a file handle to the make file 
#            that will be parsed.
#
#-------------------------------------------------------------------------------

sub ParseMk {

  my (%macros, %targets, $header_comments, $section_name);
  my $found_section = 0;
  my $unknown_section_name = ['__No_Section__'];
  
  my ($fh) = @_;

  my $comment_lines = [];
  
  while (<$fh>) {
    #print "Section found----$found_section\n";
    
    if ( /^#{1}\s*?\-+\s*$/ ){
       
       # We found a line that denotes a section in a makefile.  So we set 
       # section_name and say that we are in a section block until we find 
       # another line with '#---------------'
        
       if ( ! $found_section ) {          
	  $section_name = $comment_lines;         
          $found_section = 1;
          $comment_lines = [];	  
       }
       else {       
          $found_section = 0;       
       }
 
    }
    
    # Is this line a comment for a target or a macro?
    if ( /^(#{1}\s(.+))\s*$/ ) {

      push @$header_comments, "$1";

    } # if (comment line)
       
    # Is this line a comment for a target or a macro?
    if ( /^##\s*(.+)\s*$/ ) {

      push @$comment_lines, "$1";

    } # if (comment line)

    # Is this line a target?
    if ( /^(\w+)\s*:(\s*(.+)\s*)*$/ ) {
      
      my $options = $1;
      my $default = $2;
            
      $section_name = $unknown_section_name 
         if ( ! $found_section ); 

      $targets{$section_name->[0]} -> {$options} = {
						    COMMENTS => $comment_lines,
						    DEFAULT  => $2
						   };
		     
      $comment_lines = [];

    } # if (target line)

    # Is this line a macro?
    if ( /^(\w+)\s*=(\s*(.+)\s*)*$/ ) {

      my $options = $1;
      my $default = $2;
      
      $section_name = $unknown_section_name 
         if ( ! $found_section ); 

      $macros{$section_name->[0]} -> {$options} = {
						    COMMENTS => $comment_lines,
						    DEFAULT  => $2
						   };
						              	        
      $comment_lines = [];

    } # if (macro line)
    
  } # while (<$fh>)

  return (\%macros, \%targets, $header_comments);

} # ParseMk()





#-------------------------------------------------------------------------------
# Name: ParseHeaderComments
#
# Desc: Parses the comments at the top of a makefile and formats them
#       into a data structure for ease of printing in HTML format. 
#
# Paramters: 
#
#	header_comments - Is a reference to an array, where each element is
#                         a line from comments section at the top of the script.
#-------------------------------------------------------------------------------

sub ParseHeaderComments {

   my (%header_comments, $text);
   
   my ($header_comments) = @_;
   
   my $description = '';
   my $previous_description = '';
   
   my $comment_desc_found = 0;
   my $element_count = 1;
   
   foreach ( @$header_comments ) {
   
      if ( /^#\s([A-Z]+):.*/ ) {

         $description = $1;    	    
	 
	 # We do not want to add anything to the hash until we 
	 # encounter our first element of the syntax <DESC>:
	 if ( $comment_desc_found ) { 
	 
	    $header_comments{$element_count} = {	           	                                       
					         DESC => $previous_description,
					         TEXT => $text
					       };						 
	    $element_count++;
	 	 
	 } # if ( $comment_desc_found )

	 $text = []; 
	 $comment_desc_found = 1;
	 	 
      } # if ( /^#\s([A-Z]+):.*/ )
      
      else {
      
         # Ignore the first few lines until we find something that
	 # matches <DESC>: then start loading it into an array.
         if ( $comment_desc_found && /^#\s{2,}(.*)$/ ) {
	 	 
            # Shove the the line in the the array.
	    push (@$text, $1) unless ( /^#\s=*\s*$/ );
	    
	 } # if ( $comment_desc_found && /^#\s{2,}(.*)$/ )

      } # if ( /^#\s([A-Z]+):.*/ )
      
      $previous_description = $description;
      
   } # foreach ( @$header_comments )
   
   return \%header_comments; 
   
} # ParseHeaderComments()





#-------------------------------------------------------------------------------
# Name: PrintCommentsHTML
#
# Desc: This function generates the HTML for the comments section of the
#	HTML page
#
# Paramters: 
#       header_comments - Is a reference to a hash that holds comments from 
#	                  the top of the script
#
#	targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#	fh - Is the filehandle of the html file we are creating. 
#
#-------------------------------------------------------------------------------

sub PrintCommentsHTML {

  my ($header_comments, $fh) = @_;

  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\"><H2>Header</H2></TD></TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";
  
  # Process macros
  foreach my $element (sort keys %$header_comments) {

    print $fh ( (defined $header_comments->{$element}->{DESC} ?
		 "<TR><TD ALIGN=\"left\" VALIGN=\"top\">". $header_comments->{$element}->{DESC}. "</TD></TR>\n" :
		 "&nbsp;</TD></TR>\n" ) );

    foreach my $text (@{$header_comments->{$element}->{TEXT}}) {

      if ( ! defined $text || $text eq '' ) {

         print $fh "<TR><TD ALIGN=\"left\" COLSPAN=\"2\" VALIGN=\"top\">&nbsp;<BR></TD></TR>";

      } # if (this element is an actual comment)

      else {
      
         print $fh "<TR><TD ALIGN=\"left\" COLSPAN=\"2\" VALIGN=\"top\"><I>$text</I></TD></TR>";	    	    
      
      } # if ( ! defined $text || $text eq '' )   
      
    } # foreach (printing comments)

      print $fh "<TR><TD ALIGN=\"left\" VALIGN=\"top\">&nbsp;</TD></TR>";
      
  } # foreach (macros)

} # PrintCommentsHTML()



#-------------------------------------------------------------------------------
# Name: PrintMacroHTML
#
# Desc: This function generates the HTML for the macro section of the
#       web page.
#
# Paramters: 
#       macros - Is a reference to a hash that holds comments, and default
#                values for all the macro definitions in the make file.
#
#	targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#	fh - Is the filehandle of the html file we are creating. 
#
#-------------------------------------------------------------------------------

sub PrintMacroHTML {

  my ($macros, $section, $fh) = @_;

  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\" CELLPADDING=\"10\"><H3>Macros</H3></TD></TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";
  
  if ( !exists($macros->{$section}) ) {
     
     print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\"><I>None</I></TD></TR>";
     print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\">&nbsp;</TD></TR>";       
  
  } # No macros found for this section.
  
  else {

    # Process macros
    foreach my $macro(sort keys %{$macros->{$section} }) {

      print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\">$macro&nbsp;=&nbsp;";

	print $fh ( (defined $macros->{$section}->{$macro}->{DEFAULT} ?
		   "<FONT COLOR=\"brown\">". $macros->{$section}->{$macro}->{DEFAULT}.
		   "</FONT</TD></TR>\n" :
		   "&nbsp;</TD></TR>\n" ) );

      foreach my $comments($macros->{$section}->{$macro}->{COMMENTS}) {

	print $fh "<TR><TD>";

	if ( !defined @$comments || @$comments eq '' ) {

          next;
	  #print $fh "<TR><TD>&nbsp;</TD></TR>\n";

	} # if ( !defined @$comments || @$comments eq '' )

	else {

	  print $fh "<TR><TD>";

	  foreach (@$comments) {

	    print $fh "<I>$_</I><BR>";

	  } # foreach (@$comments)

	  print $fh "</TD></TR>";

	} # if ( !defined @$comments || @$comments eq '' )

      } # foreach (printing comments)

      print $fh "<TR><TD>&nbsp;</TD></TR>\n";

    } # foreach (macros)

  } # Macros found within this section
  
} # PrintMacroHTML()





#-------------------------------------------------------------------------------
# Name: PrintTargetHTML
#
# Desc: This function generates the HTML for the target section of the
#       web page.
#
# Paramters: 
#       macros - Is a reference to a hash that holds comments, and default
#                values for all the macro definitions in the make file.
#
#	targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#	fh - Is the filehandle of the html file we are creating. 
#
#-------------------------------------------------------------------------------

sub PrintTargetHTML {

  my ($targets, $section, $fh) = @_;

  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\" CELLPADDING=\"10\"><H3>Targets</H3></TD></TR>\n";
  print $fh "<TR><TD COLSPAN=\"2\">&nbsp;</TR>\n";

  if ( !exists($targets->{$section}) ) {
     
     print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\"><I>None</I></TD></TR>";  
     print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\">&nbsp;</TD></TR>";    
       
  } # No target's found for this section.
  
  else {

    # Process targets  
    foreach my $target(sort keys %{$targets->{$section} }) {

      print $fh "<TR><TD NOWRAP ALIGN=\"left\" VALIGN=\"top\">$target:&nbsp;\n";

      print $fh ( (defined @$targets{$section}->{$target}->{DEFAULT} ? 
		   "<FONT COLOR=\"brown\">" . @$targets{$section}->{$target}->{DEFAULT} . "</FONT></TD></TR>" :
		   "&nbsp;</TD></TR>" ) );

      foreach my $comments(@$targets{$section}->{$target}->{COMMENTS}) {

	if ( !defined @$comments || @$comments eq '' ) {

	  next;
	  #print $fh "<TR><TD>&nbsp;</TD></TR>\n";

	} # if ( !defined @$comments || @$comments eq '' )

	else {

	  print $fh "<TR><TD>";

	  foreach (@$comments) {

	    print $fh "<I>$_</I><BR>";

	  } # foreach (@$comments)

	  print $fh "</TD></TR>";

	} # if ( !defined @$comments || @$comments eq '' )

      } # foreach (printing comments)

      print $fh "<TR><TD>&nbsp;</TD></TR>\n";

    } # foreach (target)

   } # Target's found for this section
   
} # PrintTargetHTML()





#-------------------------------------------------------------------------------
# Name: GetNavigation
#
# Desc: Finds the index.html for the path passed to this script.  It then 
#       searches through this index file and grabs the top navigation links.
#
# Paramters: 
#
#       path - Is the path passed to this script at the command line.  
#-------------------------------------------------------------------------------

sub GetNavigation {

  my ($path) = @_;

  my $filename = sprintf("%s/%s", $path, 'index.html');

  my $fh = FileHandle->new( $filename, 'r' )
     or die "Could not open $filename for reading!\n";

  # Go to the Doxygen path and find an index.html.  Then search through
  # this until you find a line that has the navigation on the top.

  my $navigation_header = '';

  while (<$fh>) {

    if ( /^(<a class="qindex".*)<\/center>$/ ) {
      $navigation_header = $1;
      last;
    }

  } # while (<$fh>)

  die ('Could not find the line HTML code that creates the navigation' .
       " at the top of the index.html file in $path.")
    unless defined $navigation_header || $navigation_header ne '';

  return $navigation_header;

} #GetNavigation()




#-------------------------------------------------------------------------------
# Name: CreateSourceHTML
#
# Desc: This is the function that creates the HTML documentation page for
#       a given Makefile.
#
# Paramters: 
#
#       macros - Is a reference to a hash that holds comments, and default
#                values for all the macro definitions in the make file.
#
#	targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#	filename - Is the name of the make file that we are parsing.  This
#                  is being passed in to provide a more informative header
#                  for the HTML page. 
#
#	path - Is the path passed from the command prompt where the HTML
#              file needs to be written to.  
#-------------------------------------------------------------------------------

sub CreateSourceHTML {

  my ($filename, $path) = @_;

  my $full_filename = $filename;
  
  # Strip out the filename wi
  $filename =~ s/^.*\/(.*)$/$1/;

  my $generation_date = localtime();

  my $html_filename = sprintf ("%s/%s-source.html", $path, $filename);

  #Open html file.
  my $wfh = FileHandle->new( $html_filename, 'w' )
    or die "Could not open  '$html_filename' for writing!\n";

  my $navigation_header = GetNavigation($path);

  print $wfh <<"EOF";

      <HTML>

         <HEAD>

	    <TITLE>$filename File Reference</TITLE>
            <LINK HREF=\"doxygen.css\" REL=\"stylesheet\" TYPE=\"text\/css\">
	 <HEAD>

	 <BODY>

            <CENTER>

	    $navigation_header

	    <HR>

	    <H1>$filename</H1>

	    </CENTER>

            <A HREF=\"$filename\.html\">Go to the documentation of this file.</A>		      
            
	    <PRE><DIV CLASS="fragment">

EOF
	       # Open the makefile
	       my $rfh = FileHandle->new( "$full_filename", 'r' )
		 or die "Could not open makefile '$full_filename' for reading!\n";
	
	       my $row_num = 1;
	       
	       while (<$rfh>) {
		  my $line_num = sprintf "%05d", $row_num;	
		  print $wfh "$line_num&nbsp;&nbsp;";		  	  
		  
		  if ( /^##*.*$/ ) {
		     print $wfh "<SPAN CLASS=\"comment\">$_</SPAN>";
		  }
		  elsif ( /^\w+\s*=.*$/  ) {
		     print $wfh "<SPAN CLASS=\"keywordtype\">$_</SPAN>";		  
		  }
		  elsif ( /^\w+\s*:\s*.*$/ ) {
		     print $wfh "<SPAN CLASS=\"keyword\">$_</SPAN>";		  
		  }
		  else {
		     print $wfh "$_";
	          }
		  $row_num++;
	       }
               
  print $wfh <<"EOF";
            </DIV></PRE>
	    
            <HR>
	    
            <ADDRESS STYLE="align: right;">
	       <SMALL>Generated on $generation_date</SMALL>
	    </ADDRESS>	    
	 </BODY>

      </HTML>
EOF
  
  return $html_filename;

} # CreateSourceHTML()


#-------------------------------------------------------------------------------
# Name: CreateHTML
#
# Desc: This is the function that creates the HTML documentation page for
#       a given Makefile.
#
# Paramters: 
#
#       macros - Is a reference to a hash that holds comments, and default
#                values for all the macro definitions in the make file.
#
#	targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#	filename - Is the name of the make file that we are parsing.  This
#                  is being passed in to provide a more informative header
#                  for the HTML page. 
#
#	path - Is the path passed from the command prompt where the HTML
#              file needs to be written to.  
#-------------------------------------------------------------------------------

sub CreateHTML {

  my ($macros, $targets, $header_comments, $sections, $filename, $path) = @_;
  my $generation_date = localtime();
  
  # Strip out the filename without the path.
  $filename =~ s/^.*\/(.*)$/$1/;
  # Strip off any trailing slashes.
  $path =~ s/^(.*)\/$/$1/;
  
  my $html_filename = sprintf ("%s/%s.html", $path, $filename);
  my $source_html_filename = sprintf ("%s-source.html", $filename);  
  
  #Open html file.
  my $fh = FileHandle->new( $html_filename, 'w' )
    or die "Could not open  '$html_filename' for writing!\n";

  my $navigation_header = GetNavigation($path);

  print $fh <<"EOF";

      <HTML>

         <HEAD>

	    <TITLE>$filename File Reference</TITLE>
            <LINK HREF=\"doxygen.css\" REL=\"stylesheet\" TYPE=\"text\/css\">
	 <HEAD>

	 <BODY>

            <CENTER>

	    $navigation_header

	    <HR>

	    <H1>$filename File Reference</H1>

	    </CENTER>

	    <TABLE BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" WIDTH=\"100%\">
	    
	       <TR>
	       
	          <TD><A HREF=\"$source_html_filename\">
		      Go to the source code of this file.
		      </A>
		  </TD>
		  
	       </TR>
EOF

  PrintCommentsHTML($header_comments, $fh); 

  foreach my $section (@$sections) {  

     print $fh "<TR><TD><HR></TD></TR>\n";
     print $fh "<TR><TD COLSPAN=\"2\" CELLPADDING=\"0\"><H2>$section</H2></TD></TR>\n";
  
     PrintMacroHTML($macros, $section, $fh);
     PrintTargetHTML($targets, $section, $fh);
  }

  print $fh <<"EOF";
	    </TABLE>

            <HR>
	    
            <ADDRESS STYLE="align: right;">
	       <SMALL>Generated on $generation_date</SMALL>
	    </ADDRESS>	    
	 </BODY>

      </HTML>
EOF

  AddDoxyLink($path, $filename);

} # CreateHTML()





#-------------------------------------------------------------------------------
# Name: AddDoxyLink
#
# Desc: This Goes to the Doxygen files.html web page and scans through the
#       links found on the left side.  It compares the recently parsed file
#       names to the names found in those links and compares them alphabetically
#       inserting a link for the newly parsed file within the other links.
#
# Paramters: 
#
#	path - Is the path passed from the command prompt where the HTML
#              file needs to be written to.  
#
#	new_filename - Is the name of the newly parsed file.
#-------------------------------------------------------------------------------

sub AddDoxyLink {

  my ($path, $new_filename) = @_;

  my $wfilename = sprintf("%s/%s", $path, 'files.html');
  my $rfilename = sprintf("%s/%s", $path, 'files.html.backup');

  copy $wfilename, $rfilename;

  my $rfh = FileHandle->new( $rfilename, 'r' )
    or die "Could not open $rfilename for reading!\n";

  my $wfh = FileHandle->new( $wfilename, 'w' )
    or die "Could not open $wfilename for writing!\n";

  my $found = 0;

  my $html_link = "  <tr><td class=\"indexkey\">".
    "<a class=\"el\" href=\"$new_filename\.html\">$new_filename</a> ".
      "<a href=\"$new_filename-source\.html\">[code]</a>".
	"</td><td class=\"indexvalue\"></td></tr>";

  while (<$rfh>) {

    my ($cell, $current_filename, $table_tag);
    
    undef $table_tag;
    
    if ( /^(\s*<tr><td class="indexkey"><[^>]*>([^<]*).*?)(<\/table>)*$/ ) {

      $cell = $1;
      $current_filename = $2;
      $table_tag = $3;
      
      if (!$found) {

	my $status = $new_filename cmp $current_filename;

	if ($status == 0) {
          
	  $found = 1;

	} # if ( $status == 0 )

	elsif ( $status == -1 ) {

	  $found = 1;
	  print $wfh "$html_link\n";

	} # elsif ( $status == 1 )

      } # if (we have not made the insertion yet)
            
    } # if (dealing with a link)

    # If the new_filename is greater than the filename for the last
    # link in files.html then this is here to catch that case. 
    if ( defined $table_tag || /<\/table>/ ) {
    
       print $wfh "$cell\n"
          if defined $cell;
	  
       print $wfh "$html_link\n"
          unless $found;
	  
       if (defined $table_tag) {
          print $wfh "$table_tag\n";
	  next;
       } # if (defined $table_tag)
    
    } # if ( defined $table_tag || /<\/table>/ )

    print $wfh "$_";      
        
  } # while (<$fh>)

  $wfh->close();
  $rfh->close();

} # AddDoxyLink()




#-------------------------------------------------------------------------------
# Name: FindSections
#
# Desc: This goes through both target and macro hashes to find all the section
#       names.  This function stores them in an array, when it finds a section 
#       not yet in the array then the section name is added.  This array is then
#       used in the CreateHTML() function.
#
# Paramters: 
#       $macros - Is a reference to a hash that holds comments, and default
#                 values for all the macro definitions in the make file.
#
#	$targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#-------------------------------------------------------------------------------

sub FindSections {

  my $sections;
  
  my ($macros, $targets) = @_;
  
  # Process macros
  foreach my $section(sort keys %$macros) {
     
     if ( grep (/^$section$/, @$sections) ) {

	next;
	
     } # Section already in the array
     else {

	push (@$sections, $section);
	
     }
     
  } # foreach sections
  
  # Process targets
  foreach my $section(sort keys %$targets) {

     if ( grep (/^$section$/, @$sections) ) {
     
	next;
	
     } # Section already in the array
     else {

	push (@$sections, $section);
	
     }
     
  } # foreach sections

  return $sections;    
  
} # FindSections()





#-------------------------------------------------------------------------------
# Name: PrintStructures
#
# Desc: This is a function for debugging purposes only.  If you are 
#       curious what is in the hashes, call this function and it will
#       print out the hash in a human readable format.  
#
# Paramters: 
#       $macros - Is a reference to a hash that holds comments, and default
#                 values for all the macro definitions in the make file.
#
#	$targets - Is a reference to a hash that holds comments, and default
#                 values for all the target definitions in the make file.
#
#-------------------------------------------------------------------------------

sub PrintStructures {

  my ($macros, $targets, $header_comments) = @_;

  # Print Header Comments
  foreach my $element ( sort keys %$header_comments ) {

    print( STDERR "comments~".
    	   (defined @$header_comments{$element}->{DESC} ? 
	    @$header_comments{$element}->{DESC} . "\n" : 
	    " (No value)\n" ) );

    print STDERR "\t\tCOMMENTS : (No comments)\n"
      unless @$header_comments{$element}->{TEXT};

    foreach my $text (@$header_comments{$element}->{TEXT}) {

      if ( !defined @$text || @$text eq '' ) {

	print STDERR "\t\tCOMMENTS:(No comments)\n"	 

      } # if ( !defined @$text || @$text eq '' )
      else {

	foreach (@$text) {

	  print STDERR "\t\tTEXT:$_\n";

	} # foreach (@$text)

      } # if ( !defined @$text || @$text eq '' )

    } # foreach (printing comments)

  } # foreach my $element ( sort keys %header_comments_hash )
  

  print "\n\n";

  # Process macros
  foreach my $section(sort keys %$macros) {

     print STDERR "\n-------------------------------------------------\n";
     print STDERR "\nSECTION~$section\n";
     print STDERR "\n-------------------------------------------------\n";
  
     foreach my $macro( sort keys %{$macros->{$section}} ) {

       print STDERR "macro~$macro\n";

       print( STDERR "\t\tDEFAULT ---".
    	      (defined $macros->{$section}->{$macro}->{DEFAULT} ? 
	       $macros->{$section}->{$macro}->{DEFAULT} : " (No value)\n" ) );

       print STDERR "\t\tCOMMENTS --- (No comments)\n"
	 unless $macros->{$section}->{$macro}->{COMMENTS};

       foreach my $comments($macros->{$section}->{$macro}->{COMMENTS}) {

	 if ( !defined @$comments || @$comments eq '' ) {

	   print STDERR "\t\tCOMMENTS:(No comments)\n"	 

	 } # if ( !defined @$c || @$c eq '' )
	 else {

	   foreach (@$comments) {

	     print STDERR "\t\tCOMMENTS:$_\n";

	   } # foreach (@$c)

	 } # if ( !defined @$c || @$c eq '' )

       } # foreach (printing comments)

     } # foreach (macro)
     
  } # foreach section

  
  print "\n\n";
  
  
  # Process targets
  foreach my $section(sort keys %$targets) {

     print STDERR "\n-------------------------------------------------\n";
     print STDERR "\nSECTION~$section\n";
     print STDERR "\n-------------------------------------------------\n";
  
     foreach my $target( sort keys %{$targets->{$section}} ) {

       print STDERR "target~$target\n";

       print( STDERR "\t\tDEFAULT ---".
    	      (defined $targets->{$section}->{$target}->{DEFAULT} ? 
	       $targets->{$section}->{$target}->{DEFAULT} : " (No value)\n" ) );

       print STDERR "\t\tCOMMENTS --- (No comments)\n"
	 unless $targets->{$section}->{$target}->{COMMENTS};

       foreach my $comments($targets->{$section}->{$target}->{COMMENTS}) {

	 if ( !defined @$comments || @$comments eq '' ) {

	   print STDERR "\t\tCOMMENTS:(No comments)\n"	 

	 } # if ( !defined @$c || @$c eq '' )
	 else {

	   foreach (@$comments) {

	     print STDERR "\t\tCOMMENTS:$_\n";

	   } # foreach (@$c)

	 } # if ( !defined @$c || @$c eq '' )

       } # foreach (printing comments)

     } # foreach (target)
     
  } # foreach section

} # PrintStructures()




#-------------------------------------------------------------------------------
# Main: 
#-------------------------------------------------------------------------------

main : {

  my ($path, @files) = @ARGV;

  # Check usage
  die ( 'Incorrect number of arguments ('. (scalar @ARGV) .": @ARGV)\n".
	"Usage: $usage" )
    unless defined $path and @files;
   
  # Strip off any trailing sl
  $path =~ s/^(.*)\/$/$1/;
    
  # Check to see if the file files.html exists within the doxygen path.
  # If it doesn't then most likely doxygen has not been installed yet.  
  if ( ! -e "$path/files.html" ) {
  
     my $error_message = "\n\t####################################################################\n";
     $error_message .= "\t#    ERROR:\n";
     $error_message .= "\t#    Cannot find file $path/files.html\n";
     $error_message .= "\t#    (1)Doxygen has not been run for this path or,\n";
     $error_message .= "\t#    (2)The path: '$path'\n";
     $error_message .= "\t#       is incorrect\n";
     $error_message .= "\t####################################################################\n\n";

     die $error_message;
  }
  
  # Process makefiles
  foreach (@files) {

    my $filename = $_;

    # Open the makefile
    my $fh = FileHandle->new( "$_", 'r' )
      or die "Could not open makefile '$_' for reading!\n";

    # Parse it
    my ($macros, $targets, $header_comments) = ParseMk ($fh);
    
    # Create a array of sections
    my $sections = FindSections($macros, $targets);
    
    # Parse the header comments into a complex data structure.
    my $formated_header_comments = ParseHeaderComments ($header_comments);
    
    # Print it, used for debuging.
    #PrintStructures($macros, $targets, $formated_header_comments);

    my $source_html_file = CreateSourceHTML($filename, $path);
    
    # Create HTML file
    CreateHTML($macros, 
               $targets, 
	       $formated_header_comments, 
	       $sections, 
	       $filename, 
	       $path);

    # Copy the Makefile to the Doxygen directory
    my $dest = sprintf "$path/%s", basename( $filename );

    copy( $filename, $dest )
      or die "Could not copy file '$filename' to '$dest'\n";

  } # foreach (processing makefiles)

} # main()
