#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell

###############################################################################
# Runs krazy over the KDE source code for the EnglishBreakfastNetwork (EBN)   #
# Copyright 2006-2008 by Allen Winter <winter@kde.org>                        #
# Copyright 2009      by Bertjan Broeksema <b.broeksema@kdemail.net>          #
#                                                                             #
# This program 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 of the License, or           #
# (at your option) any later version.                                         #
#                                                                             #
# This program 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 General Public License for more details.                                #
#                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.               #
#                                                                             #
###############################################################################
# Program options:
#   --help:            display help message and exit
#   --version:         display version information and exit
#   --dry-run:         don't execute the checks; only show what would be run
#   --nodb:            don't execute any database commands
#   --nosaxon          don't execute the xslt transformations.
#   --component [comp] process component 'comp'
#   --module [mod1<,mod2,..>]
#                      process module list from component 'comp'
#   --title [title]    the title to print on the output reports
#
use strict;
use Getopt::Long;
use Env qw (PSQL);
use Sys::Hostname;
use File::Basename;
use File::Copy;
use File::Find;
use File::Path;
use POSIX qw (strftime);
use FindBin qw($Bin);
use lib "$Bin/../lib";
use Krazy::Config;
use Krazy::Utils;

my ($Prog) = 'krazy2xml';
my
 $VERSION = '0.1';    #split line so MakeMaker can find the version here

my (@modules);    # list of modules to process.  change as desired.
my ($comp);       # default component to process
my ($module);     # default module to process (empty implies ALL modules)
my ($tempdir);    # fullpath to the top level temporary output directory
my ($destdir);    # fullpath to the top level output directory
my ($trunk);      # fullpath to the top level of the trunk checkout
my ($krazy);      # fullpath to the krazy program
my ($plgpth);     # fullpath to the krazy plugins
my ($xtrpth);     # fullpath to the krazy extras
my ($PSQL);       # fullpath to the psql program
my ($md5);        # fullpath to the md5sum checksum program
my ($svn);        # fullpath to the svnlook program
my ($repos);      # fullpath to the svn repository (where svnlook looks)
my ($checks);     # The list of checks to be executed.

my ($saxon);      # fullpath to the saxon program
my ($stylesheet); # full path to the main stylesheet (krazy-main.xsl)

if ( hostname() =~ m/englishbreakfast/ ) {
  $tempdir    = '/usr/local/www/data-ebn/krazy/temp';
  $destdir    = '/usr/local/www/data-ebn/krazy/reports';
  $comp       = 'kde-4.x';
  $module     = '';
  $trunk      = '/usr/local/src';
  $krazy      = '/usr/local/www/data-ebn/krazy/bin/krazy2';
  $plgpth     = '/usr/local/www/data-ebn/krazy/lib/krazy2/krazy-plugins';
  $xtrpth     = '/usr/local/www/data-ebn/krazy/lib/krazy2/krazy-extras';
  $PSQL       = '/usr/local/bin/psql' if ( !$PSQL );
  $md5        = '/sbin/md5';
  $svn        = '/usr/local/bin/svnlook youngest';
  $repos      = '/home/svn/home/kde';
  $checks     = ''; # execute all checks.
  $saxon      = '/usr/local/bin/saxon';
  $stylesheet = '/usr/local/www/data-ebn/krazy/share/xsl/krazy-main.xsl';
} else {

  # my system settings for testing
  $tempdir    = '/home/developer/data/krazy2/temp';
  $destdir    = '/home/developer/data/krazy2/reports';
  $comp       = 'kde-4.x';
  $module     = '';
  $trunk      = '/home/developer/data/kde/trunk';
  $krazy      = '/home/developer/local/bin/krazy2';
  $plgpth     = '/home/developer/local/lib/krazy2/krazy-plugins';
  $xtrpth     = '/home/developer/local/krazy2/krazy-extras';
  $md5        = '/usr/bin/md5sum';
  $svn        = '/usr/bin/svn info';
  $repos      = '/home/developer/data/kde';
  $checks     = '--check typedefs'; # Only execute some checks, so we don't have to wait an eternity.
  $saxon      = '/usr/bin/saxon8';
  $stylesheet = '/home/developer/local/share/xsl/krazy-main.xsl';
}

