### Copyright (c) 2001 Richard Y. Kim
###
### This is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2, or (at your option)
### any later version.
### See <http://www.gnu.org/licenses/gpl.html> for details.
###
### Author: Richard Y. Kim, <richardkim@grassvalleygroup.com>
### Maintainer: Richard Y. Kim, <richardkim@grassvalleygroup.com>
### Created: Fri Nov 30 12:13:44 2001
### Version: 0.1
### 
### This utility provides a simple framework for creating and modifying
### doxygen <http://www.doxygen.org> configuration files and running doxygen.
### See the end of this file for details.
###
package Doxygen;

###****************************************************************************
###@ Configuration File
###****************************************************************************

my $this_prog  = $0;

###============================================================================
###@@ Default Hash Table
###============================================================================

# This is the default value of all objects created via Doxygen->new method.
my $doxygen_defaults =
{
  'ALIASES'               => '',
  'ALLEXTERNALS'          => 'YES',
  'ALPHABETICAL_INDEX'    => 'YES',
  'ALWAYS_DETAILED_SEC'   => 'NO',
  'BINARY_TOC'            => 'NO',
  'BIN_ABSPATH'           => '',
  'BRIEF_MEMBER_DESC'     => 'YES',
  'CASE_SENSE_NAMES'      => 'YES',
  'CGI_NAME'              => 'dsearch',
  'CGI_URL'               => 'http://localhost/cgi-bin',
  'CLASS_DIAGRAMS'        => 'YES',
  'CLASS_GRAPH'           => 'YES',
  'COLLABORATION_GRAPH'   => 'YES',
  'COLS_IN_ALPHA_INDEX'   => '5',
  'COMPACT_LATEX'         => 'NO',
  'COMPACT_RTF'           => 'NO',
  'DISABLE_INDEX'         => 'NO',
  'DISTRIBUTE_GROUP_DOC'  => 'NO',
  'DOTFILE_DIRS'          => '',
  'DOC_ABSPATH'           => '',
  'DOC_URL'               => '',
  'DOTFILE_DIRS'          => '',
  'DOT_CLEANUP'           => 'YES',
  'DOT_PATH'              => '',
  'ENABLED_SECTIONS'      => '',
  'ENABLE_PREPROCESSING'  => 'YES',
  'ENUM_VALUES_PER_LINE'  => '4',
  'EXAMPLE_PATH'          => '',
  'EXAMPLE_PATTERNS'      => '',
  'EXAMPLE_RECURSIVE'     => '',
  'EXCLUDE'               => '',
  'EXCLUDE_PATTERNS'      => '',
  'EXPAND_AS_DEFINED'     => '',
  'EXPAND_ONLY_PREDEF'    => 'NO',
  'EXTRACT_ALL'           => 'YES',
  'EXTRACT_PRIVATE'       => 'YES',
  'EXTRACT_STATIC'        => 'YES',
  'EXTRA_PACKAGES'        => '',
  'EXT_DOC_PATHS'         => '',
  'FILE_PATTERNS'         => '*.h *.hpp *.c *.cpp',
  'FILTER_SOURCE_FILES'   => 'NO',
  'FULL_PATH_NAMES'       => 'NO',
  'GENERATE_BUGLIST'      => 'NO',
  'GENERATE_CHI'          => 'NO',
  'GENERATE_HTML'         => 'YES',
  'GENERATE_HTMLHELP'     => 'NO',
  'GENERATE_LATEX'        => 'NO',
  'GENERATE_LEGEND'       => 'YES',
  'GENERATE_MAN'          => 'NO',
  'GENERATE_RTF'          => 'NO',
  'GENERATE_TAGFILE'      => '',
  'GENERATE_TESTLIST'     => 'NO',
  'GENERATE_TODOLIST'     => 'NO',
  'GENERATE_TREEVIEW'     => 'NO',
  'GENERATE_XML'          => 'NO',
  'GRAPHICAL_HIERARCHY'   => 'YES',
  'HAVE_DOT'              => 'YES',
  'HIDE_SCOPE_NAMES'      => 'NO',
  'HIDE_UNDOC_CLASSES'    => 'NO',
  'HIDE_UNDOC_MEMBERS'    => 'NO',
  'HIDE_UNDOC_RELATIONS'  => 'NO',
  'HTML_ALIGN_MEMBERS'    => 'YES',
  'HTML_FOOTER'           => '',
  'HTML_HEADER'           => '',
  'HTML_OUTPUT'           => 'html',
  'HTML_STYLESHEET'       => '',
  'IGNORE_PREFIX'         => '',
  'IMAGE_PATH'            => '',
  'INCLUDED_BY_GRAPH'     => 'YES',
  'INCLUDE_FILE_PATTERNS' => '*.h *.hpp',
  'INCLUDE_GRAPH'         => 'YES',
  'INCLUDE_PATH'          => '',
  'INHERIT_DOCS'          => 'YES',
  'INLINE_INFO'           => 'YES',
  'INLINE_SOURCES'        => 'YES',
  'INPUT'                 => '',
  'INPUT_FILTER'          => '',
  'INTERNAL_DOCS'         => 'NO',
  'JAVADOC_AUTOBRIEF'     => 'NO',
  'LATEX_BATCHMODE'       => 'NO',
  'LATEX_HEADER'          => '',
  'LATEX_OUTPUT'          => 'latex',
  'MACRO_EXPANSION'       => 'YES',
  'MAN_EXTENSION'         => '',
  'MAN_LINKS'             => '',
  'MAN_OUTPUT'            => 'man',
  'MAX_DOT_GRAPH_HEIGHT'  => '1024',
  'MAX_DOT_GRAPH_WIDTH'   => '1024',
  'MAX_INITIALIZER_LINES' => '30',
  'OPTIMIZE_OUTPUT_FOR_C' => 'NO',
  'OUTPUT_DIRECTORY'      => '',
  'OUTPUT_LANGUAGE'       => 'English',
  'PAPER_TYPE'            => 'a4wide',
  'PDF_HYPERLINKS'        => 'NO',
  'PERL_PATH'             => '/usr/bin/perl',
  'PREDEFINED'            => '',
  'PROJECT_NAME'          => 'Unnamed Project',
  'PROJECT_NUMBER'        => '0.0',
  'QUIET'                 => 'YES',
  'RECURSIVE'             => 'YES',
  'REFERENCED_BY_RELATION'=> '',
  'REFERENCES_RELATION'   => '',
  'REPEAT_BRIEF'          => 'YES',
  'RTF_EXTENSIONS_FILE'   => '',
  'RTF_HYPERLINKS'        => 'NO',
  'RTF_OUTPUT'            => 'rtf',
  'RTF_STYLESHEET_FILE'   => '',
  'SEARCHENGINE'          => 'NO',
  'SEARCH_INCLUDES'       => 'YES',
  'SHORT_NAMES'           => 'NO',
  'SHOW_INCLUDE_FILES'    => 'YES',
  'SHOW_USED_FILES'       => 'YES',
  'SKIP_FUNCTION_MACROS'  => 'YES',
  'SORT_MEMBER_DOCS'      => 'YES',
  'SOURCE_BROWSER'        => 'YES',
  'STRIP_CODE_COMMENTS'   => 'YES',
  'STRIP_FROM_PATH'       => '',
  'TAB_SIZE'              => '4',
  'TAGFILES'              => '',
  'TEMPLATE_RELATIONS'    => '',
  'TOC_EXPAND'            => 'NO',
  'TREEVIEW_WIDTH'        => '250',
  'USE_PDFLATEX'          => 'NO',
  'VERBATIM_HEADERS'      => 'YES',
  'WARNINGS'              => 'YES',
  'WARN_FORMAT'           => '',
  'WARN_IF_UNDOCUMENTED'  => 'YES',
  'WARN_LOGFILE'          => '',
};

