pidl: Move Generate*Env functions to Parse::Pidl::Samba4::Header because they only...
[ira/wip.git] / source / pidl / lib / Parse / Pidl / Samba4 / EJS.pm
index f5aea73d12f7e3e58946d191fc5def0e93183a95..efb3f2858d6da539c3b95cb9a250879ebeb64b92 100644 (file)
 
 package Parse::Pidl::Samba4::EJS;
 
+use Exporter;
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(check_null_pointer fn_declare TypeFunctionName);
+
 use strict;
-use Parse::Pidl::Typelist;
-use Parse::Pidl::Util qw(has_property);
+use Parse::Pidl::Typelist qw(typeHasBody);
+use Parse::Pidl::CUtil qw(get_pointer_to get_value_of);
+use Parse::Pidl::Util qw(has_property ParseExpr);
+use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel);
+use Parse::Pidl::Samba4::Header qw(GenerateStructEnv GenerateFunctionInEnv
+                                        GenerateFunctionOutEnv);
 
 use vars qw($VERSION);
 $VERSION = '0.01';
 
-my($res);
-my %constants;
-
-my $tabs = "";
-sub pidl($)
-{
-       my $d = shift;
-       if ($d) {
-               $res .= $tabs;
-               $res .= $d;
-       }
-       $res .= "\n";
-}
-
-sub indent()
-{
-       $tabs .= "\t";
+sub new($) {
+       my ($class) = @_;
+       my $self = { res => "", res_hdr => "", tabs => "", constants => {}};
+       bless($self, $class);
 }
 
-sub deindent()
+sub pidl_hdr ($$)
 {
-       $tabs = substr($tabs, 0, -1);
+       my $self = shift;
+       $self->{res_hdr} .= shift;
 }
 
-# this should probably be in ndr.pm
-sub GenerateStructEnv($)
+sub pidl($$)
 {
-       my $x = shift;
-       my %env;
-
-       foreach my $e (@{$x->{ELEMENTS}}) {
-               if ($e->{NAME}) {
-                       $env{$e->{NAME}} = "r->$e->{NAME}";
-               }
+       my ($self, $d) = @_;
+       if ($d) {
+               $self->{res} .= $self->{tabs};
+               $self->{res} .= $d;
        }
-
-       $env{"this"} = "r";
-
-       return \%env;
+       $self->{res} .= "\n";
 }
 
-sub GenerateFunctionInEnv($)
+sub indent($)
 {
-       my $fn = shift;
-       my %env;
-
-       foreach my $e (@{$fn->{ELEMENTS}}) {
-               if (grep (/in/, @{$e->{DIRECTION}})) {
-                       $env{$e->{NAME}} = "r->in.$e->{NAME}";
-               }
-       }
-
-       return \%env;
+       my ($self) = @_;
+       $self->{tabs} .= "\t";
 }
 
-sub GenerateFunctionOutEnv($)
+sub deindent($)
 {
-       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;
+       my ($self) = @_;
+       $self->{tabs} = substr($self->{tabs}, 0, -1);
 }
 
-sub get_pointer_to($)
+#####################################################################
+# check that a variable we get from ParseExpr isn't a null pointer
+sub check_null_pointer($$)
 {
-       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";
+       my ($self, $size) = @_;
+       if ($size =~ /^\*/) {
+               my $size2 = substr($size, 1);
+               $self->pidl("if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;");
        }
 }
 
 #####################################################################
 # work out is a parse function should be declared static or not
-sub fn_prefix($)
+sub fn_declare($$$)
 {
-       my $fn = shift;
+       my ($self,$fn,$decl) = @_;
 
-       return "" if (has_property($fn, "public"));
-       return "static ";
+       if (has_property($fn, "public")) {
+               $self->pidl_hdr("$decl;\n");
+               $self->pidl("_PUBLIC_ $decl");
+       } else {
+               $self->pidl("static $decl");
+       }
 }
 
 ###########################
 # pull a scalar element
-sub EjsPullScalar($$$$$)
+sub EjsPullScalar($$$$$$$)
 {
-       my ($e, $l, $var, $name, $env) = @_;
+       my ($self, $e, $l, $var, $name, $env) = @_;
 
        return if (has_property($e, "value"));
 
-        my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
+       if (ref($e->{TYPE}) eq "HASH" and not defined($e->{TYPE}->{NAME})) {
+               $self->EjsTypePull($e->{TYPE}, $var);
+       } else {
+               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") {
+               if (Parse::Pidl::Typelist::scalar_is_reference($e->{TYPE})
+                       and (defined($pl) and $pl->{TYPE} eq "POINTER")) {
                 $var = get_pointer_to($var);
         }
-       pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
+
+       my $t;
+               if (ref($e->{TYPE}) eq "HASH") {
+                       $t = "$e->{TYPE}->{TYPE}_$e->{TYPE}->{NAME}";
+               } else {
+                       $t = $e->{TYPE};
+               }
+               $self->pidl("EJS_CHECK(ejs_pull_$t(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);";
+sub EjsPullPointer($$$$$$)
+{
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       $self->pidl("if (ejs_pull_null(ejs, v, $name)) {");
+       $self->indent;
+       if ($l->{POINTER_TYPE} eq "ref") {
+               $self->pidl("return NT_STATUS_INVALID_PARAMETER_MIX;");
+       } else {
+               $self->pidl("$var = NULL;");
+       }
+       $self->deindent;
+       $self->pidl("} else {");
+       $self->indent;
+       $self->pidl("EJS_ALLOC(ejs, $var);");
        $var = get_value_of($var);              
-       EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
-       deindent;
-       pidl "}";
+       $self->EjsPullElement($e, GetNextLevel($e, $l), $var, $name, $env);
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ###########################
 # pull a string element
-sub EjsPullString($$$$$)
+sub EjsPullString($$$$$$)
 {
-       my ($e, $l, $var, $name, $env) = @_;
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $pl = GetPrevLevel($e, $l);
        $var = get_pointer_to($var);
-       pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
+       if (defined($pl) and $pl->{TYPE} eq "POINTER") {
+               $var = get_pointer_to($var);
+       }
+       $self->pidl("EJS_CHECK(ejs_pull_string(ejs, v, $name, $var));");
 }
 
-
 ###########################
 # pull an array element
-sub EjsPullArray($$$$$)
+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);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $nl = GetNextLevel($e, $l);
+       my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
+       my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
+       my $pl = 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);";
+                       $self->check_null_pointer($size);
+                       $self->pidl("EJS_ALLOC_N(ejs, $var, $size);");
                }
-               pidl "ejs_pull_array_uint8(ejs, v, $name, $var, $length);";
+               $self->check_null_pointer($length);
+               $self->pidl("ejs_pull_array_uint8(ejs, v, $name, $var, $length);");
                return;
        }
        my $avar = $var . "[i]";
-       pidl "{";
-       indent;
-       pidl "uint32_t i;";
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("uint32_t i;");
        if (!$l->{IS_FIXED}) {
-               pidl "EJS_ALLOC_N(ejs, $var, $size);";
+               $self->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 "}";
+       $self->pidl("for (i=0;i<$length;i++) {");
+       $self->indent;
+       $self->pidl("char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);");
+       $self->EjsPullElement($e, $nl, $avar, "id", $env);
+       $self->pidl("talloc_free(id);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("ejs_push_uint32(ejs, v, $name \".length\", &i);");
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ###########################
 # pull a switch element
-sub EjsPullSwitch($$$$$)
+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);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
+       $self->pidl("ejs_set_switch(ejs, $switch_var);");
+       $self->EjsPullElement($e, GetNextLevel($e, $l), $var, $name, $env);
 }
 
 ###########################
 # pull a structure element
-sub EjsPullElement($$$$$)
+sub EjsPullElement($$$$$$)
 {
-       my ($e, $l, $var, $name, $env) = @_;
-       if (has_property($e, "charset")) {
-               EjsPullString($e, $l, $var, $name, $env);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       if (($l->{TYPE} eq "POINTER")) {
+               $self->EjsPullPointer($e, $l, $var, $name, $env);
+       } elsif (has_property($e, "charset")) {
+               $self->EjsPullString($e, $l, $var, $name, $env);
        } elsif ($l->{TYPE} eq "ARRAY") {
-               EjsPullArray($e, $l, $var, $name, $env);
+               $self->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);
+               $self->EjsPullScalar($e, $l, $var, $name, $env);
        } elsif (($l->{TYPE} eq "SWITCH")) {
-               EjsPullSwitch($e, $l, $var, $name, $env);
+               $self->EjsPullSwitch($e, $l, $var, $name, $env);
        } else {
-               pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
+               $self->pidl("return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");");
        }
 }
 
 #############################################
 # pull a structure/union element at top level
-sub EjsPullElementTop($$)
+sub EjsPullElementTop($$$)
 {
-       my $e = shift;
-       my $env = shift;
+       my ($self, $e, $env) = @_;
        my $l = $e->{LEVELS}[0];
-       my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
+       my $var = ParseExpr($e->{NAME}, $env, $e);
        my $name = "\"$e->{NAME}\"";
-       EjsPullElement($e, $l, $var, $name, $env);
+       $self->EjsPullElement($e, $l, $var, $name, $env);
 }
 
 ###########################
 # pull a struct
-sub EjsStructPull($$)
-{
-       my $name = shift;
-       my $d = shift;
-       my $env = GenerateStructEnv($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)\n{";
-       indent;
-       pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
-        foreach my $e (@{$d->{ELEMENTS}}) {
-               EjsPullElementTop($e, $env);
+sub EjsStructPull($$$)
+{
+       my ($self, $d, $varname) = @_;
+       my $env = GenerateStructEnv($d, $varname);
+       $self->pidl("EJS_CHECK(ejs_pull_struct_start(ejs, &v, name));");
+    foreach my $e (@{$d->{ELEMENTS}}) {
+               $self->EjsPullElementTop($e, $env);
        }
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}\n";
 }
 
 ###########################
 # pull a union
-sub EjsUnionPull($$)
+sub EjsUnionPull($$$)
 {
-       my $name = shift;
-       my $d = shift;
+       my ($self, $d, $varname) = @_;
        my $have_default = 0;
-       my $env = GenerateStructEnv($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)\n{";
-       indent;
-       pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
-       pidl "switch (ejs->switch_var) {";
-       indent;
+       $self->pidl("EJS_CHECK(ejs_pull_struct_start(ejs, &v, name));");
+       $self->pidl("switch (ejs->switch_var) {");
+       $self->indent;
        foreach my $e (@{$d->{ELEMENTS}}) {
                if ($e->{CASE} eq "default") {
                        $have_default = 1;
                }
-               pidl "$e->{CASE}:";
-               indent;
+               $self->pidl("$e->{CASE}:");
+               $self->indent;
                if ($e->{TYPE} ne "EMPTY") {
-                       EjsPullElementTop($e, $env);
+                       $self->EjsPullElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"});
                }
-               pidl "break;";
-               deindent;
+               $self->pidl("break;");
+               $self->deindent;
        }
        if (! $have_default) {
-               pidl "default:";
-               indent;
-               pidl "return ejs_panic(ejs, \"Bad switch value\");";
-               deindent;
+               $self->pidl("default:");
+               $self->indent;
+               $self->pidl("return ejs_panic(ejs, \"Bad switch value\");");
+               $self->deindent;
        }
-       deindent;
-       pidl "}";
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}";
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ##############################################
 # put the enum elements in the constants array
-sub EjsEnumConstant($)
+sub EjsEnumConstant($$)
 {
-       my $d = shift;
+       my ($self, $d) = @_;
+       return unless (defined($d->{ELEMENTS}));
        my $v = 0;
        foreach my $e (@{$d->{ELEMENTS}}) {
                my $el = $e;
@@ -315,456 +283,501 @@ sub EjsEnumConstant($)
                        $el = $1;
                        $v = $2;
                }
-               $constants{$el} = $v;
+               $self->{constants}->{$el} = $v;
                $v++;
        }
 }
 
 ###########################
 # pull a enum
-sub EjsEnumPull($$)
-{
-       my $name = shift;
-       my $d = shift;
-       EjsEnumConstant($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)\n{";
-       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";
+sub EjsEnumPull($$$)
+{
+       my ($self, $d, $varname) = @_;
+       $self->EjsEnumConstant($d);
+       $self->pidl("unsigned e;");
+       $self->pidl("EJS_CHECK(ejs_pull_enum(ejs, v, name, &e));");
+       $self->pidl("*$varname = e;");
 }
 
 ###########################
 # pull a bitmap
-sub EjsBitmapPull($$)
+sub EjsBitmapPull($$$)
 {
-       my $name = shift;
-       my $d = shift;
+       my ($self, $d, $varname) = @_;
        my $type_fn = $d->{BASE_TYPE};
-       my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)\n{";
-       indent;
-       pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
-       deindent;
-       pidl "}";
+       $self->pidl("EJS_CHECK(ejs_pull_$type_fn(ejs, v, name, $varname));");
 }
 
-
-###########################
-# generate a structure pull
-sub EjsTypedefPull($)
+sub EjsTypePullFunction($$$)
 {
-       my $d = shift;
+       sub EjsTypePullFunction($$$);
+       my ($self, $d, $name) = @_;
        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});
+
+       if ($d->{TYPE} eq "TYPEDEF") {
+               $self->EjsTypePullFunction($d->{DATA}, $name);
+               return;
+       }
+
+       if ($d->{TYPE} eq "STRUCT") {
+               $self->fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)");
+       } elsif ($d->{TYPE} eq "UNION") {
+               $self->fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)");
+       } elsif ($d->{TYPE} eq "ENUM") {
+               $self->fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)");
+       } elsif ($d->{TYPE} eq "BITMAP") {
+               my($type_decl) = Parse::Pidl::Typelist::mapTypeName($d->{BASE_TYPE});
+               $self->fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)");
+       }
+       $self->pidl("{");
+       $self->indent;
+
+       $self->EjsTypePull($d, "r");
+
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}\n");
+}
+
+sub EjsTypePull($$$)
+{
+       my ($self, $d, $varname) = @_;
+       if ($d->{TYPE} eq 'STRUCT') {
+               $self->EjsStructPull($d, $varname);
+       } elsif ($d->{TYPE} eq 'UNION') {
+               $self->EjsUnionPull($d, $varname);
+       } elsif ($d->{TYPE} eq 'ENUM') {
+               $self->EjsEnumPull($d, $varname);
+       } elsif ($d->{TYPE} eq 'BITMAP') {
+               $self->EjsBitmapPull($d, $varname);
        } else {
-               warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
+               warn "Unhandled pull $varname of type $d->{TYPE}";
        }
 }
 
 #####################
 # generate a function
