comrogue-pi/tools/pidl/lib/Parse/Pidl/COMROGUE/Header.pm
Eric J. Bowersox 983d6f7f31 added some extra interfaces for heap support, and the code structures defined
in the IDL files necessitated some refinements to the PIDL parser and code
generator
2013-05-07 02:42:36 -06:00

347 lines
8.1 KiB
Perl

# COM Header generation
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Modifications (C) 2013 Eric J. Bowersox <erbo@erbosoft.com>
package Parse::Pidl::COMROGUE::Header;
use Parse::Pidl::Typelist qw(mapTypeName maybeMapScalarType is_struct is_enum);
use Parse::Pidl::Util qw(has_property is_constant);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub stripquotes($)
{
my $str = shift;
$str =~ s/^\"//;
$str =~ s/\"$//;
return $str;
}
sub GetArgumentProtoList($)
{
my $f = shift;
my $res = "";
my $first = 1;
foreach my $a (@{$f->{ELEMENTS}}) {
$res .= ", " unless $first;
$first = 0;
$res .= maybeMapScalarType($a->{TYPE}) . " ";
my $l = $a->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($a->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
if (defined $a->{ARRAY_LEN}[0] && !is_constant($a->{ARRAY_LEN}[0]) &&
!$a->{POINTERS}) {
$res .= "*";
}
$res .= $a->{NAME};
if (defined $a->{ARRAY_LEN}[0] && is_constant($a->{ARRAY_LEN}[0])) {
$res .= "[$a->{ARRAY_LEN}[0]]";
}
}
return undef if $first;
return $res;
}
sub GetArgumentList($)
{
my $f = shift;
my $res = "";
my $first = 1;
foreach (@{$f->{ELEMENTS}}) {
$res .= ", " unless $first;
$first = 0;
$res .= "$_->{NAME}";
}
return undef if $first;
return $res;
}
sub MethodsDefinition($)
{
my $interface = shift;
my $res = "";
$res .= "#define METHODS_" . $interface->{NAME} . " \\\n";
if (defined($interface->{BASE})) {
$res .= "\tINHERIT_METHODS(METHODS_" . $interface->{BASE} . ") \\\n";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
next unless ($d->{TYPE} eq "FUNCTION");
if ($d->{RETURN_TYPE} eq "HRESULT") {
$res .= "\tSTDMETHOD($d->{NAME})";
} else {
$res .= "\tSTDMETHOD_($d->{NAME}," . $d->{RETURN_TYPE} . ")";
}
my $args = GetArgumentProtoList($d);
if (defined($args)) {
$res .= "(THIS_($interface->{NAME}) $args) PURE;\\\n";
} else {
$res .= "(THIS($interface->{NAME})) PURE;\\\n";
}
}
$res .= "\tEND_METHODS\n\n";
return $res;
}
sub MakeGUIDDef($$$)
{
my $t = shift;
my $name = shift;
my $uuid = shift;
my @uuidparts = split(/-/, $uuid);
my $b1 = substr($uuidparts[3], 0, 2);
my $b2 = substr($uuidparts[3], 2, 2);
my $b3 = substr($uuidparts[4], 0, 2);
my $b4 = substr($uuidparts[4], 2, 2);
my $b5 = substr($uuidparts[4], 4, 2);
my $b6 = substr($uuidparts[4], 6, 2);
my $b7 = substr($uuidparts[4], 8, 2);
my $b8 = substr($uuidparts[4], 10, 2);
return "DEFINE_$t(${t}_$name, 0x$uuidparts[0], 0x$uuidparts[1], 0x$uuidparts[2], " .
"0x$b1, 0x$b2, 0x$b3, 0x$b4, 0x$b5, 0x$b6, 0x$b7, 0x$b8);\n\n";
}
sub ParseImports($)
{
my $imp = shift;
my $res = "";
my $seen = 0;
foreach my $p (@{$imp->{PATHS}}) {
my $header = $p;
$header =~ s/\.idl/\.h/;
$header =~ s/^\"/</;
$header =~ s/\"$/>/;
$res .= "#include $header\n";
$seen = 1;
}
$res .= "\n" if $seen;
return $res;
}
sub ParseElement($$)
{
my $prefix = shift;
my $element = shift;
my $res = "";
$res .= $prefix . maybeMapScalarType($element->{TYPE}) . " ";
my $l = $element->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($element->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
$res .= $element->{NAME};
if (defined($element->{ARRAY_LEN})) {
foreach my $l (@{$element->{ARRAY_LEN}}) {
$res .= "[" . $l . "]";
}
}
$res .= ";\n";
return $res;
}
sub ParseTypedef($)
{
my $def = shift;
my $res = "";
$res .= "typedef ";
$res .= "const " if ($def->{CONST});
if (ref($def->{DATA}) ne "HASH") {
$res .= maybeMapScalarType($def->{DATA}) . " ";
} else {
if (is_struct($def->{DATA})) {
$res .= mapTypeName($def->{DATA}) . " {\n";
foreach my $elt (@{$def->{DATA}->{ELEMENTS}}) {
$res .= ParseElement("\t", $elt);
}
$res .= "} ";
} elsif (is_enum($def->{DATA})) {
$res .= mapTypeName($def->{DATA}) . " {";
my $first = 1;
foreach my $elt (@{$def->{DATA}->{ELEMENTS}}) {
$res .= "," if $first == 0;
$first = 0;
$res .= "\n\t" . $elt;
}
$res .= "\n} ";
} else {
$res .= mapTypeName($def->{DATA}) . " ";
}
}
my $l = $def->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($def->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
$res .= $def->{NAME} . ";\n";
return $res;
}
sub ParseTypedefs($)
{
my $if = shift;
my $res = "";
my $count = 0;
foreach my $d (@{$if->{DATA}}) {
$res .= stripquotes($d->{DATA}) . "\n" if ($d->{TYPE} eq "CPP_QUOTE");
next unless ($d->{TYPE} eq "TYPEDEF");
++$count;
$res .= ParseTypedef($d);
}
$res .= "\n";
return "" if ($count == 0);
return $res;
}
sub ParseInterface($)
{
my $if = shift;
my $res;
my $d;
$res .= "/*---------------------------------------------------------------\n";
$res .= " * Interface $if->{NAME}\n";
$res .= " *---------------------------------------------------------------\n";
$res .= " */\n\n";
foreach $d (@{$if->{DATA}}) {
$res .= stripquotes($d->{DATA}) . "\n" if ($d->{TYPE} eq "CPP_QUOTE");
$res .= ParseTypedef($d) if ($d->{TYPE} eq "TYPEDEF");
}
$res .= MakeGUIDDef("IID", $if->{NAME}, $if->{PROPERTIES}->{uuid});
$res .= MethodsDefinition($if);
if (defined($if->{BASE})) {
$res .= "BEGIN_INTERFACE_(" . $if->{NAME} . ", " . $if->{BASE} . ")\n";
} else {
$res .= "BEGIN_INTERFACE(" . $if->{NAME} . ")\n";
}
$res .= "\tMETHODS_" . $if->{NAME} . "\n";
$res .= "END_INTERFACE(" . $if->{NAME} . ")\n\n";
$res .= "\n#ifdef CINTERFACE\n\n";
foreach $d (@{$if->{DATA}}) {
next unless ($d->{TYPE} eq "FUNCTION");
my $args = GetArgumentList($d);
if (defined($args)) {
$res .= "#define $if->{NAME}_$d->{NAME}(pInterface, $args) \\\n";
$res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(($if->{NAME} *)(pInterface), $args)\n";
} else {
$res .= "#define $if->{NAME}_$d->{NAME}(pInterface) \\\n";
$res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(($if->{NAME} *)(pInterface))\n";
}
}
$res .= "\n#endif /* CINTERFACE */\n\n";
return $res;
}
sub ParseCoClass($)
{
my ($c) = @_;
my $res = "";
$res .= "/*---------------------------------------------------------------\n";
$res .= " * Class $c->{NAME}\n";
$res .= " *---------------------------------------------------------------\n";
$res .= " */\n\n";
$res .= MakeGUIDDef("CLSID", $c->{NAME}, $c->{PROPERTIES}->{uuid});
if (has_property($c, "progid")) {
$res .= "#define PROGID_" . $c->{NAME} . " \"$c->{PROPERTIES}->{progid}\"\n";
}
$res .= "\n";
return $res;
}
sub Parse($$$)
{
my ($idl,$basename, $srcfile) = @_;
my $res = "";
my $has_obj = 0;
$res .= "/* COMROGUE: Autogenerated from IDL file $srcfile */\n\n";
my $include_sym = "__" . uc($basename) . "_H_INCLUDED";
$res .= "#ifndef $include_sym\n" .
"#define $include_sym\n\n" .
"#ifndef __ASM__\n\n";
my $want_macro_headers = 1;
foreach (@{$idl})
{
next unless ($_->{TYPE} eq "INTERFACE");
next unless (has_property($_, "object"));
if ($want_macro_headers) {
$res .= "#include <comrogue/object_definition_macros.h>\n\n";
$want_macro_headers = 0;
}
$res .= "DECLARE_INTERFACE(" . $_->{NAME} . ")\n";
}
$res .= "\n";
foreach (@{$idl})
{
if ($_->{TYPE} eq "CPP_QUOTE") {
$res .= stripquotes($_->{DATA}) . "\n";
}
if ($_->{TYPE} eq "IMPORT") {
$res .= ParseImports($_);
}
if ($_->{TYPE} eq "INTERFACE") {
if (has_property($_, "object")) {
if ($want_macro_headers) {
$res .= "#include <comrogue/object_definition_macros.h>\n\n";
$want_macro_headers = 0;
}
$res .= ParseInterface($_);
} else {
$res .= ParseTypedefs($_);
}
$has_obj = 1;
}
if ($_->{TYPE} eq "COCLASS") {
if ($want_macro_headers) {
$res .= "#include <comrogue/object_definition_macros.h>\n\n";
$want_macro_headers = 0;
}
$res.=ParseCoClass($_);
$has_obj = 1;
}
}
$res .= "#endif /* __ASM__ */\n\n";
$res .= "#endif /* $include_sym */\n";
return $res if ($has_obj);
return undef;
}
1;