###============================================================================
###@@ Basic Methods
###============================================================================

sub new
{
  my $type = shift;
  my $self = $doxygen_defaults;
  bless $self, $type;
}

###============================================================================
###@@ Misc Methods
###============================================================================

# Modify config params so that only HTML output will be generated.
sub html_only()
{
  my $self = shift;

  $self->{"GENERATE_HTML"}  	= "YES";
  $self->{"GENERATE_HTMLHELP"} 	= "NO";
  $self->{"GENERATE_LATEX"} 	= "NO";
  $self->{"GENERATE_RTF"}   	= "NO";
  $self->{"GENERATE_MAN"}   	= "NO";
  $self->{"GENERATE_XML"}   	= "NO";
}

# $obj->run_doxygen( dir )
#   dir = directory to which to cd before running doxygen
# This creates the doxygen config file as well.
sub run_doxygen()
{
  my $self = shift;
  my $dir  = shift;
  local *FH;

  open(FH, ">$dir/Doxyfile")
      || die "Can't open $dir/Doxyfile for output";
  $self->print_config_file(FH);
  close(FH);

  print "Running doxygen ...\n";
  print "    INPUT  = $self->{INPUT}\n";
  print "    OUTPUT = $self->{OUTPUT_DIRECTORY}\n";
  my $beg = time;
  system "cd $dir; doxygen Doxyfile;";
  my $end = time;
  my $minutes = int ($end - $beg) / 60;
  my $seconds = ($end - $beg) % 60;
  print "Running doxygen ... done.\n";
  print "Elapsed time is $minutes min $seconds sec.\n";
}