-sub EjsPullFunction($)
+sub EjsPullFunction($$)
 {
-       my $d = shift;
+       my ($self, $d) = @_;
        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\"));";
+       $self->pidl("\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("EJS_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);
+               next if (has_property($e, "length_is") || has_property($e, "size_is"));
+               $self->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);
+               next unless (has_property($e, "length_is") || has_property($e, "size_is"));
+               $self->EjsPullElementTop($e, $env);
        }
 
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}\n";
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}\n");
 }
 
-
 ###########################
 # push a scalar element
-sub EjsPushScalar($$$$$)
+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));";
+       my ($self, $e, $l, $var, $name, $env) = @_;
+
+       if (ref($e->{TYPE}) eq "HASH" and not defined($e->{TYPE}->{NAME})) {
+               $self->EjsTypePush($e->{TYPE}, get_pointer_to($var));
+       } else {
+    # have to handle strings specially :(
+        my $pl = GetPrevLevel($e, $l);
+
+               if ((not Parse::Pidl::Typelist::scalar_is_reference($e->{TYPE}))
+                       or (defined($pl) and $pl->{TYPE} eq "POINTER")) {
+                                       $var = get_pointer_to($var);
+                       }
+
+               $self->pidl("EJS_CHECK(".TypeFunctionName("ejs_push", $e->{TYPE})."(ejs, v, $name, $var));");
+       }
 }
 
 ###########################
 # push a string element