#END OF SETTINGS

my ($help)    = '';
my ($version) = '';
my ($dryrun)  = '';
my ($nodb) = '';
my ($nosaxon) = '';
my ($reptitle) = '';

exit 1
  if ( !GetOptions(
       'help'        => \$help,
       'version'     => \$version,
       'dry-run'     => \$dryrun,
       'nodb'        => \$nodb,
       'nosaxon'     => \$nosaxon,
       'component=s' => \$comp,
       'module=s'    => \$module,
       'title=s'     => \$reptitle
      )
     );

&Help()    if ($help);
&Version() if ($version);

# Setup for db
my($hasdb) = !$nodb; # Added for convenience.
$PSQL="" if ($nodb);

my ($compId) = '';
my ($toolId) = '';
my ($generation) = '';

if ($hasdb) {
  $compId = &execSql("\"SELECT id FROM components WHERE name='$comp';\"");
  if ( !$compId || $compId eq "0" ) {
    die "Error: Cannot get Component Id for $comp\n";
  }

  $toolId = &execSql("\"SELECT id FROM tools WHERE name='krazy' AND component=$compId;\"");
  if ( !$toolId || $toolId eq "0" ) {
    die "Error: Cannot get Tool Id for krazy and component $comp\n";
  }

  $generation = &execSql("\"SELECT * FROM nextval('generation');\"");
}

my ($svnRev) = '';
if ( hostname() =~ m/englishbreakfast/ ) {
  $svnRev = `$svn $repos`;
} else { # I don't have a copy of the repository, just a local checkout.
  $svnRev = `$svn $repos | grep Revision | awk '{print \$2}'`;
}
chomp($svnRev);
$svnRev = 0 if ( !$svnRev || $svnRev eq "0" );

# Global settings
my (@gIgModsList);    #modules to ignore
my (@gIgSubsList) = ( #subdirs to ignore in all modules
  "doc",
  "cmake",
  "pics",
  "applnk",
  "admin"
);
my ($defRegex)   = "/////";
my ($gSkipRegex) = "$defRegex";    #regex of stuff to skip in a subdir
my ($gPriority)  = "high";         #priority. default is high
my ($gStrict)    = "normal";       #strictness. default is normal
my (@gCheckList);                  #plugins to run. default is all
my (@gExcludeList);                #plugins to exclude. default is none
my (@gExtraList);                  #extra plugins. default is none

# Per Module settings
my (@mIgSubsList);
my ($mSkipRegex) = "";
my ($mPriority) = "";
my ($mStrict) = "";
my (@mCheckList);
my (@mExcludeList);
my (@mExtraList);

# Per Subdir settings
my ($sSkipRegex) = "";
my ($sPriority) = "";
my ($sStrict) = "";
my (@sCheckList);
my (@sExcludeList);
my (@sExtraList);

# Override Global settings from the component .krazy file
&mergeComponentSettings("$trunk/$comp");

push( @modules, split( ",", $module ) ) if ($module);

# Create the module list
my ($m);
if ( $#modules < 0 ) {
  my ( $im, $found );
  opendir( DIR, "$trunk/$comp" ) or die "Error: Cannot open $trunk/$comp: $!";
  while ( defined( $m = readdir(DIR) ) ) {
    next unless ( -d "$trunk/$comp/$m" );
# allow kdebase-foo    next if ( -l "$trunk/$comp/$m" );    #skip symlinks
    next if ( $m eq "." );               #skip cwd
    next if ( $m eq ".." );              #skip parent dir
    next if ( $m eq ".svn" );            #skip .svn
    $found = 0;
    for $im (@gIgModsList) {
      if ( $im eq $m ) {                 #IGNOREMODS from component-level .krazy
        $found = 1;
        last;
      }
    }
    push @modules, $m unless $found;
  }
}

# Let's doit!
my (@subdirs);

&myMkdir("$tempdir/$comp") if (! -d "$tempdir/$comp");

# This is the same for all modules so generate only once
print "  Generating $comp/tool-list.xml\n";
my $command = "$krazy --export=xml --list --explain > $tempdir/$comp/tool-list.xml";
system("$command");