###============================================================================
###@@ Print Configuration File
###============================================================================
#
# print_config_file() is the top-level method.

# Utility used by other function.
sub print_header()
{
  my $self = shift;
  local *FH = shift;
  my ($name) = @_;

  print FH "\n";
  print FH "#----------------------------------------------------------------\n";
  print FH "# $name configuration options\n";
  print FH "#----------------------------------------------------------------\n";
  print FH "\n";
}

# Utility used by other function.
sub print_an_option()
{
  my $self   = shift;
  local *FH  = shift;
  my $name   = shift;
  my $value  = $doxygen_defaults->{"$name"};
  my $spaces = 24 - length($name);
  $spaces = 0 if $spaces < 0;
  print FH "$name" . " " x $spaces . "= " . $value . "\n";
}

sub print_general_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "General");
  $self->print_an_option(FH, "PROJECT_NAME");
  $self->print_an_option(FH, "PROJECT_NUMBER");
  $self->print_an_option(FH, "OUTPUT_DIRECTORY");
  $self->print_an_option(FH, "OUTPUT_LANGUAGE");
  $self->print_an_option(FH, "EXTRACT_ALL");
  $self->print_an_option(FH, "EXTRACT_PRIVATE");
  $self->print_an_option(FH, "EXTRACT_STATIC");
  $self->print_an_option(FH, "HIDE_UNDOC_MEMBERS");
  $self->print_an_option(FH, "HIDE_UNDOC_CLASSES");
  $self->print_an_option(FH, "BRIEF_MEMBER_DESC");
  $self->print_an_option(FH, "REPEAT_BRIEF");
  $self->print_an_option(FH, "ALWAYS_DETAILED_SEC");
  $self->print_an_option(FH, "FULL_PATH_NAMES");
  $self->print_an_option(FH, "STRIP_FROM_PATH");
  $self->print_an_option(FH, "INTERNAL_DOCS");
  $self->print_an_option(FH, "STRIP_CODE_COMMENTS");
  $self->print_an_option(FH, "CASE_SENSE_NAMES");
  $self->print_an_option(FH, "SHORT_NAMES");
  $self->print_an_option(FH, "HIDE_SCOPE_NAMES");
  $self->print_an_option(FH, "VERBATIM_HEADERS");
  $self->print_an_option(FH, "SHOW_INCLUDE_FILES");
  $self->print_an_option(FH, "JAVADOC_AUTOBRIEF");
  $self->print_an_option(FH, "INHERIT_DOCS");
  $self->print_an_option(FH, "INLINE_INFO");
  $self->print_an_option(FH, "SORT_MEMBER_DOCS");
  $self->print_an_option(FH, "DISTRIBUTE_GROUP_DOC");
  $self->print_an_option(FH, "TAB_SIZE");
  $self->print_an_option(FH, "GENERATE_TODOLIST");
  $self->print_an_option(FH, "GENERATE_TESTLIST");
  $self->print_an_option(FH, "GENERATE_BUGLIST");
  $self->print_an_option(FH, "ALIASES");
  $self->print_an_option(FH, "ENABLED_SECTIONS");
  $self->print_an_option(FH, "MAX_INITIALIZER_LINES");
  $self->print_an_option(FH, "OPTIMIZE_OUTPUT_FOR_C");
  $self->print_an_option(FH, "SHOW_USED_FILES");
}