-sub EjsPushString($$$$$)
+sub EjsPushString($$$$$$)
 {
-       my ($e, $l, $var, $name, $env) = @_;
-       pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $pl = GetPrevLevel($e, $l);
+       if (defined($pl) and $pl->{TYPE} eq "POINTER") {
+               $var = get_pointer_to($var);
+       }
+       $self->pidl("EJS_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;
+sub EjsPushPointer($$$$$$)
+{
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       $self->pidl("if (NULL == $var) {");
+       $self->indent;
+       if ($l->{POINTER_TYPE} eq "ref") {
+               $self->pidl("return NT_STATUS_INVALID_PARAMETER_MIX;");
+       } else {
+               $self->pidl("EJS_CHECK(ejs_push_null(ejs, v, $name));");
+       }
+       $self->deindent;
+       $self->pidl("} else {");
+       $self->indent;
        $var = get_value_of($var);              
-       EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
-       deindent;
-       pidl "}";
+       $self->EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ###########################
 # push a switch element
-sub EjsPushSwitch($$$$$)
+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);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
+       $self->pidl("ejs_set_switch(ejs, $switch_var);");
+       $self->EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
 }
 
-
 ###########################
 # push an array element
-sub EjsPushArray($$$$$)
+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);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       my $nl = GetNextLevel($e, $l);
+       my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
+       my $pl = 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);";
+               $self->check_null_pointer($length);
+               $self->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 "}";
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("uint32_t i;");
+       $self->pidl("for (i=0;i<$length;i++) {");
+       $self->indent;
+       $self->pidl("const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);");
+       $self->EjsPushElement($e, $nl, $avar, "id", $env);
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("ejs_push_uint32(ejs, v, $name \".length\", &i);");
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ################################
 # push a structure/union element
