#! /usr/bin/perl
#  stubgen2 -- Stub Generator for OPEN-R Object (libObjectComm Ver2.x)
#
#  Copyright 2002 Sony Corporation
#

sub CheckFuncname {
    $funcname = $_[0];
    $funcname =~ s/\s*$//; # remove the trailing whitespace
    if ( $funcname eq "null" ){
	return $funcname;
    } elsif ( $funcname !~ /\(\)\Z/ ){
	die "Missing () for function name.\n";
    } else {
	$funcname = $`;
	$funcname =~ s/\s*$//; # remove the trailing whitespace
	return $funcname;
    }
}


$countSubject      = 0;
$countObserver     = 0;
$numOfExtraEntries = 0;
while ( <> ) {
    $_ =~ s/[\r\n]//g;
    if ( /^\s*ObjectName\s*:\s*(\S+)\s*/ ) {
	$objectName = $1;
    } elsif ( /^\s*NumOfOSubject\s*:\s*(\S+)\s*/ ) {
	$numOfOSubject = $1;
    } elsif ( /^\s*NumOfSubject\s*:\s*(\S+)\s*/ ) {
	$numOfOSubject = $1;
    } elsif ( /^\s*NumOfOObserver\s*:\s*(\S+)\s*/ ) {
	$numOfOObserver = $1;
    } elsif ( /^\s*NumOfObserver\s*:\s*(\S+)\s*/ ) {
	$numOfOObserver = $1;
    } elsif ( /^\s*Service\s*:\s*/ ) {
	@lineService = split( /\s*,\s*/, $' );
	$serviceName = shift(@lineService);
	@serviceElement = split( /\./, $serviceName );
	if ( $serviceElement[3] =~ /^S\"$/ ) { #"
	    $subjectService[$countSubject] = $serviceName;
	    $subjectSubname[$countSubject] = $serviceElement[1];
	    $controlFunc[$countSubject] = CheckFuncname(shift(@lineService));
	    $readyFunc[$countSubject] = CheckFuncname(shift(@lineService));
	    $countSubject++;
	} elsif ( $serviceElement[3] =~ /^O\"$/ ) { #"
	    $observerService[$countObserver] = $serviceName;
	    $observerSubname[$countObserver] = $serviceElement[1];
	    $connectFunc[$countObserver] = CheckFuncname(shift(@lineService));
	    $notifyFunc[$countObserver]  = CheckFuncname(shift(@lineService));
	    $countObserver++;
	}
    } elsif ( /^\s*Extra\s*:\s*(\S+)\s*/ ) {
	$func = $1;
	if ( $func !~ /\(\)\Z/ ){
	    die "Missing () for extra-function name.\n";
	} else {
	    $extraFunction[$numOfExtraEntries] = $`;
	    $numOfExtraEntries++;
	}
    }
}


if ( $numOfOSubject == 0 ) {
    die "At least one Subject-Service should be specified.\n";
} elsif ( $numOfOSubject != $countSubject ) {
    die "Inconsitency found between service and numOfOSubject.\n";
}

if ( $numOfOObserver == 0 ) {
    die "At least one Observer-Service should be specified.\n";
} elsif ( $numOfOObserver != $countObserver ) {
    die "Inconsitency found between service and numOfOObserver.\n";
}


#
#  print on terminal
#
print "Object = $objectName\n"; 
print "numOfSubject  = $numOfOSubject\n";
print "numOfObserver = $numOfOObserver\n";
for ($i = 0; $i < $numOfOSubject; $i++) {
    print "Service name = $subjectService[$i]\n";
    print "\tControl Function = $controlFunc[$i]\n";
    print "\tReady Function   = $readyFunc[$i]\n";
}
for ($i = 0; $i < $numOfOObserver; $i++) {
    print "Service name = $observerService[$i]\n";
    print "\tConnect Function = $connectFunc[$i]\n";
    print "\tNotify Function  = $notifyFunc[$i]\n";
}
for ($i = 0; $i < $numOfExtraEntries; $i++) {
    print "Extra function = $extraFunction[$i]\n";
}


###
###  Output def.h
###
open(OUT, ">def.h"); 
print OUT <<def_h_section1;
//
//  def.h
//  This file is generated by stubgen2.
//

//
// Copyright 2002 Sony Corporation 
//
// Permission to use, copy, modify, and redistribute this software for
// non-commercial use is hereby granted.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//