for $m (@modules) {
  print "  [$m]\n";
  &myRmdir("$tempdir/$comp/$m");
  &myMkdir("$tempdir/$comp/$m");

  # Create two required files for xmltodb:
  # 1) tool-list.xml
  print "    Copying tool-list.xml to module dir\n";
  copy("$tempdir/$comp/tool-list.xml", "$tempdir/$comp/$m/tool-list.xml");

  # 2) component.info
  print "    Generating $comp/$m/component.info\n";
  open(COMPINFO,">$tempdir/$comp/$m/component.info") || die("Cannot Open component.info");
  print COMPINFO "component=$comp\n";
  print COMPINFO "module=$m\n";
  print COMPINFO "revision=$svnRev\n";
  close(COMPINFO);

  @subdirs = ();
  if ( -f "$trunk/$comp/$m/CMakeLists.txt" ) {
    &subdirsFromCMakeList("$trunk/$comp/$m/CMakeLists.txt");
  } else {
    if ( -f "$trunk/$comp/$m/subdirs" ) {
      &subdirsFromSubdirs("$trunk/$comp/$m/subdirs");
    } else {
      &subdirsFromAll("$trunk/$comp/$m");
    }
  }
  &mergeModuleSettings("$trunk/$comp/$m");
  &doItForList( "$m", $svnRev );
  &myMkdir("$destdir/$comp/$m");
  &myMvdir("$tempdir/$comp/$m", "$destdir/$comp/$m");
}

# Update our generation field in the tools table.
if ($hasdb) {
  &execSql("\"UPDATE tools SET generation=$generation WHERE id=$toolId;\"");

  # Put a summary of this run into the generations table.
  my ($now) = `date "+%B %d %Y %T"`;
  chomp $now;
  &execSql("\"INSERT INTO generations VALUES ($generation, '$now',"
    . "(SELECT SUM(issues) FROM results_krazy WHERE component='$compId' "
    . " AND generation=$generation), $toolId, $svnRev );\"");
}

#==============================================================================

