#!/usr/bin/perl
#############################################################################
## Crytek Source File
## Copyright (C) 2007, Crytek Studios
##
## Creator: Sascha Demetrio
## Date: Jul 17, 2007
## Description: GNU-make based build system
#############################################################################

# This script generates the C++ files for an SPU job.

use warnings;
use strict;

use Elements;
use Getopt::Long qw(:config no_auto_abbrev bundling);

my $perl = '/usr/bin/perl';

# Parse the command line.
my $indexFile;
my $entryElementName;
my $jobName;
my $optionJobExec = 0;
my $depFile;
my $toolDir;
my $toolBinDir;
my $outputFile;
my $optCygwinMode = 0;
my $optCygwinBaseDir;
my @optConfigVars = ( );
my $optionHelp = 0;
my $optionVerbose = 0;
GetOptions(
    'i|index-file=s' => \$indexFile,
    'E|entry=s' => \$entryElementName,
    'o|output=s' => \$outputFile,
    'j|job=s' => \$jobName,
    'x|job-exec' => \$optionJobExec,
    'd|dep-file=s' => \$depFile,
    't|tool-dir=s' => \$toolDir,
    'h|help' => \$optionHelp,
    'v|verbose!' => \$optionVerbose,
    'c|cygwin!' => \$optCygwinMode,
    'b|basedir|base-dir=s' => \$optCygwinBaseDir,
    'D|define=s' => \@optConfigVars
    ) or exit 1;
if ($optionHelp)
{
  print <<EOF
genspujob.pl: Script generating an SPU job C++ file.
Synopsis:
  \$PERL genspujob.pl (Options)
Options:
-i|--index-file FILE
  The name of the CCG index file name.
-E|--entry NAME
  The name of the job entry point function or method.
-j|--job NAME
  The name of the job.  This option is required.
-x|--job-exec
  If this option is specified, then a job execute file is generated.
-d|--dep-file FILE
  The name of the dependency file.
-t|--tool-dir DIR
  The directory containing the crycg executables.  This is the directory
  containing the 'host-linux' and 'host-win32' subdirectories.
-c|--cygwin
  Enable cygwin mode.  This enables a path fixup step for the generated
  dependency files.
-b|--basedir|--base-dir DIR
  The Cygwin base directory.  This is the directory mounted to '/base' within
  Cygwin.
-D|--define NAME=VALUE
  Config substitution variable to be passed to CryCG.
-v|--verbose
  Verbose operation.
-h|--help
  Display this help screen and exit.
EOF
  ;
  exit 0;
}
if (not defined $indexFile)
{
  print STDERR "genspujob: no index file specified!\n";
  exit 1;
}
if (not defined $entryElementName)
{
  print STDERR "genspujob: no entry element name specified!\n";
  exit 1;
}
if (not defined $jobName)
{
  print STDERR "genspujob: no job name specified!\n";
  exit 1;
}
if (not defined $outputFile)
{
  print STDERR "genspujob: no output file name specified!\n";
  exit 1;
}

# Fix the specified Cygwin dir.
if (defined $optCygwinBaseDir)
{
	$optCygwinBaseDir =~ s#\\#/#g;
	$optCygwinBaseDir =~ s#//+#/#g;
	#while ($optCygwinBaseDir =~ s#[^/]+/\.\./##g) { }
	#$optCygwinBaseDir =~ s#/[^/]+/\.\.$##;
}

# If no tool directory was specified, locate the tool directory and binary
# directory containing the CryCG executable using the command name.  We'll
# assume that this script is _not_ in the system path and the we can get the
# directory containing the script from $0.
if (not defined $toolDir)
{
  my $sepIndex = rindex $0, '/';
  if ($sepIndex == -1) { $sepIndex = rindex $0, '\\'; }
  if ($sepIndex == -1)
  {
    print STDERR "genspujob: can not locate tool directory!\n";
    exit 1;
  }
  $toolDir = substr $0, 0, $sepIndex;
}
if (not defined $toolBinDir)
{
  if ($^O eq 'linux')
  {
    $toolBinDir = "$toolDir/host-linux";
  }
  elsif ($^O eq 'cygwin')
  {
    $toolBinDir = "$toolDir/host-win32";
  }
  else
  {
    print STDERR "genspujob: ",
      "can not locate tool binary directory for OS '$^O'!\n";
    exit 1;
  }
}
if (not -d $toolDir)
{
  print STDERR "genspujob: tool directory '$toolDir' does not exist!\n";
  exit 1;
}
if (not -d $toolBinDir)
{
  print STDERR "genspujob: ",
    "tool binary directory '$toolBinDir' does not exist!\n";
  exit 1;
}

