@REM Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
@REM All rights reserved.
@REM This component and the accompanying materials are made available
@REM under the terms of the License "Eclipse Public License v1.0"
@REM which accompanies this distribution, and is available
@REM at the URL "http://www.eclipse.org/legal/epl-v10.html".
@REM
@REM Initial Contributors:
@REM Nokia Corporation - initial contribution.
@REM 
@REM Contributors:
@REM

@goto invoke

#!perl

use strict;
use FindBin;		# for FindBin::Bin
use Getopt::Long;
use Cwd;

$_ = cwd;
tr/\//\\/;
my $Pwd = $_;

my $PerlLibPath;    # fully qualified pathname of the directory containing our Perl modules

# establish the path to the Perl binaries
BEGIN {
	require 5.005_03;				# check user has a version of perl that will cope
# establish the path to the Perl libraries: currently the same directory as this script
	$PerlLibPath = $FindBin::Bin;	# X:/epoc32/tools
	$PerlLibPath =~ s/\//\\/g;	# X:\epoc32\tools
	$PerlLibPath .= "\\";
}
use lib $PerlLibPath;

use Defutl;
use Genutl;

my %opts = ();

my $result = GetOptions(\%opts,
			"srcpath:s",
			"defpath:s",
			"name:s",
			"version:s",
			"alignstack",
			"help",
		       );

Usage() if(!$result || $opts{'help'} || @ARGV < 1);

my $srcPath = $opts{"srcpath"} || $Pwd;
my $defPath = $opts{"defpath"} || $srcPath;
my $outputName = $opts{"name"} || "shim";
my %Version;
if ($opts{version}) {
	%Version = &Genutl_StringToVersion($opts{version}) or die "Bad version number\n";
} else {
	$Version{major} = 0;
	$Version{minor} = 0;
}

my $infile = pop @ARGV;

my @DefData;
eval { &Def_ReadFileL(\@DefData, $infile); } ;
die $@ if $@;

sub WriteFunction($$$) {
  my ($ordinal, $branchTarget, $comment) = @_;
  my $fnName = "export_at_ordinal_$ordinal";
  if ($branchTarget =~ /^\"(.*)\"$/) {
	  $branchTarget = $1;
	}
  if ($comment =~ /(null)/) {
    $comment = $branchTarget;
  }

  print CPP <<FUNCTION_DEFINITION;

EXPORT_C __NAKED__ int $fnName()
//
// $comment
//
	{
	asm("B $branchTarget ");
	}

FUNCTION_DEFINITION
}

sub WriteFunctionAligned($$$) {
  my ($ordinal, $branchTarget, $comment) = @_;
  my $fnName = "export_at_ordinal_$ordinal";
  if ($branchTarget =~ /^\"(.*)\"$/) {
	  $branchTarget = $1;
	}
  if ($comment =~ /(null)/) {
    $comment = $branchTarget;
  }

  print CPP <<FUNCTION_DEFINITION2;

EXPORT_C __NAKED__ int $fnName()
//
// $comment
//
	{
	asm("stmfd sp!, {r4,lr} ");
	asm("mov r4, sp ");
	asm("bic sp, sp, #4 ");
	asm("bl $branchTarget ");
	asm("mov sp, r4 ");
	asm("ldmfd sp!, {r4,pc} ");
	}

FUNCTION_DEFINITION2
}

sub WriteCppHeader($) {
  my ($filename) = @_;
  print CPP <<FILE_HEADER;
//
// $filename - generated by GENSHIMSRC.BAT
//

#include <e32def.h>
#include <e32const.h>
#include <cpudefs.h>

FILE_HEADER
}

sub WriteExport($$$) {
  my ($ordinal, $export, $comment) = @_;

  if ($comment =~ /(null)/) {
    $comment = $export;
  }
  printf DEF "\t${export}=export_at_ordinal_${ordinal}__Fv \@ $ordinal NONAME \; $comment\n";
}

my $cppFile = "$srcPath\\$outputName\.cia";
die "ERROR: Couldn't open $cppFile\n" unless open CPP, ">$cppFile";
my $vstring = &Genutl_VersionToFileAugment(%Version);
my $defFile = "$defPath\\${outputName}$vstring\.def";
die "ERROR: Couldn't open $defFile\n" unless open DEF, ">$defFile";

WriteCppHeader(uc "${outputName}.cia");
printf DEF "EXPORTS\n";

foreach my $defData (@DefData){
  my $ord = $$defData{Ordinal};
  if ($ord) {
	my $name = $$defData{Name};
	my $comment = $$defData{Comment};
	if ($opts{alignstack}) {
		WriteFunctionAligned($ord, $name, $comment);
	} else {
		WriteFunction($ord, $name, $comment);
	}
	WriteExport($ord, $name, $comment);
  }
}

close CPP;
close DEF;

#####################################################################
sub Usage
{
	print <<EOT;

genshimsrc

	Generate source for a shim DLL and its associated deffile from a supplied deffile

Usage:
	genshimsrc [options] deffile

Where:
	[deffile]     The source deffile

Options:
	--srcpath         the path for the output source file (defaults to CWD)
	--defpath         the path for the output DEF file (defaults to srcpath)
	--name            the name to use for the output files (defaults to shim)
	--version         the version to use for the output DEF file (defaults to 0.0)
	--alignstack      use shims which align the stack to an 8 byte boundary
EOT
	exit 1;
}

1;

__END__

# Tell emacs that this is a perl script even 'though it has a .bat extension
# Local Variables:
# mode:perl
# tab-width:4
# End:

:invoke
@perl -x -S genshimsrc.bat %1 %2 %3 %4 %5 %6 %7 %8 %9