#ifndef _def_h_DEFINED
#define _def_h_DEFINED

//
//  Object name
//
const char* const objectName = "$objectName";

//
//  Number of OObserver & OSubeject instances
//
const int numOfSubject  = $numOfOSubject;
const int numOfObserver = $numOfOObserver;

//
//  Service name
//
const char* const subjectService[numOfSubject] = 
{
def_h_section1

for ($i = 0; $i < $numOfOSubject; $i++) {
    print OUT "\t$subjectService[$i]";
    if ( $i+1 < $numOfOSubject ){
	print OUT ",\n";
    } else {
	print OUT "\n";     
    } 
}

print OUT <<def_h_section2;
};

const char* const observerService[numOfObserver] = 
{
def_h_section2

for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "\t$observerService[$i]";
    if ( $i+1 < $numOfOObserver ){
	print OUT ",\n";
    } else {
	print OUT "\n";
    } 
}

print OUT <<def_h_section3;
};

//
//  OSubject Index
//
def_h_section3

for ($i = 0; $i < $numOfOSubject; $i++){ 
    print OUT "const int sbj$subjectSubname[$i] = $i;\n";
}

print OUT <<def_h_section4;

//
//  OObserver Index
//
def_h_section4

for ($i = 0; $i < $numOfOObserver; $i++){ 
    print OUT "const int obs$observerSubname[$i] = $i;\n";
}

print OUT "\n\n#endif // _def_h_DEFINED\n";

close(OUT);


###
###  Output entry.h
###
open(OUT, ">entry.h") || die "entry.h : $!\n";

print OUT <<entry_h_section1;
//
//  entry.h
//
//  This file is generated by stubgen2.
//

//
// Copyright 2002 Sony Corporation 
//
// Permission to use, copy, modify, and redistribute this software for
// non-commercial use is hereby granted.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//

#ifndef _entry_h_DEFINED
#define _entry_h_DEFINED

#include <Types.h>
#include "def.h"

const int numOfHook = 4;

const Selector Entry_Hook   [numOfHook]     = { 0, 1, 2, 3 };
entry_h_section1

$countEntry = 4;