# Locate the CryCG executable.
my $tool;
my @toolOptions = ( );
if (-x "$toolBinDir/crycg")
{
  $tool = "$toolBinDir/crycg";
}
elsif (-x "$toolBinDir/crycg.exe")
{
  $tool = "$toolBinDir/crycg.exe";
}
else
{
  print STDERR "genspujob: ",
    "can not locate generator tool 'crycg' or 'crycg.exe'!\n";
  exit 1;
}

if (not $optionVerbose) { push @toolOptions, '-CLogLevel:notice'; }

# Locate the CryCG configuration file.
if (-r "$toolDir/crycg.conf")
{
  push @toolOptions, '-c', "$toolDir/crycg.conf";
}
else
{
  print STDERR "genspujob WARNING: ",
    "crycg configuration file not found, using default configuration!\n";
}

# Pass on -D options.
foreach my $configVar (@optConfigVars)
{
  push @toolOptions, "-D$configVar";
}

# Add a suffix to the basename (without extension) of the specified file name.
sub applySuffix ($$)
{
  my $fileName = shift;
  my $suffix = shift;

  my $dotIndex = rindex $fileName, '.';
  if ($dotIndex > 0)
  {
    $fileName =
      substr($fileName, 0, $dotIndex)
      .$suffix
      .substr($fileName, $dotIndex);
  }
  else
  {
    $fileName .= $suffix;
  }
  return $fileName;
}

# Run the CryCG tool.
my @toolCommand = ($perl, "$toolDir/build.pl");
if ($optCygwinMode)
{
  push @toolCommand, '--cygwin';
  if (defined $optCygwinBaseDir)
  {
    push @toolCommand, '--basedir', $optCygwinBaseDir;
  }
}
push @toolCommand,
  '--',
  $tool, @toolOptions,
  'gen',
  '-i', $indexFile,
  '-e', $entryElementName,
  "-CSPUBreakpoint:$entryElementName",
  "-DJOB=$jobName",
  '-o', $outputFile;
if ($optionJobExec)
{
  push @toolCommand, '-j', "$jobName";
}
else
{
  push @toolCommand, '-DPAGE=0';
}
if (defined $depFile)
{
  if ($optCygwinMode)
  {
    push @toolCommand, '-d', "${depFile}_";
  }
  else
  {
    push @toolCommand, '-d', $depFile;
  }
}
if ($optionVerbose)
{
  print "genspujob: ", join(' ', @toolCommand), "\n";
}
if (defined $jobName) { print "genspujob: generating job '$jobName' ...\n"; }

system(@toolCommand) == 0 or exit 1;

# Fix dependencies when running in Cygwin mode.
sub fixDeps ($$)
{
  my $inFile = shift;
  my $outFile = shift;
  my @lines = ( );
  local *IN;
  local *OUT;

  open(IN, "$inFile")
    or die "Can't open dependency file '$inFile' for fixdeps: $!";
  while (<IN>) { push @lines, $_; }
  close(IN);
  unlink $inFile;
  unlink $outFile;
  open(OUT, ">$outFile")
    or die "Can't open dependency file '$outFile' for fixdeps: $!";
  foreach my $line (@lines)
  {
    # Remove "DIR/.." patterns.
		#while ($line =~ s#[^/]+/\.\./##g) { }
    if (defined $optCygwinBaseDir)
    {
      my $index = index lc $line, lc $optCygwinBaseDir;
      if ($index >= 0)
      {
        # Make sure the base dir is a prefix of a filename.
        if ($index > 0 and (substr $line, $index - 1, 1) ne ' ')
        {
          $index = -1;
        }
      }
      if ($index >= 0)
      {
        my $prefix = substr $line, 0, $index;
        my $suffix = substr $line, $index + length $optCygwinBaseDir, -1;
        $line = $prefix . '/base/' . $suffix;
        $line =~ s#//+#/#g;
      }
    }
    if ($line =~ /^(\s+)([a-z]):\/(.*$)/i)
    {
      my $driveLetter = lc $2;
      $line = "$1/cygdrive/$driveLetter/$3\n";
    }
    elsif ($line =~ /^(\S+:\s+)([a-z]):\/(.*$)/i)
    {
      my $driveLetter = lc $2;
      $line = "$1/cygdrive/$driveLetter/$3\n";
    }
    if ($line =~ /^([a-z]):(.*$)/i)
    {
      my $driveLetter = lc $1;
      $line = "/cygdrive/$driveLetter$2\n";
    }
    $line =~ s/\s+$//;
    print OUT "$line\r\n";
  }
  close(OUT);
}

if (defined $depFile and $optCygwinMode)
{
  fixDeps("${depFile}_", $depFile);
}

# Tools/genspujob.pl
# vim:ts=2:sw=2:expandtab