-sub EjsPushElement($$$$$)
+sub EjsPushElement($$$$$$)
 {
-       my ($e, $l, $var, $name, $env) = @_;
-       if (has_property($e, "charset")) {
-               EjsPushString($e, $l, $var, $name, $env);
+       my ($self, $e, $l, $var, $name, $env) = @_;
+       if (($l->{TYPE} eq "POINTER")) {
+               $self->EjsPushPointer($e, $l, $var, $name, $env);
+       } elsif (has_property($e, "charset")) {
+               $self->EjsPushString($e, $l, $var, $name, $env);
        } elsif ($l->{TYPE} eq "ARRAY") {
-               EjsPushArray($e, $l, $var, $name, $env);
+               $self->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);
+               $self->EjsPushScalar($e, $l, $var, $name, $env);
        } elsif (($l->{TYPE} eq "SWITCH")) {
-               EjsPushSwitch($e, $l, $var, $name, $env);
+               $self->EjsPushSwitch($e, $l, $var, $name, $env);
        } else {
-               pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
+               $self->pidl("return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");");
        }
 }
 
 #############################################
 # push a structure/union element at top level
-sub EjsPushElementTop($$)
+sub EjsPushElementTop($$$)
 {
-       my $e = shift;
-       my $env = shift;
+       my ($self, $e, $env) = @_;
        my $l = $e->{LEVELS}[0];
-       my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
+       my $var = ParseExpr($e->{NAME}, $env, $e);
        my $name = "\"$e->{NAME}\"";
-       EjsPushElement($e, $l, $var, $name, $env);
+       $self->EjsPushElement($e, $l, $var, $name, $env);
 }
 
 ###########################
 # push a struct