sub print_warnings_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Warnings");
  $self->print_an_option(FH, "QUIET");
  $self->print_an_option(FH, "WARNINGS");
  $self->print_an_option(FH, "WARN_IF_UNDOCUMENTED");
  $self->print_an_option(FH, "WARN_FORMAT");
  $self->print_an_option(FH, "WARN_LOGFILE");
}

sub print_input_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Input");
  $self->print_an_option(FH, "INPUT");
  $self->print_an_option(FH, "FILE_PATTERNS");
  $self->print_an_option(FH, "RECURSIVE");
  $self->print_an_option(FH, "EXCLUDE");
  $self->print_an_option(FH, "EXCLUDE_PATTERNS");
  $self->print_an_option(FH, "EXAMPLE_PATH");
  $self->print_an_option(FH, "EXAMPLE_PATTERNS");
  $self->print_an_option(FH, "EXAMPLE_RECURSIVE");
  $self->print_an_option(FH, "IMAGE_PATH");
  $self->print_an_option(FH, "INPUT_FILTER");
  $self->print_an_option(FH, "FILTER_SOURCE_FILES");
}

sub print_browsing_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Source Browsing");
  $self->print_an_option(FH, "SOURCE_BROWSER");
  $self->print_an_option(FH, "INLINE_SOURCES");
  $self->print_an_option(FH, "REFERENCED_BY_RELATION");
  $self->print_an_option(FH, "REFERENCES_RELATION");
}

sub print_class_index_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Class Index");
  $self->print_an_option(FH, "ALPHABETICAL_INDEX");
  $self->print_an_option(FH, "COLS_IN_ALPHA_INDEX");
  $self->print_an_option(FH, "IGNORE_PREFIX");
}

sub print_html_output_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "HTML Output");
  $self->print_an_option(FH, "GENERATE_HTML");
  $self->print_an_option(FH, "HTML_OUTPUT");
  $self->print_an_option(FH, "HTML_HEADER");
  $self->print_an_option(FH, "HTML_FOOTER");
  $self->print_an_option(FH, "HTML_STYLESHEET");
  $self->print_an_option(FH, "HTML_ALIGN_MEMBERS");
  $self->print_an_option(FH, "GENERATE_HTMLHELP");
  $self->print_an_option(FH, "GENERATE_CHI");
  $self->print_an_option(FH, "BINARY_TOC");
  $self->print_an_option(FH, "TOC_EXPAND");
  $self->print_an_option(FH, "DISABLE_INDEX");
  $self->print_an_option(FH, "ENUM_VALUES_PER_LINE");
  $self->print_an_option(FH, "GENERATE_TREEVIEW");
  $self->print_an_option(FH, "TREEVIEW_WIDTH");
}

sub print_latex_output_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "LaTeX Output");
  $self->print_an_option(FH, "GENERATE_LATEX");
  $self->print_an_option(FH, "LATEX_OUTPUT");
  $self->print_an_option(FH, "COMPACT_LATEX");
  $self->print_an_option(FH, "PAPER_TYPE");
  $self->print_an_option(FH, "EXTRA_PACKAGES");
  $self->print_an_option(FH, "LATEX_HEADER");
  $self->print_an_option(FH, "PDF_HYPERLINKS");
  $self->print_an_option(FH, "USE_PDFLATEX");
  $self->print_an_option(FH, "LATEX_BATCHMODE");
}

sub print_rtf_output_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "RTF Output");
  $self->print_an_option(FH, "GENERATE_RTF");
  $self->print_an_option(FH, "RTF_OUTPUT");
  $self->print_an_option(FH, "COMPACT_RTF");
  $self->print_an_option(FH, "RTF_HYPERLINKS");
  $self->print_an_option(FH, "RTF_STYLESHEET_FILE");
  $self->print_an_option(FH, "RTF_EXTENSIONS_FILE");
}

