mirror of
https://github.com/samba-team/samba.git
synced 2025-12-23 00:23:53 +03:00
now that it is guaranteed that the smbcalls modules are always initialized
after the EJS subsystem itself.
(This used to be commit 1e8670874b)
872 lines
20 KiB
Perl
872 lines
20 KiB
Perl
###################################################
|
|
# EJS function wrapper generator
|
|
# Copyright jelmer@samba.org 2005
|
|
# Copyright Andrew Tridgell 2005
|
|
# released under the GNU GPL
|
|
|
|
package Parse::Pidl::Samba4::EJS;
|
|
|
|
use strict;
|
|
use Parse::Pidl::Typelist;
|
|
use Parse::Pidl::Util qw(has_property);
|
|
|
|
use vars qw($VERSION);
|
|
$VERSION = '0.01';
|
|
|
|
my $res;
|
|
my $res_hdr;
|
|
|
|
my %constants;
|
|
|
|
my $tabs = "";
|
|
|
|
sub pidl_hdr ($)
|
|
{
|
|
$res_hdr .= shift;
|
|
}
|
|
|
|
sub pidl($)
|
|
{
|
|
my $d = shift;
|
|
if ($d) {
|
|
$res .= $tabs;
|
|
$res .= $d;
|
|
}
|
|
$res .= "\n";
|
|
}
|
|
|
|
sub indent()
|
|
{
|
|
$tabs .= "\t";
|
|
}
|
|
|
|
sub deindent()
|
|
{
|
|
$tabs = substr($tabs, 0, -1);
|
|
}
|
|
|
|
# this should probably be in ndr.pm
|
|
sub GenerateStructEnv($)
|
|
{
|
|
my $x = shift;
|
|
my %env;
|
|
|
|
foreach my $e (@{$x->{ELEMENTS}}) {
|
|
if ($e->{NAME}) {
|
|
$env{$e->{NAME}} = "r->$e->{NAME}";
|
|
}
|
|
}
|
|
|
|
$env{"this"} = "r";
|
|
|
|
return \%env;
|
|
}
|
|
|
|
sub GenerateFunctionInEnv($)
|
|
{
|
|
my $fn = shift;
|
|
my %env;
|
|
|
|
foreach my $e (@{$fn->{ELEMENTS}}) {
|
|
if (grep (/in/, @{$e->{DIRECTION}})) {
|
|
$env{$e->{NAME}} = "r->in.$e->{NAME}";
|
|
}
|
|
}
|
|
|
|
return \%env;
|
|
}
|
|
|
|
sub GenerateFunctionOutEnv($)
|
|
{
|
|
my $fn = shift;
|
|
my %env;
|
|
|
|
foreach my $e (@{$fn->{ELEMENTS}}) {
|
|
if (grep (/out/, @{$e->{DIRECTION}})) {
|
|
$env{$e->{NAME}} = "r->out.$e->{NAME}";
|
|
} elsif (grep (/in/, @{$e->{DIRECTION}})) {
|
|
$env{$e->{NAME}} = "r->in.$e->{NAME}";
|
|
}
|
|
}
|
|
|
|
return \%env;
|
|
}
|
|
|
|
sub get_pointer_to($)
|
|
{
|
|
my $var_name = shift;
|
|
|
|
if ($var_name =~ /^\*(.*)$/) {
|
|
return $1;
|
|
} elsif ($var_name =~ /^\&(.*)$/) {
|
|
return "&($var_name)";
|
|
} else {
|
|
return "&$var_name";
|
|
}
|
|
}
|
|
|
|
sub get_value_of($)
|
|
{
|
|
my $var_name = shift;
|
|
|
|
if ($var_name =~ /^\&(.*)$/) {
|
|
return $1;
|
|
} else {
|
|
return "*$var_name";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# work out is a parse function should be declared static or not
|
|
sub fn_declare($$)
|
|
{
|
|
my ($fn,$decl) = @_;
|
|
|
|
if (has_property($fn, "public")) {
|
|
pidl_hdr "$decl;\n";
|
|
pidl "$decl";
|
|
} else {
|
|
pidl "static $decl";
|
|
}
|
|
}
|
|
|
|
###########################
|
|
# pull a scalar element
|
|
sub EjsPullScalar($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
|
|
return if (has_property($e, "value"));
|
|
|
|
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
|
$var = get_pointer_to($var);
|
|
# have to handle strings specially :(
|
|
if ($e->{TYPE} eq "string" && $pl && $pl->{TYPE} eq "POINTER") {
|
|
$var = get_pointer_to($var);
|
|
}
|
|
pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
|
|
}
|
|
|
|
###########################
|
|
# pull a pointer element
|
|
sub EjsPullPointer($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
pidl "if (ejs_pull_null(ejs, v, $name)) {";
|
|
indent;
|
|
pidl "$var = NULL;";
|
|
deindent;
|
|
pidl "} else {";
|
|
indent;
|
|
pidl "EJS_ALLOC(ejs, $var);";
|
|
$var = get_value_of($var);
|
|
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
###########################
|
|
# pull a string element
|
|
sub EjsPullString($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
$var = get_pointer_to($var);
|
|
pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
|
|
}
|
|
|
|
|
|
###########################
|
|
# pull an array element
|
|
sub EjsPullArray($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
|
|
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
|
|
my $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
|
|
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
|
if ($pl && $pl->{TYPE} eq "POINTER") {
|
|
$var = get_pointer_to($var);
|
|
}
|
|
# uint8 arrays are treated as data blobs
|
|
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
|
|
if (!$l->{IS_FIXED}) {
|
|
pidl "EJS_ALLOC_N(ejs, $var, $size);";
|
|
}
|
|
pidl "ejs_pull_array_uint8(ejs, v, $name, $var, $length);";
|
|
return;
|
|
}
|
|
my $avar = $var . "[i]";
|
|
pidl "{";
|
|
indent;
|
|
pidl "uint32_t i;";
|
|
if (!$l->{IS_FIXED}) {
|
|
pidl "EJS_ALLOC_N(ejs, $var, $size);";
|
|
}
|
|
pidl "for (i=0;i<$length;i++) {";
|
|
indent;
|
|
pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
|
|
EjsPullElement($e, $nl, $avar, "id", $env);
|
|
pidl "talloc_free(id);";
|
|
deindent;
|
|
pidl "}";
|
|
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
###########################
|
|
# pull a switch element
|
|
sub EjsPullSwitch($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
|
|
pidl "ejs_set_switch(ejs, $switch_var);";
|
|
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
|
}
|
|
|
|
###########################
|
|
# pull a structure element
|
|
sub EjsPullElement($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
if (has_property($e, "charset")) {
|
|
EjsPullString($e, $l, $var, $name, $env);
|
|
} elsif ($l->{TYPE} eq "ARRAY") {
|
|
EjsPullArray($e, $l, $var, $name, $env);
|
|
} elsif ($l->{TYPE} eq "DATA") {
|
|
EjsPullScalar($e, $l, $var, $name, $env);
|
|
} elsif (($l->{TYPE} eq "POINTER")) {
|
|
EjsPullPointer($e, $l, $var, $name, $env);
|
|
} elsif (($l->{TYPE} eq "SWITCH")) {
|
|
EjsPullSwitch($e, $l, $var, $name, $env);
|
|
} else {
|
|
pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
|
|
}
|
|
}
|
|
|
|
#############################################
|
|
# pull a structure/union element at top level
|
|
sub EjsPullElementTop($$)
|
|
{
|
|
my $e = shift;
|
|
my $env = shift;
|
|
my $l = $e->{LEVELS}[0];
|
|
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
|
|
my $name = "\"$e->{NAME}\"";
|
|
EjsPullElement($e, $l, $var, $name, $env);
|
|
}
|
|
|
|
###########################
|
|
# pull a struct
|
|
sub EjsStructPull($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $env = GenerateStructEnv($d);
|
|
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
EjsPullElementTop($e, $env);
|
|
}
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
###########################
|
|
# pull a union
|
|
sub EjsUnionPull($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $have_default = 0;
|
|
my $env = GenerateStructEnv($d);
|
|
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
|
|
pidl "switch (ejs->switch_var) {";
|
|
indent;
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
if ($e->{CASE} eq "default") {
|
|
$have_default = 1;
|
|
}
|
|
pidl "$e->{CASE}:";
|
|
indent;
|
|
if ($e->{TYPE} ne "EMPTY") {
|
|
EjsPullElementTop($e, $env);
|
|
}
|
|
pidl "break;";
|
|
deindent;
|
|
}
|
|
if (! $have_default) {
|
|
pidl "default:";
|
|
indent;
|
|
pidl "return ejs_panic(ejs, \"Bad switch value\");";
|
|
deindent;
|
|
}
|
|
deindent;
|
|
pidl "}";
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
##############################################
|
|
# put the enum elements in the constants array
|
|
sub EjsEnumConstant($)
|
|
{
|
|
my $d = shift;
|
|
my $v = 0;
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
my $el = $e;
|
|
chomp $el;
|
|
if ($el =~ /^(.*)=\s*(.*)\s*$/) {
|
|
$el = $1;
|
|
$v = $2;
|
|
}
|
|
$constants{$el} = $v;
|
|
$v++;
|
|
}
|
|
}
|
|
|
|
###########################
|
|
# pull a enum
|
|
sub EjsEnumPull($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
EjsEnumConstant($d);
|
|
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "unsigned e;";
|
|
pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
|
|
pidl "*r = e;";
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
###########################
|
|
# pull a bitmap
|
|
sub EjsBitmapPull($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $type_fn = $d->{BASE_TYPE};
|
|
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
|
|
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
|
|
###########################
|
|
# generate a structure pull
|
|
sub EjsTypedefPull($)
|
|
{
|
|
my $d = shift;
|
|
return if (has_property($d, "noejs"));
|
|
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
|
|
EjsStructPull($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
|
|
EjsUnionPull($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
|
|
EjsEnumPull($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
|
|
EjsBitmapPull($d->{NAME}, $d->{DATA});
|
|
} else {
|
|
warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
|
|
}
|
|
}
|
|
|
|
#####################
|
|
# generate a function
|
|
sub EjsPullFunction($)
|
|
{
|
|
my $d = shift;
|
|
my $env = GenerateFunctionInEnv($d);
|
|
my $name = $d->{NAME};
|
|
|
|
pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
|
|
|
|
# we pull non-array elements before array elements as arrays
|
|
# may have length_is() or size_is() properties that depend
|
|
# on the non-array elements
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
next unless (grep(/in/, @{$e->{DIRECTION}}));
|
|
next if (has_property($e, "length_is") ||
|
|
has_property($e, "size_is"));
|
|
EjsPullElementTop($e, $env);
|
|
}
|
|
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
next unless (grep(/in/, @{$e->{DIRECTION}}));
|
|
next unless (has_property($e, "length_is") ||
|
|
has_property($e, "size_is"));
|
|
EjsPullElementTop($e, $env);
|
|
}
|
|
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
|
|
###########################
|
|
# push a scalar element
|
|
sub EjsPushScalar($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
# have to handle strings specially :(
|
|
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
|
if ($e->{TYPE} ne "string" || ($pl && $pl->{TYPE} eq "POINTER")) {
|
|
$var = get_pointer_to($var);
|
|
}
|
|
pidl "NDR_CHECK(ejs_push_$e->{TYPE}(ejs, v, $name, $var));";
|
|
}
|
|
|
|
###########################
|
|
# push a string element
|
|
sub EjsPushString($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
|
|
}
|
|
|
|
###########################
|
|
# push a pointer element
|
|
sub EjsPushPointer($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
pidl "if (NULL == $var) {";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
|
|
deindent;
|
|
pidl "} else {";
|
|
indent;
|
|
$var = get_value_of($var);
|
|
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
###########################
|
|
# push a switch element
|
|
sub EjsPushSwitch($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
|
|
pidl "ejs_set_switch(ejs, $switch_var);";
|
|
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
|
|
}
|
|
|
|
|
|
###########################
|
|
# push an array element
|
|
sub EjsPushArray($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
|
|
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
|
|
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
|
|
if ($pl && $pl->{TYPE} eq "POINTER") {
|
|
$var = get_pointer_to($var);
|
|
}
|
|
# uint8 arrays are treated as data blobs
|
|
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
|
|
pidl "ejs_push_array_uint8(ejs, v, $name, $var, $length);";
|
|
return;
|
|
}
|
|
my $avar = $var . "[i]";
|
|
pidl "{";
|
|
indent;
|
|
pidl "uint32_t i;";
|
|
pidl "for (i=0;i<$length;i++) {";
|
|
indent;
|
|
pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
|
|
EjsPushElement($e, $nl, $avar, "id", $env);
|
|
deindent;
|
|
pidl "}";
|
|
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
################################
|
|
# push a structure/union element
|
|
sub EjsPushElement($$$$$)
|
|
{
|
|
my ($e, $l, $var, $name, $env) = @_;
|
|
if (has_property($e, "charset")) {
|
|
EjsPushString($e, $l, $var, $name, $env);
|
|
} elsif ($l->{TYPE} eq "ARRAY") {
|
|
EjsPushArray($e, $l, $var, $name, $env);
|
|
} elsif ($l->{TYPE} eq "DATA") {
|
|
EjsPushScalar($e, $l, $var, $name, $env);
|
|
} elsif (($l->{TYPE} eq "POINTER")) {
|
|
EjsPushPointer($e, $l, $var, $name, $env);
|
|
} elsif (($l->{TYPE} eq "SWITCH")) {
|
|
EjsPushSwitch($e, $l, $var, $name, $env);
|
|
} else {
|
|
pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
|
|
}
|
|
}
|
|
|
|
#############################################
|
|
# push a structure/union element at top level
|
|
sub EjsPushElementTop($$)
|
|
{
|
|
my $e = shift;
|
|
my $env = shift;
|
|
my $l = $e->{LEVELS}[0];
|
|
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
|
|
my $name = "\"$e->{NAME}\"";
|
|
EjsPushElement($e, $l, $var, $name, $env);
|
|
}
|
|
|
|
###########################
|
|
# push a struct
|
|
sub EjsStructPush($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $env = GenerateStructEnv($d);
|
|
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
EjsPushElementTop($e, $env);
|
|
}
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
###########################
|
|
# push a union
|
|
sub EjsUnionPush($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $have_default = 0;
|
|
my $env = GenerateStructEnv($d);
|
|
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
|
|
pidl "switch (ejs->switch_var) {";
|
|
indent;
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
if ($e->{CASE} eq "default") {
|
|
$have_default = 1;
|
|
}
|
|
pidl "$e->{CASE}:";
|
|
indent;
|
|
if ($e->{TYPE} ne "EMPTY") {
|
|
EjsPushElementTop($e, $env);
|
|
}
|
|
pidl "break;";
|
|
deindent;
|
|
}
|
|
if (! $have_default) {
|
|
pidl "default:";
|
|
indent;
|
|
pidl "return ejs_panic(ejs, \"Bad switch value\");";
|
|
deindent;
|
|
}
|
|
deindent;
|
|
pidl "}";
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
###########################
|
|
# push a enum
|
|
sub EjsEnumPush($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
EjsEnumConstant($d);
|
|
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "unsigned e = *r;";
|
|
pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
###########################
|
|
# push a bitmap
|
|
sub EjsBitmapPush($$)
|
|
{
|
|
my $name = shift;
|
|
my $d = shift;
|
|
my $type_fn = $d->{BASE_TYPE};
|
|
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
|
|
# put the bitmap elements in the constants array
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
if ($e =~ /^(\w*)\s*(.*)\s*$/) {
|
|
my $bname = $1;
|
|
my $v = $2;
|
|
$constants{$bname} = $v;
|
|
}
|
|
}
|
|
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)");
|
|
pidl "{";
|
|
indent;
|
|
pidl "return ejs_push_$type_fn(ejs, v, name, r);";
|
|
deindent;
|
|
pidl "}";
|
|
}
|
|
|
|
|
|
###########################
|
|
# generate a structure push
|
|
sub EjsTypedefPush($)
|
|
{
|
|
my $d = shift;
|
|
return if (has_property($d, "noejs"));
|
|
|
|
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
|
|
EjsStructPush($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
|
|
EjsUnionPush($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
|
|
EjsEnumPush($d->{NAME}, $d->{DATA});
|
|
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
|
|
EjsBitmapPush($d->{NAME}, $d->{DATA});
|
|
} else {
|
|
warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
|
|
}
|
|
}
|
|
|
|
|
|
#####################
|
|
# generate a function
|
|
sub EjsPushFunction($)
|
|
{
|
|
my $d = shift;
|
|
my $env = GenerateFunctionOutEnv($d);
|
|
|
|
pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
|
|
pidl "{";
|
|
indent;
|
|
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
|
|
|
|
foreach my $e (@{$d->{ELEMENTS}}) {
|
|
next unless (grep(/out/, @{$e->{DIRECTION}}));
|
|
EjsPushElementTop($e, $env);
|
|
}
|
|
|
|
if ($d->{RETURN_TYPE}) {
|
|
my $t = $d->{RETURN_TYPE};
|
|
pidl "NDR_CHECK(ejs_push_$t(ejs, v, \"result\", &r->out.result));";
|
|
}
|
|
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
|
|
#################################
|
|
# generate a ejs mapping function
|
|
sub EjsFunction($$)
|
|
{
|
|
my $d = shift;
|
|
my $iface = shift;
|
|
my $name = $d->{NAME};
|
|
my $callnum = uc("DCERPC_$name");
|
|
my $table = "&dcerpc_table_$iface";
|
|
|
|
pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
|
|
pidl "{";
|
|
indent;
|
|
pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
|
|
deindent;
|
|
pidl "}\n";
|
|
}
|
|
|
|
###################
|
|
# handle a constant
|
|
sub EjsConst($)
|
|
{
|
|
my $const = shift;
|
|
$constants{$const->{NAME}} = $const->{VALUE};
|
|
}
|
|
|
|
#####################################################################
|
|
# parse the interface definitions
|
|
sub EjsInterface($$)
|
|
{
|
|
my($interface,$needed) = @_;
|
|
my @fns = ();
|
|
my $name = $interface->{NAME};
|
|
|
|
%constants = ();
|
|
|
|
pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
|
|
pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
|
|
|
|
if (has_property($interface, "depends")) {
|
|
foreach (split / /, $interface->{PROPERTIES}->{depends}) {
|
|
pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
|
|
}
|
|
}
|
|
|
|
pidl_hdr "\n";
|
|
|
|
foreach my $d (@{$interface->{TYPES}}) {
|
|
($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
|
|
($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
|
|
}
|
|
|
|
foreach my $d (@{$interface->{FUNCTIONS}}) {
|
|
next if not defined($d->{OPNUM});
|
|
next if Parse::Pidl::Util::has_property($d, "noejs");
|
|
|
|
EjsPullFunction($d);
|
|
EjsPushFunction($d);
|
|
EjsFunction($d, $name);
|
|
|
|
push (@fns, $d->{NAME});
|
|
}
|
|
|
|
foreach my $d (@{$interface->{CONSTS}}) {
|
|
EjsConst($d);
|
|
}
|
|
|
|
pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
|
|
pidl "{";
|
|
indent;
|
|
pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
|
|
foreach (@fns) {
|
|
pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
|
|
}
|
|
foreach my $v (keys %constants) {
|
|
my $value = $constants{$v};
|
|
if (substr($value, 0, 1) eq "\"") {
|
|
pidl "mprSetVar(obj, \"$v\", mprString($value));";
|
|
} else {
|
|
pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
|
|
}
|
|
}
|
|
pidl "return ejs_rpc_init(obj, \"$name\");";
|
|
deindent;
|
|
pidl "}\n";
|
|
|
|
pidl "NTSTATUS ejs_init_$name(void)";
|
|
pidl "{";
|
|
indent;
|
|
pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
|
|
pidl "return NT_STATUS_OK;";
|
|
deindent;
|
|
pidl "}";
|
|
|
|
pidl_hdr "\n";
|
|
pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a parsed IDL into a C header
|
|
sub Parse($$)
|
|
{
|
|
my($ndr,$hdr) = @_;
|
|
|
|
my $ejs_hdr = $hdr;
|
|
$ejs_hdr =~ s/.h$/_ejs.h/;
|
|
$res = "";
|
|
$res_hdr = "";
|
|
|
|
pidl_hdr "/* header auto-generated by pidl */\n\n";
|
|
|
|
pidl "
|
|
/* EJS wrapper functions auto-generated by pidl */
|
|
#include \"includes.h\"
|
|
#include \"lib/appweb/ejs/ejs.h\"
|
|
#include \"scripting/ejs/ejsrpc.h\"
|
|
#include \"scripting/ejs/smbcalls.h\"
|
|
#include \"librpc/gen_ndr/ndr_misc_ejs.h\"
|
|
#include \"$hdr\"
|
|
#include \"$ejs_hdr\"
|
|
|
|
";
|
|
|
|
my %needed = ();
|
|
|
|
foreach my $x (@{$ndr}) {
|
|
($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
|
|
}
|
|
|
|
foreach my $x (@{$ndr}) {
|
|
($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
|
|
}
|
|
|
|
return ($res_hdr, $res);
|
|
}
|
|
|
|
sub NeededFunction($$)
|
|
{
|
|
my ($fn,$needed) = @_;
|
|
$needed->{"pull_$fn->{NAME}"} = 1;
|
|
$needed->{"push_$fn->{NAME}"} = 1;
|
|
foreach my $e (@{$fn->{ELEMENTS}}) {
|
|
if (grep (/in/, @{$e->{DIRECTION}})) {
|
|
$needed->{"pull_$e->{TYPE}"} = 1;
|
|
}
|
|
if (grep (/out/, @{$e->{DIRECTION}})) {
|
|
$needed->{"push_$e->{TYPE}"} = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub NeededTypedef($$)
|
|
{
|
|
my ($t,$needed) = @_;
|
|
if (Parse::Pidl::Util::has_property($t, "public")) {
|
|
$needed->{"pull_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
|
|
$needed->{"push_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
|
|
}
|
|
if ($t->{DATA}->{TYPE} ne "STRUCT" &&
|
|
$t->{DATA}->{TYPE} ne "UNION") {
|
|
return;
|
|
}
|
|
for my $e (@{$t->{DATA}->{ELEMENTS}}) {
|
|
if ($needed->{"pull_$t->{NAME}"}) {
|
|
$needed->{"pull_$e->{TYPE}"} = 1;
|
|
}
|
|
if ($needed->{"push_$t->{NAME}"}) {
|
|
$needed->{"push_$e->{TYPE}"} = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# work out what parse functions are needed
|
|
sub NeededInterface($$)
|
|
{
|
|
my ($interface,$needed) = @_;
|
|
foreach my $d (@{$interface->{FUNCTIONS}}) {
|
|
NeededFunction($d, $needed);
|
|
}
|
|
foreach my $d (reverse @{$interface->{TYPES}}) {
|
|
NeededTypedef($d, $needed);
|
|
}
|
|
}
|
|
|
|
1;
|