-sub EjsStructPush($$)
-{
-       my $name = shift;
-       my $d = shift;
-       my $env = GenerateStructEnv($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)\n{";
-       indent;
-       pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
+sub EjsStructPush($$$)
+{
+       my ($self, $d, $varname) = @_;
+       my $env = GenerateStructEnv($d, $varname);
+       $self->pidl("EJS_CHECK(ejs_push_struct_start(ejs, &v, name));");
         foreach my $e (@{$d->{ELEMENTS}}) {
-               EjsPushElementTop($e, $env);
+               $self->EjsPushElementTop($e, $env);
        }
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}\n";
 }
 
 ###########################
 # push a union
-sub EjsUnionPush($$)
+sub EjsUnionPush($$$)
 {
-       my $name = shift;
-       my $d = shift;
+       my ($self, $d, $varname) = @_;
        my $have_default = 0;
-       my $env = GenerateStructEnv($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)\n{";
-       indent;
-       pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
-       pidl "switch (ejs->switch_var) {";
-       indent;
+       $self->pidl("EJS_CHECK(ejs_push_struct_start(ejs, &v, name));");
+       $self->pidl("switch (ejs->switch_var) {");
+       $self->indent;
        foreach my $e (@{$d->{ELEMENTS}}) {
                if ($e->{CASE} eq "default") {
                        $have_default = 1;
                }
-               pidl "$e->{CASE}:";
-               indent;
+               $self->pidl("$e->{CASE}:");
+               $self->indent;
                if ($e->{TYPE} ne "EMPTY") {
-                       EjsPushElementTop($e, $env);
+                       $self->EjsPushElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"} );
                }
-               pidl "break;";
-               deindent;
+               $self->pidl("break;");
+               $self->deindent;
        }
        if (! $have_default) {
-               pidl "default:";
-               indent;
-               pidl "return ejs_panic(ejs, \"Bad switch value\");";
-               deindent;
+               $self->pidl("default:");
+               $self->indent;
+               $self->pidl("return ejs_panic(ejs, \"Bad switch value\");");
+               $self->deindent;
        }
-       deindent;
-       pidl "}";
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}";
+       $self->deindent;
+       $self->pidl("}");
 }
 
 ###########################
 # push a enum
-sub EjsEnumPush($$)
+sub EjsEnumPush($$$)
 {
-       my $name = shift;
-       my $d = shift;
-       EjsEnumConstant($d);
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)\n{";
-       indent;
-       pidl "unsigned e = *r;";
-       pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}\n";
+       my ($self, $d, $varname) = @_;
+       $self->EjsEnumConstant($d);
+       $self->pidl("unsigned e = ".get_value_of($varname).";");
+       $self->pidl("EJS_CHECK(ejs_push_enum(ejs, v, name, &e));");
 }
 
 ###########################
 # push a bitmap