#override global settings from component-level directives
sub mergeComponentSettings {
  my ($rc) = @_;
  $rc .= "/.krazy";

  my (%d) = ParseKrazyRC($rc);

  @gIgModsList = @{ $d{'IGMODSLIST'} } if ( $#{ $d{'IGMODSLIST'} } >= 0 );
  @gIgSubsList = @{ $d{'IGSUBSLIST'} } if ( $#{ $d{'IGSUBSLIST'} } >= 0 );

  if ( $d{'SKIPREGEX'} ) {
    $gSkipRegex = $d{'SKIPREGEX'};
    $gSkipRegex =~ s+\|+\\\|+g;
  }

  $gPriority = $d{'PRIORITY'} if ( $d{'PRIORITY'} );
  $gStrict = $d{'STRICT'} if ( $d{'STRICT'} );

  @gExcludeList = split( ",", $d{'EXCLUDE'} ) if ( $d{'EXCLUDE'} );
  @gExtraList   = split( ",", $d{'EXTRA'} )   if ( $d{'EXTRA'} );
  #do not allow CHECK at the component-level
  #@gCheckList   = split( ",", $d{'CHECK'} )   if ( $d{'CHECK'} );
}

#merge global settings with module-level directives
sub mergeModuleSettings {
  my ($rc) = @_;
  $rc .= "/.krazy";

  my (%d) = ParseKrazyRC($rc);

  @mIgSubsList = @gIgSubsList;
  push( @mIgSubsList, @{ $d{'IGSUBSLIST'} } ) if ( $#{ $d{'IGSUBSLIST'} } >= 0 );
  deDupe(@mIgSubsList);

  $mSkipRegex = $gSkipRegex;
  my ($tmpstr) = "";
  $tmpstr = $d{'SKIPREGEX'} if ( $d{'SKIPREGEX'} );
  $tmpstr =~ s+\|+\\\|+g;
  if ( $mSkipRegex ne $defRegex ) {
    $mSkipRegex = $mSkipRegex . "\\|" . $tmpstr if ( $tmpstr );
  } else {
    $mSkipRegex = $tmpstr if ( $tmpstr );
  }

  #module priority and strictness overrides the global values
  $mPriority = $gPriority;
  $mPriority = $d{'PRIORITY'} if ( $d{'PRIORITY'} );
  $mStrict = $gStrict;
  $mStrict = $d{'STRICT'} if ( $d{'STRICT'} );

  @mExcludeList = @gExcludeList;
  push( @mExcludeList, split( ",", $d{'EXCLUDE'} ) ) if ( $d{'EXCLUDE'} );
  deDupe(@mExcludeList);

  @mExtraList = @gExtraList;
  push( @mExtraList, split( ",", $d{'EXTRA'} ) ) if ( $d{'EXTRA'} );
  deDupe(@mExtraList);

  @mCheckList = @gCheckList;
  push( @mCheckList, split( ",", $d{'CHECK'} ) ) if ( $d{'CHECK'} );
  deDupe(@mCheckList);
}

#merge module-level directives with subdir-level directives
sub mergeSubdirSettings {
  my ($rc) = @_;
  $rc .= "/.krazy";

  my (%d) = ParseKrazyRC($rc);

  $sSkipRegex = $mSkipRegex;
  my ($tmpstr) = "";
  $tmpstr = $d{'SKIPREGEX'} if ( $d{'SKIPREGEX'} );
  $tmpstr =~ s+\|+\\\|+g;
  if ( $sSkipRegex ne $defRegex ) {
    $sSkipRegex = $sSkipRegex . "\\|" . $tmpstr if ( $tmpstr );
  } else {
    $sSkipRegex = $tmpstr if ( $tmpstr );
  }

  #subdir priority and strictness overrides the module values
  $sPriority = $mPriority;
  $sPriority = $d{'PRIORITY'} if ( $d{'PRIORITY'} );
  $sStrict = $mStrict;
  $sStrict = $d{'STRICT'} if ( $d{'STRICT'} );

  @sExcludeList = @mExcludeList;
  push( @sExcludeList, split( ",", $d{'EXCLUDE'} ) ) if ( $d{'EXCLUDE'} );
  deDupe(@sExcludeList);

  @sExtraList = @mExtraList;
  push( @sExtraList, split( ",", $d{'EXTRA'} ) ) if ( $d{'EXTRA'} );
  deDupe(@sExtraList);

  @sCheckList = @mCheckList;
  push( @sCheckList, split( ",", $d{'CHECK'} ) ) if ( $d{'CHECK'} );
  deDupe(@sCheckList);
}

sub doItForList {
  my (
    $module,    # module
    $rev
  ) = @_;

  my ( $s, $is );
  my ($checksum);
  my ( $out, @issues, $iss );
  if ( $#subdirs >= 0 ) {
    for $s (@subdirs) {

      $out = "$tempdir/$comp/$module/$s";
      &myMkdir("$out");
      $checksum = 0;
      $iss      = 0;
      if ( &inIgnoreSubs($s) ) {
        print "    Ignoring $comp/$module/$s\n";
        &createIgnorePage( "$out", "$comp/$module/$s" ) if (!$nosaxon);
      } else {
        &mergeSubdirSettings( "$trunk/$comp/$module/$s" );
        &doIt( "$trunk/$comp/$module/$s", "$out", "$comp/$module/$s", $rev );
        if ( -f "$out/index.html" && `grep "Total Issues" $out/index.html` ) {
          (@issues) =
            split( " ", `grep "Total Issues" $out/index.html | head -1` );
          $iss = $issues[3];

          #compute checksum (grep out the date, which changes every run)
          ($checksum) =
            split( " ", `grep -v "\.\.\.as of" $out/index.html | $md5` );
        }
      }
      if ($hasdb) {
        &execSql("\"INSERT INTO results_krazy "
               . "(checksum, issues, report, component, module, application, generation ) "
               . "VALUES ( '$checksum', $iss, '$comp/$module/$s/index.html'"
               .        ", '$compId', '$module', '$s', $generation );\"");
      }
    }
  }
}

sub doIt {
  my (
    $in,     # dir to process
    $out,    # dir to write the report
    $cms,    # component/module/subdir
    $rev     # svn revision
  ) = @_;

  my ($t);

  #subtract checkList from excludeList
  &removeChecksFromExcludes();

  $t = &arrayToCSL(@sExcludeList);
  my ($exclude) = "";
  $exclude = "--exclude=$t" if ($t);

  $t = &arrayToCSL(@sExtraList);
  my ($extra) = "";
  $extra = "--extra=$t" if ($t);

  my ($skip) = $sSkipRegex;
  if ( $skip ne $defRegex && $skip ne "" ) {
    print "    Processing $cms (without $skip)\n";
  } else {
    print "    Processing $cms\n";
  }

  my ($priority) = "";
  $priority = "--priority=$sPriority" if ($sPriority);

  my ($strict) = "";
  $strict = "--strict=$sStrict" if ($sStrict);

  my ($title);
  if ($reptitle) {
    $title = $reptitle;
  } else {
    $title = "Results for $cms";
  }

  my ($command) =
 "cd $in; find . -name '*.tcc' -o -name '*.cpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.c' -o -name '*.h' -o -name '*.hxx' -o -name '*.ui' -o -name '*.desktop' -o -name '*.kcfg' -o -name Messages.sh -o -name '*.rc' -o -name tips -type f | grep -v '$skip' | xargs $krazy $checks --ignorerc $priority $strict --export=xml --explain --title \"$title\" -cms $cms --rev $rev $exclude $extra";
  if ($dryrun) {
    print "$command\n";
    $command = "echo " . "\'" . $command . "\'";
  }
  # Generate the xml report.
  $command = "$command" . " > " . "$out/result.xml";
  system("$command");

  # Probably no files to process resulting in an empty (0 byte) result.xml file.
  if (-z "$out/result.xml") {
    return;
  }

  # Translate the xml report to ebn website 
  # NOTE: This is imo a temporary solution. As soon as we store the results in
  #       the database in a fine grained enough manner, we can change te ebn site
  #       to be a php only site and not a mixture of php and krazy generated pages.
  my ( $component, $module, $subdir ) = split( "/", $cms );
  if (!$nosaxon) {
    $command = "$saxon -im krazy2ebn $out/result.xml $stylesheet component=$component module=$module submodule=$subdir > $out/index.html";
    system($command);
    # Make sure the file ends with a newline.
    if (-f "$out/index.html") {
      open( F, ">>$out/index.html" );
      print F "\n";
      close F;
    }
  }

  # TODO: translate the xml reports to SQL queries and execute them.

  # We're finished, remove the xml file.
  #$command = "rm $out/result.xml";
  #system($command);
}

sub subdirsFromCMakeList {
  my ($f) = @_;
  open( F, "$f" ) || die "Error: Cannot open $f";
  my ($line);
  while ( $line = <F> ) {
    $line =~ s/#.*$//;
    next unless ( $line =~ m/add_subdirectory/i );
    $line =~ s/macro_optional_//i;
    $line =~ s/add_subdirectory[[:space:]]*\(\s+(\S+)\s+\)/$1/i;
    $line =~ s/add_subdirectory[[:space:]]*\((\S+)\)/$1/i;
    $line =~ s/^\s+//;
    $line =~ s/\s+$//;
    push( @subdirs, $line );
  }
  close(F);
}

sub subdirsFromSubdirs {
  my ($f) = @_;
  (@subdirs) = split( "[[:space:]]", `cat $f` );
}

sub subdirsFromAll {
  my ($d) = @_;
  my ($s);
  if ( !-d $d ) {
    print "bad component or module specified... exiting\n";
    exit 1;
  }
  opendir( DIR, "$d" ) or die "Error: Cannot open $d: $!";
  while ( defined( $s = readdir(DIR) ) ) {
    next unless ( -d "$d/$s" );
    next if ( -l "$d/$s" );           #skip symlinks
    next if ( $s eq "." );            #skip cwd
    next if ( $s eq ".." );           #skip parent dir
    next if ( $s =~ /svn/ );          #skip .svn
    next if ( $s =~ /build/ );        #skip build dirs
    next if ( $s eq "admin" );
    next if ( $s eq "cmake" );
    next if ( $s eq "CMakeFiles" );
    next if ( $s eq "doc" );
    next if ( $s eq ".libs" );
    next if ( $s eq "Testing" );
    next if ( $s eq "lib" );
    next if ( $s eq "bin" );
    next if ( $s eq "pics" );
    next if ( $s eq "m4" );
    push( @subdirs, $s );
  }
}

sub removeChecksFromExcludes() {
  my (%count) = ();
  my ( @diff, $item );
  foreach $item ( @sExcludeList, @sCheckList ) {
    $count{$item}++;
  }
  foreach $item (@sExcludeList) {
    if ( $count{$item} == 1 ) {
      push( @diff, $item );
    }
  }
  @sExcludeList = @diff;
}

# determine if $s is found in @mIgSubsList
sub inIgnoreSubs {
  my ($s) = @_;
  my ($item);
  foreach $item (@mIgSubsList) {
    return 1 if ( $s eq $item );
  }
  return 0;
}

# turn array into a comma-separated list
sub arrayToCSL {
  my (@list) = @_;
  my ($item);
  my ($s) = "";
  foreach $item (@list) {
    $s .= $item . ",";
  }
  $s =~ s/,$//;
  return $s;
}

sub myMkdir {
  my ($d) = @_;
  if ( !-d "$d" ) {
    mkpath("$d") || die "Error: Cannot create directory $d: $!\n";
    chmod 0775, $d;
  }
}

sub myRmdir {
  my ($d) = @_;
  if ( -d "$d" ) {
    rmtree("$d") || die "Error: Cannot remove directory $d: $!\n";
  }
}

sub myMvdir {
  my ( $d1, $d2 ) = @_;
  &myRmdir($d2);
  if ( -d "$d1" ) {
    rename( $d1, $d2 ) || die "Error: Cannot move directory $d1 to $d2: $!\n";
    chmod 0775, $d2;
  }
}

sub execSql {
  if ($PSQL) {
    if ( $PSQL ne "debug" ) {
      return `echo @_ | $PSQL -t -h services.codeyard.net -U kde kde -A -q`;
    } else {
      print "echo @_ | PSQL -t -h services.codeyard.net -U kde kde -A -q\n";
    }
  }
}

# createIgnorePage: create an empty "ignore" page.
sub createIgnorePage {
  my ( $outdir, $cms ) = @_;
  my ($f) = "$outdir" . "/index.html";
  open( F, ">$f" ) || return;
  my ($title) = "Results for " . "$cms";
  print "$title\n";
  my ( $component, $module, $subdir ) = split( "/", $cms );
  my ($upcomp) = uc($component);
  $upcomp =~ s/-/ /;

  print F "<html>\n";
  print F "<head>\n";
  print F "<title>$title</title>\n";
  print F "<link rel=\"stylesheet\" type=\"text/css\" title=\"Normal\" href=\"/style.css\" />\n";
  print F "</head>\n";
  print F "<body>\n";
  print F "<div id=\"title\">\n";
  print F "<div class=\"logo\">&nbsp;</div>\n";
  print F "<div class=\"header\">\n";
  print F "<h1><a href=\"/\">English Breakfast Network</a></h1>\n";
  print F "<p><a href=\"/\">Almost, but not quite, entirely unlike tea.</a></p>\n";
  print F "</div>\n";
  print F "</div>\n";
  print F "<div id=\"content\">\n";
  print F "<div class=\"inside\">\n";

  # Links to other available reports
  if ( $component && $module && $subdir ) {
    print F "<p style=\"font-size: x-small;font-style: sans-serif;\">\n";
    print F "Other $module/$subdir reports:\n";
    print F "[<a href=\"/apidocs/apidox-$component/$module-$subdir.html\">APIDOX</a>]\n";
    print F "[<a href=\"/sanitizer/reports/$component/$module/$subdir/index.html\">Docs</a>]\n";
    print F "</p>\n";
  }

  print F "<h1>$title</h1>\n";
  print F "<p>Not processed per IGNORESUBS directive found in $component/.krazy or $module/.krazy file.<br>\n";

  print F " ...as of ";
  print F asOf();
  print F "</p>\n";
  print F "<ol>\n";

  print F "</ol>\n";
  print F "</div>\n";
  print F "</div>\n";
  print F "<div id=\"footer\">\n";
  print F "<p>Site content Copyright 2005-2007 by Adriaan de Groot,<br/>\n";
  print F "except images as indicated.</p>\n";
  print F "</div>\n";
  print F "</body>\n";
  print F "</html>\n";

  close F;
}

#==============================================================================
# Help function: print help message and exit.
sub Help {
  &Version();
  print "KDE source code checking for the English Breakfast Network (EBN)\n\n";
  print "Usage: $Prog [OPTION]... FILE...\n";
  print "  --help      display help message and exit\n";
  print "  --version   display version information and exit\n";
  print "  --dry-run   don't execute the checks; only show what would be run\n";
  print "  --nodb      don't execute any database commands\n";
  print "  --nosaxon   don't execute the xslt transformation\n";
  print "  --component component to process (default=\"$comp\")\n";
  print "  --module    [mod1<,mod2...>]\n";
  print "              comma-separated list of modules to process (default=ALL)\n";
  print "  --title     [title] the title to print on the output reports\n";

  print "\n";
  exit 0 if $help;
}

# Version function: print the version number and exit.
sub Version {
  print "$Prog, version $VERSION\n";
  exit 0 if $version;
}

__END__

#==============================================================================

=head1 NAME

krazy2ebn - KDE source code checking for the English Breakfast Network (EBN)

=head1 SYNOPSIS

krazy2ebn [options]

=head1 DESCRIPTION

krazy2ebn is a big wrapper around krazy(1) for no obvious use other than
generating Code Checking Quality reports on the English Breakfast Network.

=head1 OPTIONS

=over 4

=item B<--help>

Print help message and exit.

=item B<--version>

Print version information and exit.

=item B<--dry-run>

With this option the checker programs aren't run; instead, the command line
for each check that would be run is printed.

=item B<--nodb>

Set this option to turn-off all database operations.

=item B<--component>=[comp]

Only run for the specified KDE component. By default, the kde-4.0
component is assumed.

=item B<--module>=[mod1,<mod2>,...<modN>]

Only run for the specified KDE module within the component.
By default all modules within the component are processed.

=item B<--title>=title

A title string to print onto each report page. If this option is not provided,
a title for each page is generated that contains the source component,
module and subdir.

=back

=head1 EXAMPLES

=over 4

=item Process all modules within component extragear

 % krazy2ebn --component=extragear

=item Process module kdelibs within component kde-4.0

 % krazy2ebn --component=kde-4.0 --module=kdelibs

=back

=head1 ENVIRONMENT

KRAZY_PLUGIN_PATH - this is a colon-separated list of paths which is
searched when locating plugins. By default, plugins are searched for in
the path F<$TOP/lib/krazy2/krazy-plugins:krazy-plugins>.

KRAZY_EXTRA_PATH - this is a colon-separated list of paths which is
searched when locating "extra" plugins. By default, the "extras" are searched
for in the path F<$TOP/lib/krazy2/krazy-extras:krazy-extras>.

where $TOP is the top-level installation directory (eg. F</usr/local>, F</usr/local/Krazy2>)

=head1 EXIT STATUS

In normal operation, krazy2ebn exits with status 0.

If a command line option was incorrectly provided, krazy2ebn exits with
status=1.

If krazy2 was envoked with the B<--help> or B<--version> options it
will exit with status=0.

=head1 COPYRIGHT

Copyright (c) 2005-2007 by Allen Winter <winter@kde.org>

This program 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 of the License, or
(at your option) any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

=head1 FILES

krazyrc(5) files are processed in descending hierarchical order
with each sublevel setting appending in a logical way to the previous
level settings. The following files are read:
 F<component/.krazy>
 F<component/module/.krazy>
 F<component/module/subdir/.krazy>

=head1 SEE ALSO

krazyrc(5), krazy2(1), krazy2all(1)

=head1 AUTHORS

Allen Winter, <winter@kde.org>

=cut