print OUT "const Selector Entry_Control[numOfSubject]  = { ";
for ($i = $numOfOSubject; $i > 0; $i--) {
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ) {
	print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Ready  [numOfSubject]  = { ";
for ($i = $numOfOSubject; $i > 0; $i--) {
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
	print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Connect[numOfObserver] = { ";
for ($i = $numOfOObserver; $i > 0; $i--) {
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
	print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Notify [numOfObserver] = { ";
for ($i = $numOfOObserver; $i > 0; $i--) {
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
	print OUT ", ";
    }
}
print OUT " };\n";

print OUT <<entry_h_section3;

//
//  Number of basic entries is 
//      numOfHook + (numOfSubject + numOfObserver) * 2
//
entry_h_section3

$numOfEntries = ($numOfOSubject + $numOfOObserver) * 2 + 4;
print OUT "const longword numOfBasicEntries = $numOfEntries;\n";

if ( $numOfExtraEntries > 0 ) {
    print OUT <<entry_h_section4;

//
// Extra entry
//
entry_h_section4

    print OUT "const Selector Extra_Entry[]  = { ";
    for ($i = $numOfExtraEntries; $i > 0; $i--) {
	print OUT "$countEntry"; $countEntry++;
	if ( $i > 1 ){
	    print OUT ", ";
	}
    }
    print OUT " };\n\n";

    for ($i = 0; $i < $numOfExtraEntries; $i++) {
	print OUT "const int entry$extraFunction[$i] = $i;\n";
    }
}

print OUT "\n#endif // _entry_h_DEFINED\n";

close(OUT);


###
###  Output stub.h
###
open(OUT, ">".$objectName."Stub.h");

print OUT "//\n";
print OUT "//  ".$objectName."Stub.h\n";
print OUT <<stub_h_section1; 				
//  This file is generated by stubgen2.
//

//
// Copyright 2002 Sony Corporation 
//
// Permission to use, copy, modify, and redistribute this software for
// non-commercial use is hereby granted.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//

#ifndef _stub_h_DEFINED
#define _stub_h_DEFINED

#ifndef OPENR_STUBGEN
#define OPENR_STUBGEN
#endif

#include <OPENR/OPENR.h>
#include <OPENR/OPENRMessages.h>
#include <OPENR/ObjcommMessages.h>
#include <OPENR/stub_macro.h>
#include "def.h"

extern "C" {
    StubFuncDeclare_Basic(Init)
    StubFuncDeclare_Basic(Start)
    StubFuncDeclare_Basic(Stop)
    StubFuncDeclare_Basic(Destroy)
stub_h_section1

for ($i = 0; $i < $numOfOSubject; $i++){
    print OUT "    StubFuncDeclare_Subject($i)\n";
#    print OUT "StubFuncDeclare_Ready($i)\n";
}
for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "    StubFuncDeclare_Observer($i)\n";
#    print OUT "StubFuncDeclare_Notify($i)\n";
}
for ($i = 0; $i < $numOfExtraEntries; $i++) {
    print OUT "    void _$extraFunction[$i](void*);\n";
}

print OUT <<stub_h_section3;
}

#endif // _stub_h_DEFINED

stub_h_section3

close(OUT);


###
###  Output stub.cc 
###
open(OUT, ">".$objectName."Stub.cc");

print OUT "//\n";
print OUT "//  ".$objectName."Stub.cc\n";
print OUT <<stub_cc_section1;
//  This file is generated by stubgen2.
//

//
// Copyright 2002 Sony Corporation 
//
// Permission to use, copy, modify, and redistribute this software for
// non-commercial use is hereby granted.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//

#ifndef OPENR_STUBGEN
#define OPENR_STUBGEN
#endif

#if defined(__GNUC__)
#include <apsys.h>
#endif
#include <MCOOP.h>
#include <ObjectEntryTable.h>
#include <OPENR/stub_macro.h>
#include "def.h"
#include "entry.h"
stub_cc_section1

print OUT "#include \"".$objectName."Stub.h\"\n";

print OUT <<stub_cc_section2;

//
//  Object Core
//
stub_cc_section2

print OUT "#include \"$objectName.h\"\n";
print OUT "$objectName Self;\n\n";

print OUT <<stub_cc_section3;
//
//  Stub Function Definitions
//
StubFuncDefine_Basic(Init)
StubFuncDefine_Basic(Start)
StubFuncDefine_Basic(Stop)
StubFuncDefine_Basic(Destroy)
stub_cc_section3

for ($i = 0; $i < $numOfOSubject; $i++) {
    if ($controlFunc[$i] eq "null") {
	print OUT "StubFuncDefine_Control_nofunc($i)\n";
    } else {
	print OUT "StubFuncDefine_Control($i, $controlFunc[$i])\n";
    }
    if ($readyFunc[$i] eq "null") { 
	print OUT "StubFuncDefine_Ready_nofunc($i)\n";
    } else {			       
	print OUT "StubFuncDefine_Ready($i, $readyFunc[$i])\n";
    }
}
for ($i = 0; $i < $numOfOObserver; $i++) {
    if ($connectFunc[$i] eq "null") {
	print OUT "StubFuncDefine_Connect_nofunc($i)\n";
    } else {
	print OUT "StubFuncDefine_Connect($i, $connectFunc[$i])\n";
    }
    if ($notifyFunc[$i] eq "null") {
	print OUT "StubFuncDefine_Notify_nofunc($i)\n";
    } else {
	print OUT "StubFuncDefine_Notify($i, $notifyFunc[$i])\n";
    }
}

print OUT <<stub_cc_section5;

//
// Other definitions if any
//
stub_cc_section5

for ($i = 0; $i < $numOfExtraEntries; $i++) {
    print OUT "extern \"C\" void\n";
    print OUT "_$extraFunction[$i](void* msg)\n{\n";
    print OUT "    Self.$extraFunction[$i](msg);\n";
    print OUT "    Return();\n}\n\n";
}

print OUT <<stub_cc_section_gcc1;

//
// Set Entry Table
//
#if defined(__GNUC__)
GEN_ENTRY(_hookstub0, _Init);
GEN_ENTRY(_hookstub1, _Start);
GEN_ENTRY(_hookstub2, _Stop);
GEN_ENTRY(_hookstub3, _Destroy);
stub_cc_section_gcc1

for ($i = 0; $i < $numOfOSubject; $i++)
{
    print OUT "GEN_ENTRY(_controlstub$i, \t_Control$i);\n";
    print OUT "GEN_ENTRY(_readystub$i, \t_Ready$i);\n";
}
for ($i = 0; $i < $numOfOObserver; $i++)
{
    print OUT "GEN_ENTRY(_connectstub$i, \t_Connect$i);\n";
    print OUT "GEN_ENTRY(_notifystub$i, \t_Notify$i);\n";
}
for ($i = 0; $i < $numOfExtraEntries; $i++)
{
    print OUT "GEN_ENTRY(_$extraFunction[$i]stub, \t_$extraFunction[$i]);\n";
}

print OUT "GEN_ENTRY(PrologueEntry, Prologue);\n";

print OUT "\nObjectEntry	ObjectEntryTable[] = {\n";

for ($i = 0; $i < 4; $i++)
{
    print OUT "    {Entry_Hook[$i], \t(Entry)_hookstub$i},\n";
}
for ($i = 0; $i < $numOfOSubject; $i++)
{
    print OUT "    {Entry_Control[$i], \t(Entry)_controlstub$i},\n";
    print OUT "    {Entry_Ready[$i], \t(Entry)_readystub$i},\n";
}
for ($i = 0; $i < $numOfOObserver; $i++)
{
    print OUT "    {Entry_Connect[$i], \t(Entry)_connectstub$i},\n";
    print OUT "    {Entry_Notify[$i], \t(Entry)_notifystub$i},\n";
}
for ($i = 0; $i < $numOfExtraEntries; $i++)
{
    print OUT "    {Extra_Entry[$i], \t(Entry)_$extraFunction[$i]stub},\n";
}

print OUT <<stub_cc_section_gcc2;
    {UNDEF,            (Entry) ENTRY_UNDEF}
};
#else
stub_cc_section_gcc2

print OUT <<stub_cc_section4;

//
//  Stub Function Pointer
//  
_Hook _hook[numOfHook] = { _Hook(Init), _Hook(Start), _Hook(Stop), _Hook(Destroy) };
stub_cc_section4

print OUT "_Control _control[numOfSubject]  = { ";
for ($i = 0; $i < $numOfOSubject; $i++) {
    print OUT "_Control($i)";
    if ( $i + 1 < $numOfOSubject ) {
	print OUT ", ";
    }
} print OUT " };\n";
print OUT "_Ready   _ready  [numOfSubject]  = { ";
for ($i = 0; $i < $numOfOSubject; $i++) {
    print OUT "_Ready($i)";
    if ( $i + 1 < $numOfOSubject ) {
	print OUT ", ";
    }
} print OUT " };\n";
print OUT "_Connect _connect[numOfObserver] = { ";
for ($i = 0; $i < $numOfOObserver; $i++) {
    print OUT "_Connect($i)";
    if ( $i + 1 < $numOfOObserver ) {
	print OUT ", ";
    }
} print OUT " };\n";
print OUT "_Notify  _notify [numOfObserver] = { ";
for ($i = 0; $i < $numOfOObserver; $i++) {
    print OUT "_Notify($i)";
    if ( $i + 1 < $numOfOObserver ) {
	print OUT ", ";
    }
} print OUT " };\n";

print OUT <<stub_cc_section6;

ObjectEntry  ObjectEntryTable[] = {
stub_cc_section6

print OUT "    {Entry_Hook[0], \t(Entry) _Hook(Init)},\n";
print OUT "    {Entry_Hook[1], \t(Entry) _Hook(Start)},\n";
print OUT "    {Entry_Hook[2], \t(Entry) _Hook(Stop)},\n";
print OUT "    {Entry_Hook[3], \t(Entry) _Hook(Destroy)},\n";

for ($i = 0; $i < $numOfOSubject; $i++) {
    print OUT "    {Entry_Control[$i], \t(Entry) _Control($i)},\n";
}
for ($i = 0; $i < $numOfOSubject; $i++) {
    print OUT "    {Entry_Ready[$i], \t(Entry) _Ready($i)},\n";
}
for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "    {Entry_Connect[$i], \t(Entry) _Connect($i)},\n";
}
for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "    {Entry_Notify[$i], \t(Entry) _Notify($i)},\n";
}
for ($i = 0; $i < $numOfExtraEntries; $i++) {
    print OUT "    {Extra_Entry[$i], \t(Entry) _$extraFunction[$i]},\n";
}
print OUT "    {UNDEF, \t\t(Entry) ENTRY_UNDEF}\n};\n";
print OUT "#endif\n";

close(OUT);