-sub EjsBitmapPush($$)
+sub EjsBitmapPush($$$)
 {
-       my $name = shift;
-       my $d = shift;
+       my ($self, $d, $varname) = @_;
+       return unless (defined($d->{ELEMENTS}));
        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;
+                       $self->{constants}->{$bname} = $v;
                }
        }
-       pidl fn_prefix($d);
-       pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)\n{";
-       indent;
-       pidl "return ejs_push_$type_fn(ejs, v, name, r);";
-       deindent;
-       pidl "}";
+       $self->pidl("EJS_CHECK(ejs_push_$type_fn(ejs, v, name, $varname));");
 }
 
-
-###########################
-# generate a structure push
-sub EjsTypedefPush($)
+sub EjsTypePushFunction($$$)
 {
-       my $d = shift;
+       sub EjsTypePushFunction($$$);
+       my ($self, $d, $name) = @_;
        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});
+
+       my $var = undef;
+       my $dt = $d;
+       if ($dt->{TYPE} eq "TYPEDEF") {
+               $dt = $dt->{DATA};
+       }
+       if ($dt->{TYPE} eq "STRUCT") {
+               $var = "const struct $name *r";
+       } elsif ($dt->{TYPE} eq "UNION") {
+               $var = "const union $name *r";
+       } elsif ($dt->{TYPE} eq "ENUM") {
+               $var = "const enum $name *r";
+       } elsif ($dt->{TYPE} eq "BITMAP") {
+               my($type_decl) = Parse::Pidl::Typelist::mapTypeName($dt->{BASE_TYPE});
+               $var = "const $type_decl *r";
+       }
+       $self->fn_declare($d, "NTSTATUS ".TypeFunctionName("ejs_push", $d) . "(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $var)");
+       $self->pidl("{");
+       $self->indent;
+       $self->EjsTypePush($d, "r");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}\n");
+}
+
+sub EjsTypePush($$$)
+{
+       sub EjsTypePush($$$);
+       my ($self, $d, $varname) = @_;
+
+       if ($d->{TYPE} eq 'STRUCT') {
+               $self->EjsStructPush($d, $varname);
+       } elsif ($d->{TYPE} eq 'UNION') {
+               $self->EjsUnionPush($d, $varname);
+       } elsif ($d->{TYPE} eq 'ENUM') {
+               $self->EjsEnumPush($d, $varname);
+       } elsif ($d->{TYPE} eq 'BITMAP') {
+               $self->EjsBitmapPush($d, $varname);
+       } elsif ($d->{TYPE} eq 'TYPEDEF') {
+               $self->EjsTypePush($d->{DATA}, $varname);
        } else {
-               warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
+               warn "Unhandled push $varname of type $d->{TYPE}";
        }
 }
 
-
 #####################
 # generate a function
-sub EjsPushFunction($)
+sub EjsPushFunction($$)
 {
-       my $d = shift;
+       my ($self, $d) = @_;
        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\"));";
+       $self->pidl("\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("EJS_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));");
 
        foreach my $e (@{$d->{ELEMENTS}}) {
                next unless (grep(/out/, @{$e->{DIRECTION}}));
-               EjsPushElementTop($e, $env);
+               $self->EjsPushElementTop($e, $env);
        }
 
        if ($d->{RETURN_TYPE}) {
-               my $t = $d->{RETURN_TYPE};
-               pidl "NDR_CHECK(ejs_push_$t(ejs, v, \"result\", &r->out.result));";
+               $self->pidl("EJS_CHECK(".TypeFunctionName("ejs_push", $d->{RETURN_TYPE})."(ejs, v, \"result\", &r->out.result));");
        }
 
