#!/usr/bin/perl
# ====================================================================
# The Vovida Software License, Version 1.0
#
# Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. The names "VOCAL", "Vovida Open Communication Application Library",
# and "Vovida Open Communication Application Library (VOCAL)" must
# not be used to endorse or promote products derived from this
# software without prior written permission. For written
# permission, please contact vocal\@vovida.org.
#
# 4. Products derived from this software may not be called "VOCAL", nor
# may "VOCAL" appear in their name, without prior written
# permission of Vovida Networks, Inc.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
# NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
# IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# ====================================================================
#
# This software consists of voluntary contributions made by Vovida
# Networks, Inc. and many individuals on behalf of Vovida Networks,
# Inc. For more information on Vovida Networks, Inc., please see
# .
# $Id: cApiBuilder,v 1.11 2000/08/12 01:24:57 bogawa Exp $
use strict 'subs';
#use strict 'getopts.pl';
@functions = ( ); # main data structure that holds all info about all functions
$doCode = 1; # flag to generate CXX file, otherwise do header file
@inclues = {}; # holds allfiles to be included in generated output
# parse the heasder information
for $arg ( @ARGV ) {
&debug(" arg=",$arg,"\n");
if ( $arg =~ /^-c/ ) {
$doCode = 1;
}
if ( $arg =~ /^-h/ ) {
$doCode = 0;
}
if ( $arg =~ /^-d/ ) {
$debugCode = 1;
}
if ( $arg =~ /^-i/ ) {
# an file to include
$arg =~ s/^-i//;
push @includes, $arg;
}
}
#generate the file header info
print < ) {
# still need to deal with C style comments
if ( s/^\#include/\#include/g > 0 ) {
print $_ if $doCode;
}
else {
chomp;
$ignore = 1 if(/\/\/ API:ignore begin/) ;
$ignore = 0 if(/\/\/ API:ignore end/) ;
next if($ignore);
s/:/ : /g;
s/,/ , /g;
s/\(/ \( /g;
s/\)/ \) /g;
s/\{/ \{ /g;
s/\}/ \} /g;
s/\;/ \; /g;
s/\/\/.*$/ /g;
s/\#.*$/ /g;
s/^t/ /g;
s/const/ /g;
s/virtual/ /g;
$data .= $_ . " ";
}
}
# remvoe C Style comments
$data =~ s/\/\*.*?\*\///gm;
# tokenize the data
@data = split( " " , $data );
$inClass = 0;
$inPublic = 0;
for( $i=0; $i < $#data; $i++ ) {
if ( $data[$i] eq "class" ) {
$className = $data[$i+1];
if ( $data[$i+2] ne ";" ) {
while ( $data[$i] ne "{" ) { $i++; }
$i++;
$inClass = 1;
$inPublic = 0;
&debug("# in class " , $className , "\n");
}
}
if ( $data[$i] eq "}" ) {
$inClass = 0;
}
if ( ($data[$i] eq "public") and $inClass ) {
while ( $data[$i] ne ":" ) { $i++; }
$i++;
$inPublic = 1;
&debug("# in public of " , $className , "\n");
}
if ( ($data[$i] eq "private") or ($data[$i] eq "protected") ) {
while ( $data[$i] ne ":" ) { $i++; }
$i++;
$inPublic = 0;
}
if ( ($data[$i] eq "(" ) and $inClass and $inPublic ) {
#found a function
$functionName = $data[$i-1];
if ( $functionName eq $className ) {
$returnType = $className . "*";
$functionName = "constructor";
}
elsif ( $functionName eq ( "~" . $className ) ) {
$returnType = "void";
$functionName = "destructor";
}
else {
$staticFunction = ( $data[$i-3] eq "static");
$returnType = $data[$i-2];
$returnType = "int" if ($returnType eq ";");
$returnType = "int" if ($returnType eq ":");
$returnType = "int" if ($returnType eq "{");
}
$i++;
$rec = { };
$rec->{name} = $functionName;
$rec->{isStatic} = $staticFunction;
$rec->{class} = $className;
$rec->{return} = $returnType;
&debug("#func ",$returnType," ",$className,"::",$functionName,"\n");
$numParam = 0;
# get the parameters
PARAM: while ( 1 ) {
last PARAM if ( $data[$i] eq ")" );
#for ( $t=$i; $t<$i+3; $t++) { print "data[",$t,"]=",$data[$t],"\n"; }
$type = $data[$i];
$name = $data[$i+1];
$name =~ s/=.*//g; # kill default paramters
&debug("# param ",$numParam," ",$type," ",$name,"\n");
$rec->{"paramName",$numParam} = $name;
$rec->{"paramType",$numParam} = $type;
$numParam++;
$rec->{numParam} = $numParam;
$i = $i+2;
&debug("data is ",$data[$i],"\n");
last PARAM if ( $data[$i] eq ")" );
if ( $data[$i] eq "," ) {
$i++;
next PARAM;
}
print STDERR "VERY CONFUSED\n";
print "VERY CONFUSED\n";
for ( $j = $i-10; $j < $i+10; $j++ ) {
print $data[$j]," ";
}
print "\n";
last PARAM;
}
push @functions, $rec;
# eat rest of function
INLINEFUNC: while ( ($data[$i] ne ";") ) {
if (($data[$i] eq "{") ) {
#Deal with inline function
$i++;
$depth = 1;
while ( $depth > 0 ) {
$depth++ if ($data[$i] eq "{");
$depth-- if ($data[$i] eq "}");
$i++;
}
last INLINEFUNC;
}
$i++;
}
}
&debug($i,": ",$data[$i] , "\n");
}
# print the functions
if (0) {
for $func ( @functions ) {
print "static " if $func->{isStatic};
print $func->{return}," ", $func->{class},"::",$func->{name},"(";
for( $t=0; $t < $func->{numParam}; $t++) {
print "," if ( $t != 0 );
print $func->{"paramType",$t}," ",$func->{"paramName",$t};
}
print ");\n";
}
}
%definedTypes = ( "void" => 1,
"bool" => 1,
"char" => 1,
"int" => 1,
"long" => 1,
"float" => 1,
"double" => 1,
"string" => 1,
"String" => 1,
"RtpSeqNumber" => 1,
"RtcpHeader" => 1,
"RtcpReport" => 1,
"RtcpSDESItem" => 1,
"RtcpSDESType" => 1,
"RtcpSender" => 1,
"RtcpType" => 1,
"RtpHeader" => 1,
"RtpPayloadType" => 1,
"RtpSource" => 1,
"RtpTime" => 1,
"RtpSrc" => 1,
"u_int32_t" => 1
);
sub addType ( $ ) {
my $type = shift;
&debug("adding type ",$type," -> ",&mapTypeToC($type),"\n");
$_ = $type;
s/&//g;
s/\*//g;
$_ = "builtin" if ( $definedTypes{$_} );
$type = $_;
$types{$type} = $type unless ( $type eq "builtin" );
}
sub mapTypeToC ( $ ) {
$_ = shift;
s/string&/char\*/g;
s/string/char\*/g;
s/&/\*/g;
s/bool/int/g;
my $type = $_;
# try to fix template classes
s/\<(\w*)\>/_Tmpl_$1_/;
$type =~ s/\<(\w*)\>/_Tmpl_$1_/;
s/Ptr$/\*/;
s/\**//g;
&debug("check defined for " , $_ , "\n");
if ( $definedTypes{$_} ) {
&debug("is defined\n");
#$type .= "_isCDefined";
}
else {
&debug("is not defined\n");
$type =~ s/\*/Ptr/; # needs work for builtin types
# $type .= "Ptr"; # needs work for builtin types
}
# try to fix template classes
s/\<(\w*)\>/_Tmpl_$1_/;
# s/^intPtr/int*/;
# s/^longPtr/long*/;
# s/^charPtr/char*/;
# s/^shortPtr/short*/;
# s/^floatPtr/float*/;
# s/^doublePtr/double*/;
# s/^voidPtr/void*/;
$mapTypeToC = $type;
}
# compute all the type lookups
for $func ( @functions ) {
&addType( $func->{class} );
&addType( $func->{return} );
for( $t=0; $t < $func->{numParam}; $t++) {
&addType( $func->{"paramType",$t} );
}
}
# generate the file
if (1) {
# print "\n#include \n\n" if $doCode;
print "\n#include \n\n" if $doCode;
for $include ( @includes ) {
print "#include \"$include\" \n";
}
print "\n#ifdef __cplusplus\nextern \"C\" \n{\n#endif\n";
print "\n\n";
print " \/\* This file uses the types : \n";
# build the type declarations
for $type ( sort keys %types ) {
$type =~ s/\<(\w*)\>/_Tmpl_$1_/;
print "typedef void* ",$type,"Ptr;\n";
}
print " */ \n ";
print "\n\n";
print "/* these function return a string describibg any */ \n";
print "/* errors or NULL if there was no error */ \n\n";
# build the prototypes
for $func ( @functions ) {
if ( $func->{class} ne $prevClass ) {
print "\n" ;
$constructorCount=0;
}
$prevClass = $func->{class};
if ( $func->{name} eq "constructor" ) {
if (1) {
$constructorCount++;
if ( $doCode ) {
print "\n/// See ",$func->{class},"::",$func->{class},"\n";
}
print "int ";
print "\n" if $doCode;
print $func->{class},"_create",$constructorCount;
print "( ",&mapTypeToC($func->{class} . "*"),"* objPtr";
for( $t=0; $t < $func->{numParam}; $t++) {
print ", ",&mapTypeToC($func->{"paramType",$t});
print " ",$func->{"paramName",$t};
}
print ")";
print ";" unless $doCode;
print "\n";
if ( $doCode ) {
print "{\n";
print " int retValue=0;\n";
print " ",$func->{class},"* obj = NULL; \n";
print " try\n";
print " {\n";
print " ";
print "obj = new ",$func->{class},"(";
for( $t=0; $t < $func->{numParam}; $t++) {
print "," if ( $t != 0 );
$type = $func->{"paramType",$t};
if ( $type eq "string" ) {
print "string";
print "(",$func->{"paramName",$t},")";
}
elsif ( $type eq "string&" ) {
print "string";
print "(",$func->{"paramName",$t},")";
}
elsif ( $type =~ /.*&$/ ) {
# deal with a feverence type
$type =~ s/&$//;
print "*static_cast<",$type,"*>";
print "(",$func->{"paramName",$t},")";
}
else {
print "static_cast<",$type,">";
print "(",$func->{"paramName",$t},")";
}
}
print ")";
print ";\n";
print " assert(objPtr); \n";
print " *objPtr = static_cast<",&mapTypeToC($func->{class} . "*"),">(obj); \n";
print " }\n";
print " catch (...)\n";
print " {\n";
print " retValue=-1; \n";
print " }\n";
print " \n";
print " return retValue;\n";
print "}\n\n";
}
}
}
elsif( $func->{name} eq "destructor" ) {
if (1) {
if ( $doCode ) {
print "\n/// See ",$func->{class},"::~",$func->{class},"\n";
}
print "void ";
print "\n" if $doCode;
print $func->{class},"_free";
print "( ",&mapTypeToC($func->{class} . "*")," objPtr";
print ")";
if ( $doCode ) {
print "\n{\n";
print " assert(objPtr);\n";
print " ",$func->{class},"* obj = ";
print "static_cast<",$func->{class},"*>(objPtr);\n";
print " delete obj;\n";
print "}\n";
}
else {
print ";\n";
}
}
}
else {
if (1) {
if ( $doCode ) {
print "\n/// See ",$func->{class},"::",$func->{name},"\n";
}
print "int ";
print "\n" if $doCode;
# deal with overloaded function names
$cName = $func->{class} . "_" . $func->{name};
$count = 1;
while ( $usedName{$cName} ) {
$count++;
$cName = $func->{class} . "_" . $func->{name} . $count;
}
$usedName{$cName} = 1;
print $cName;
print "( ";
# do the this pointer part
print &mapTypeToC($func->{class} . "*")," objPtr" unless $func->{isStatic};
print ", " unless $func->{isStatic} or ( ($func->{numParam}==0) and (($func->{return} eq "void")) );
# do the parametes
for( $t=0; $t < $func->{numParam}; $t++) {
print ", " unless ( $t == 0 );
print &mapTypeToC($func->{"paramType",$t});
print " ",$func->{"paramName",$t};
}
print ", " unless ($func->{return} eq "void")or($func->{numParam}==0);
# do return value part
if ( $func->{return} ne "void" ) {
print &mapTypeToC($func->{return} . "*")," returnValue";
}
# end the first line
print ")";
print ";" unless $doCode;
print "\n";
if ( $doCode ) {
print "{\n";
print " int retValue=0;\n";
if ( !($func->{isStatic}) ) {
print " ",$func->{class},"* obj = ";
print "static_cast<",$func->{class},"*>(objPtr);\n";
}
print " try\n";
print " {\n";
print " ";
# deal with the return type here
if ( $func->{return} ne "void" ) {
print "*reinterpret_cast<",$func->{return},"*>(returnValue) = ";
}
if ( $func->{isStatic} ) {
print "$func->{class}::";
}
else {
print "obj->";
}
print $func->{name},"(";
for( $t=0; $t < $func->{numParam}; $t++) {
print "," if ( $t != 0 );
$type = $func->{"paramType",$t};
if ( $type eq "string" ) {
print "string";
print "(",$func->{"paramName",$t},")";
}
elsif ( $type eq "string&" ) {
print "string";
print "(",$func->{"paramName",$t},")";
}
elsif ( $type =~ /.*&$/ ) {
# deal with a reference type
$type =~ s/&$//;
print "*static_cast<",$type,"*>";
print "(",$func->{"paramName",$t},")";
}
else {
print "static_cast<",$type,">";
print "(",$func->{"paramName",$t},")";
}
}
print ")";
print ";\n";
print " }\n";
print " catch (...)\n";
print " {\n";
print " retValue=-1; \n";
print " }\n";
print " \n";
print " return retValue;\n";
print "}\n\n";
}
}
}
}
print "\n#ifdef __cplusplus\n} /*close extern C*/ \n#endif\n";
}
sub debug {
if($debugCode) {
print STDERR @_;
}
}