sub print_man_output_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Man Page Output");
  $self->print_an_option(FH, "GENERATE_MAN");
  $self->print_an_option(FH, "MAN_OUTPUT");
  $self->print_an_option(FH, "MAN_EXTENSION");
  $self->print_an_option(FH, "MAN_LINKS");
}

sub print_xml_output_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "XML Output");
  $self->print_an_option(FH, "GENERATE_XML");
}

sub print_preprocessor_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Preprocessor");
  $self->print_an_option(FH, "ENABLE_PREPROCESSING");
  $self->print_an_option(FH, "MACRO_EXPANSION");
  $self->print_an_option(FH, "EXPAND_ONLY_PREDEF");
  $self->print_an_option(FH, "SEARCH_INCLUDES");
  $self->print_an_option(FH, "INCLUDE_PATH");
  $self->print_an_option(FH, "INCLUDE_FILE_PATTERNS");
  $self->print_an_option(FH, "PREDEFINED");
  $self->print_an_option(FH, "EXPAND_AS_DEFINED");
  $self->print_an_option(FH, "SKIP_FUNCTION_MACROS");
}

sub print_external_ref_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "External Reference");
  $self->print_an_option(FH, "TAGFILES");
  $self->print_an_option(FH, "GENERATE_TAGFILE");
  $self->print_an_option(FH, "ALLEXTERNALS");
  $self->print_an_option(FH, "PERL_PATH");
}

sub print_dot_tool_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Dot tool");
  $self->print_an_option(FH, "CLASS_DIAGRAMS");
  $self->print_an_option(FH, "HAVE_DOT");
  $self->print_an_option(FH, "CLASS_GRAPH");
  $self->print_an_option(FH, "COLLABORATION_GRAPH");
  $self->print_an_option(FH, "TEMPLATE_RELATIONS");
  $self->print_an_option(FH, "HIDE_UNDOC_RELATIONS");
  $self->print_an_option(FH, "INCLUDE_GRAPH");
  $self->print_an_option(FH, "INCLUDED_BY_GRAPH");
  $self->print_an_option(FH, "GRAPHICAL_HIERARCHY");
  $self->print_an_option(FH, "DOT_PATH");
  $self->print_an_option(FH, "DOTFILE_DIRS");
  $self->print_an_option(FH, "MAX_DOT_GRAPH_WIDTH");
  $self->print_an_option(FH, "MAX_DOT_GRAPH_HEIGHT");
  $self->print_an_option(FH, "GENERATE_LEGEND");
  $self->print_an_option(FH, "DOT_CLEANUP");
}

sub print_search_engine_section()
{
  my $self = shift;
  local *FH = shift;
  $self->print_header(FH, "Search Engine");
  $self->print_an_option(FH, "SEARCHENGINE");
  $self->print_an_option(FH, "CGI_NAME");
  $self->print_an_option(FH, "CGI_URL");
  $self->print_an_option(FH, "DOC_URL");
  $self->print_an_option(FH, "DOC_ABSPATH");
  $self->print_an_option(FH, "BIN_ABSPATH");
  $self->print_an_option(FH, "EXT_DOC_PATHS");
}

sub print_config_file()
{
  my $self = shift;
  local *FH = shift;
  my $now_string = localtime;  # e.g. "Thu Oct 13 04:54:34 1994"

  print FH "# Doxygen Configuration File for version 1.2.12\n";
  print FH "# DO NOT EDIT THIS FILE!\n";
  print FH "# It was generated by $this_prog perl script on $now_string.\n\n";

  $self->print_general_section(FH);
  $self->print_warnings_section(FH);
  $self->print_input_section(FH);
  $self->print_browsing_section(FH);
  $self->print_class_index_section(FH);
  $self->print_html_output_section(FH);
  $self->print_latex_output_section(FH);
  $self->print_rtf_output_section(FH);
  $self->print_man_output_section(FH);
  $self->print_xml_output_section(FH);
  $self->print_preprocessor_section(FH);
  $self->print_external_ref_section(FH);
  $self->print_dot_tool_section(FH);
  $self->print_search_engine_section(FH);
}