-       pidl "return NT_STATUS_OK;";
-       deindent;
-       pidl "}\n";
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}\n");
 }
 
-
 #################################
 # generate a ejs mapping function
-sub EjsFunction($$)
+sub EjsFunction($$$)
 {
-       my $d = shift;
-       my $iface = shift;
+       my ($self, $d, $iface) = @_;
        my $name = $d->{NAME};
-       my $callnum = uc("DCERPC_$name");
-       my $table = "&dcerpc_table_$iface";
+       my $callnum = uc("NDR_$name");
+       my $table = "&ndr_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";
+       $self->pidl("static int ejs_$name(int eid, int argc, struct MprVar **argv)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);");
+       $self->deindent;
+       $self->pidl("}\n");
 }
 
 ###################
 # handle a constant
-sub EjsConst($)
+sub EjsConst($$)
+{
+    my ($self, $const) = @_;
+    $self->{constants}->{$const->{NAME}} = $const->{VALUE};
+}
+
+sub EjsImport
 {
-    my $const = shift;
-    $constants{$const->{NAME}} = $const->{VALUE};
+       my $self = shift;
+       my @imports = @_;
+       foreach (@imports) {
+               s/\.idl\"$//;
+               s/^\"//;
+               $self->pidl_hdr("#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n");
+       }
 }
 
 #####################################################################
 # parse the interface definitions
-sub EjsInterface($$)
+sub EjsInterface($$$)
 {
-       my($interface,$needed) = @_;
+       my($self,$interface,$needed) = @_;
        my @fns = ();
        my $name = $interface->{NAME};
 
-       %constants = ();
+       $self->pidl_hdr("#ifndef _HEADER_EJS_$interface->{NAME}\n");
+       $self->pidl_hdr("#define _HEADER_EJS_$interface->{NAME}\n\n");
+
+       $self->pidl_hdr("\n");
 
-       foreach my $d (@{$interface->{TYPEDEFS}}) {
-               ($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
-               ($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
+       foreach my $d (@{$interface->{TYPES}}) {
+               next unless (typeHasBody($d));
+               ($needed->{TypeFunctionName("ejs_push", $d)}) && $self->EjsTypePushFunction($d, $d->{NAME});
+               ($needed->{TypeFunctionName("ejs_pull", $d)}) && $self->EjsTypePullFunction($d, $d->{NAME});
        }
 
        foreach my $d (@{$interface->{FUNCTIONS}}) {
                next if not defined($d->{OPNUM});
-               next if Parse::Pidl::Util::has_property($d, "noejs");
+               next if has_property($d, "noejs");
 
-               EjsPullFunction($d);
-               EjsPushFunction($d);
-               EjsFunction($d, $name);
+               $self->EjsPullFunction($d);
+               $self->EjsPushFunction($d);
+               $self->EjsFunction($d, $name);
 
                push (@fns, $d->{NAME});
        }
 
        foreach my $d (@{$interface->{CONSTS}}) {
-               EjsConst($d);
+               $self->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);";
+       $self->pidl("static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);");
        foreach (@fns) {
-               pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
+               $self->pidl("mprSetCFunction(obj, \"$_\", ejs_$_);");
        }
-       foreach my $v (keys %constants) {
-               my $value = $constants{$v};
+       foreach my $v (keys %{$self->{constants}}) {
+               my $value = $self->{constants}->{$v};
                if (substr($value, 0, 1) eq "\"") {
-                       pidl "mprSetVar(obj, \"$v\", mprString($value));";
+                       $self->pidl("mprSetVar(obj, \"$v\", mprString($value));");
                } else {
-                       pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
+                       $self->pidl("mprSetVar(obj, \"$v\", mprCreateNumberVar($value));");
                }
        }
-       pidl "return ejs_rpc_init(obj, \"$name\");";
-       deindent;
-       pidl "}\n";
+       $self->pidl("return ejs_rpc_init(obj, \"$name\");");
+       $self->deindent;
+       $self->pidl("}\n");
 
-       pidl "NTSTATUS ejs_init_$name(void)";
-       pidl "{";
-       indent;
-       pidl "return smbcalls_register_ejs(\"$name\_init\", ejs_$name\_init);";
-       deindent;
-       pidl "}";
+       $self->pidl("NTSTATUS ejs_init_$name(void)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}");
+
+       $self->pidl_hdr("\n");
+       $self->pidl_hdr("#endif /* _HEADER_EJS_$interface->{NAME} */\n");
 }
 
 #####################################################################
 # parse a parsed IDL into a C header
-sub Parse($$)
+sub Parse($$$)
 {
-    my($ndr,$hdr) = @_;
+    my($self,$ndr,$hdr) = @_;
     
     my $ejs_hdr = $hdr;
     $ejs_hdr =~ s/.h$/_ejs.h/;
-    $res = "";
-    pidl "
+
+    $self->pidl_hdr("/* header auto-generated by pidl */\n\n");
+       
+    $self->pidl("
 /* EJS wrapper functions auto-generated by pidl */
 #include \"includes.h\"
+#include \"librpc/rpc/dcerpc.h\"
 #include \"lib/appweb/ejs/ejs.h\"
 #include \"scripting/ejs/ejsrpc.h\"
 #include \"scripting/ejs/smbcalls.h\"
@@ -772,7 +785,7 @@ sub Parse($$)
 #include \"$hdr\"
 #include \"$ejs_hdr\"
 
-";
+");
 
     my %needed = ();
 
@@ -780,46 +793,50 @@ sub Parse($$)
            ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
     }
 
-    foreach my $x (@{$ndr}) {
-           ($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
+    foreach my $x (@$ndr) {
+           ($x->{TYPE} eq "INTERFACE") && $self->EjsInterface($x, \%needed);
+               ($x->{TYPE} eq "IMPORT") && $self->EjsImport(@{$x->{PATHS}});
     }
 
-    return $res;
+    return ($self->{res_hdr}, $self->{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;
+
+       $needed->{"ejs_pull_$fn->{NAME}"} = 1;
+       $needed->{"ejs_push_$fn->{NAME}"} = 1;
+        
+       foreach (@{$fn->{ELEMENTS}}) {
+               next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
+               if (grep(/in/, @{$_->{DIRECTION}})) {
+                       $needed->{TypeFunctionName("ejs_pull", $_->{TYPE})} = 1;
                }
-               if (grep (/out/, @{$e->{DIRECTION}})) {
-                       $needed->{"push_$e->{TYPE}"} = 1;
+               if (grep(/out/, @{$_->{DIRECTION}})) {
+                       $needed->{TypeFunctionName("ejs_push", $_->{TYPE})} = 1;
                }
        }
 }
 
-sub NeededTypedef($$)
+sub NeededType($$$)
 {
-       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;
+       sub NeededType($$$);
+       my ($t,$needed,$req) = @_;
+
+       NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
+
+       return unless (($t->{TYPE} eq "STRUCT") or ($t->{TYPE} eq "UNION"));
+
+       return unless(typeHasBody($t));
+
+       foreach (@{$t->{ELEMENTS}}) {
+               next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
+               my $n;
+               if (ref($_->{TYPE}) ne "HASH" or defined($_->{TYPE}->{NAME})) {
+                       $needed->{TypeFunctionName("ejs_$req", $_->{TYPE})} = 1;
                }
+               NeededType($_->{TYPE}, $needed, $req) if (ref($_->{TYPE}) eq "HASH");
        }
 }
 
@@ -828,12 +845,30 @@ sub NeededTypedef($$)
 sub NeededInterface($$)
 {
        my ($interface,$needed) = @_;
-       foreach my $d (@{$interface->{FUNCTIONS}}) {
-           NeededFunction($d, $needed);
-       }
-       foreach my $d (reverse @{$interface->{TYPEDEFS}}) {
-           NeededTypedef($d, $needed);
+
+       NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
+
+       foreach (reverse @{$interface->{TYPES}}) {
+               if (has_property($_, "public")) {
+                       $needed->{TypeFunctionName("ejs_pull", $_)} = not has_property($_, "noejs");
+                       $needed->{TypeFunctionName("ejs_push", $_)} = not has_property($_, "noejs");
+               }
+
+               NeededType($_, $needed, "pull")  if ($needed->{TypeFunctionName("ejs_pull", $_)});
+               NeededType($_, $needed, "push")  if ($needed->{TypeFunctionName("ejs_push", $_)});
        }
 }
 
+sub TypeFunctionName($$)
+{
+       my ($prefix, $t) = @_;
+
+       return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and 
+                       $t->{TYPE} eq "TYPEDEF");
+       return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH");
+       return "$prefix\_$t";
+}
+
+
+
 1;