###****************************************************************************
###@ Samples
###****************************************************************************

# $obj->generate_sample(1) creates ./sample1 directory, creates sample.cpp file
# in that directory, then runs doxygen in that directory.
# $obj->generate_sample(2) and $obj->generate_sample(3) are also valid.
sub generate_sample()
{
  my $self = shift;
  my $num  = shift;
  my $sdir = "sample$num";
  my $cfg   = "$sdir/Doxyfile";
  local *FH;

  mkdir "$sdir" unless -d "$sdir";

  $self->{"PROJECT_NAME"} 	= "Sample #$num";
  $self->{"INPUT"} 		= "$sdir";
  $self->{"OUTPUT_DIRECTORY"} 	= "$sdir";

  $self->{"GENERATE_HTML"}  	= "YES";
  $self->{"GENERATE_HTMLHELP"} 	= "YES";
  $self->{"GENERATE_CHI"} 	= "YES";
  $self->{"GENERATE_LATEX"} 	= "YES";
  $self->{"GENERATE_RTF"}   	= "YES";
  $self->{"GENERATE_MAN"}   	= "YES";
  $self->{"GENERATE_XML"}   	= "YES";

  open(FH, ">$cfg") || die "Can't open $cfg for output";
  $self->print_config_file(FH);
  close(FH);

  if ( $num == 3 )
  {
    # This case should be handled by the "eval" line below.
    # However, this case doesn't work.
    # Don't know why this is the case. -ryk11/30/01.
    $self->create_sample_program3($sdir);
  }
  else
  {
    eval "\$self->create_sample_program$num($sdir);";
  }

  system "doxygen $cfg;";
}

###============================================================================
###@@ Sample #1
###============================================================================

# Private function called by generate_sample().
sub create_sample_program1 ()
{
  my $self  = shift;
  my $sdir  = shift;
  local *FH;
  my $samp  = "$sdir/sample.cpp";

  open(FH, ">$samp") || die "Can't open $samp for output";

  print FH <<EOF;
\#define MAC1 1

typedef enum
{
  ENUM_ONE,
  ENUM_TWO,
  ENUM_THREE,
} EnumOne;

typedef struct
{
  int m_one;
  int m_two;
} StructOne;

int
f1()
{
}

int
f2()
{
}

int
main()
{
    int i, j;
    EnumOne e1;
    StructOne s1;

    f1();
    f2();
}
EOF

    close(FH);
}

###============================================================================
###@@ Sample #2
###============================================================================

# Private function called by generate_sample().
sub create_sample_program2 ()
{
  my $self  = shift;
  my $sdir  = shift;
  local *FH;
  my $samp  = "$sdir/sample.cpp";

  $self->create_sample_header2($sdir);

  open(FH, ">$samp") || die "Can't open $samp for output";

  print FH <<EOF;

\#include "sample.h"
  
/**
 * This is the first function.  f2() is the second.
 * This uses #MAC1 macro.
 */
int
f1()
{
  int i = MAC1;
}

int
f2()
{
}

/**
 * This is the main function.
 * Functions called include:
 * - f1()
 * - f2()
 */
int
main()
{
    int i, j;
    EnumOne e1;
    StructOne s1;

    f1();
    f2();
}
EOF

    close(FH);
}

# Private function.
sub create_sample_header2 ()
{
  my $self  = shift;
  my $sdir  = shift;
  local *FH;
  my $samp  = "$sdir/sample.h";

  open(FH, ">$samp") || die "Can't open $samp for output";

  print FH <<EOF;
/**
 * MAC1 is the first macro.
 */  
\#define MAC1 1

/**
 * EnumOne has three enums.
 */
typedef enum
{
  /**
   * ENUM_ONE is the first enum.
   */
  ENUM_ONE,
  /**
   * ENUM_TWO is the second enum.
   */
  ENUM_TWO,
  /**
   * ENUM_THREE is the third enum.
   */
  ENUM_THREE,
} EnumOne;

/**
 * StructOne has only two members.
 */
typedef struct
{
  int m_one;
  int m_two;
} StructOne;
EOF

    close(FH);
}

###============================================================================
###@@ Sample #3
###============================================================================

# Private function called by generate_sample().
sub create_sample_program3 ()
{
  my $self  = shift;
  my $sdir  = shift;
  local *FH;
  my $samp  = "$sdir/sample.cpp";

  $self->create_sample_header3($sdir);

  open (FH, ">$samp") || die "Can't open $samp for output";

  print FH <<'EOF';

\#include "sample.h"

/**
 * 
 * @mainpage Sample Project
 * 
 * @section intro Introduction
 * 
 * This is @b introduction section.
 * 
 * The second section, @ref sec2, documents the second section.
 * which has a subsection, @ref subsec2, as well.
 * 
 * @section sec2 The Second Section
 * 
 * This is the second section.
 * 
 * @subsection subsec2 The Second Section First Subsection
 * 
 */

/**
 * @defgroup g1 Group1
 *
 * This is the first group created via the @b defgroup command.
 */

/**
 * @defgroup g1a Group1a
 * @ingroup g1
 *
 * This is the first sub group created via the @b defgroup and
 * @b ingroup commands.
 */

/**
 * @defgroup g2 Group2
 *
 * This is the second group created via the @b defgroup command.
 */

/**
 * @defgroup g2a Group2a
 * @ingroup g2
 *
 * This is a sub group created via the @b defgroup and
 * @b ingroup commands.
 * The firs group, @ref g1, comes before this.
 */

/**
 * This is the first function.  f2() is the second.
 * This uses #MAC1 macro.
 */
int
f1()
{
  int i = MAC1;
}

int
f2()
{
}

/**
 * This is the main function.
 * Functions called include:
 * - f1()
 * - f2()
 */
int
main()
{
    int i, j;
    EnumOne e1;
    StructOne s1;

    f1();
    f2();
}
EOF

    close FH;
}

# Private function
sub create_sample_header3 ()
{
  my $self = shift;
  my $sdir = shift;
  local *FH;
  my $samp = "$sdir/sample.h";

  open (FH, ">$samp") || die "Can't open $samp for output";
  
  print FH <<EOF;
/**
 * MAC1 is the first macro.
 */  
\#define MAC1 1

/**
 * EnumOne has three enums.
 */
typedef enum
{
  /**
   * ENUM_ONE is the first enum.
   */
  ENUM_ONE,
  /**
   * ENUM_TWO is the second enum.
   */
  ENUM_TWO,
  /**
   * ENUM_THREE is the third enum.
   */
  ENUM_THREE,
} EnumOne;

/**
 * StructOne has only two members.
 */
typedef struct
{
  int m_one;
  int m_two;
} StructOne;
EOF

    close FH;
}

###****************************************************************************
###@ Documentation
###****************************************************************************

1;

__END__

=head1 NAME

Doxygen - utilities to create doxygen config files and run doxygen.

=head1 SYNOPSIS

    use Doxygen;

    # $dox is a reference to a hash table with doxygen configuration
    # parameters as the key.  The default values should be good for C/C++
    # projects with HTML output only.
    my $dox = Doxygen->new;

    # Any config param can be modified.
    $dox->{"PROJECT_NAME"}     = "Project Name";
    $dox->{"INPUT"}            = "src/include src/common src/project";
    $dox->{"OUTPUT_DIRECTORY"} = "doxygen_out";

    # Run doxygen by taking these steps:
    # - change directory to $dir
    # - create $dir/Doxyfile configuration file
    # - run doxygen
    my $dir = ".";
    $dox->run_doxygen($dir);

    # Other misc methods are described below.

    # Generate ./sample1 directory with a sample C++ file, then run doxygen
    # to generate all output types.
    $dox->generate_sample( 1 );

    $dox->generate_sample( 2 );		# generate ./sample2 tree

    $dox->generate_sample( 3 );		# generate ./sample3 tree

    # Print the configuration file to stdout.
    $self->print_config_file(STDOUT);

=head1 DESCRIPTION

The goal is to allow one to write Perl scripts to control Doxygen easily.

=cut

