1 ###################################################
2 # EJS function wrapper generator
3 # Copyright jelmer@samba.org 2005
4 # Copyright Andrew Tridgell 2005
5 # released under the GNU GPL
7 package Parse
::Pidl
::Samba4
::EJS
;
11 @EXPORT_OK = qw(get_pointer_to get_value_of check_null_pointer $res
15 use Parse::Pidl::Typelist;
16 use Parse::Pidl::Util qw(has_property ParseExpr);
17 use Parse
::Pidl
::NDR
qw(GetPrevLevel GetNextLevel);
18 use Parse
::Pidl
::Samba4
::NDR
::Parser
qw(GenerateStructEnv GenerateFunctionInEnv
19 GenerateFunctionOutEnv);
21 use vars
qw($VERSION);
53 $tabs = substr($tabs, 0, -1);
60 if ($var_name =~ /^\*(.*)$/) {
62 } elsif ($var_name =~ /^\&(.*)$/) {
63 return "&($var_name)";
73 if ($var_name =~ /^\&(.*)$/) {
80 #####################################################################
81 # check that a variable we get from ParseExpr isn't a null pointer
82 sub check_null_pointer($)
86 my $size2 = substr($size, 1);
87 pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
91 #####################################################################
92 # work out is a parse function should be declared static or not
97 if (has_property($fn, "public")) {
99 pidl "_PUBLIC_ $decl";
105 ###########################
106 # pull a scalar element
107 sub EjsPullScalar($$$$$)
109 my ($e, $l, $var, $name, $env) = @_;
111 return if (has_property($e, "value"));
113 if (ref($e->{TYPE}) eq "HASH" and not defined($e->{TYPE}->{NAME})) {
114 EjsTypePull($e->{TYPE}, $var);
116 my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
117 $var = get_pointer_to($var);
118 # have to handle strings specially :(
119 if (Parse::Pidl::Typelist::scalar_is_reference($e->{TYPE})
120 and (defined($pl) and $pl->{TYPE} eq "POINTER")) {
121 $var = get_pointer_to($var);
125 if (ref($e->{TYPE}) eq "HASH") {
126 $t = "$e->{TYPE}->{TYPE}_$e->{TYPE}->{NAME}";
130 pidl "NDR_CHECK(ejs_pull_$t(ejs, v, $name, $var));";
134 ###########################
135 # pull a pointer element
136 sub EjsPullPointer($$$$$)
138 my ($e, $l, $var, $name, $env) = @_;
139 pidl "if (ejs_pull_null(ejs, v, $name)) {";
141 if ($l->{POINTER_TYPE} eq "ref") {
142 pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
149 pidl "EJS_ALLOC(ejs, $var);";
150 $var = get_value_of($var);
151 EjsPullElement($e, GetNextLevel($e, $l), $var, $name, $env);
156 ###########################
157 # pull a string element
158 sub EjsPullString($$$$$)
160 my ($e, $l, $var, $name, $env) = @_;
161 my $pl = GetPrevLevel($e, $l);
162 $var = get_pointer_to($var);
163 if (defined($pl) and $pl->{TYPE} eq "POINTER") {
164 $var = get_pointer_to($var);
166 pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
169 ###########################
170 # pull an array element
171 sub EjsPullArray($$$$$)
173 my ($e, $l, $var, $name, $env) = @_;
174 my $nl = GetNextLevel($e, $l);
175 my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
176 my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
177 my $pl = GetPrevLevel($e, $l);
178 if ($pl && $pl->{TYPE} eq "POINTER") {
179 $var = get_pointer_to($var);
181 # uint8 arrays are treated as data blobs
182 if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
183 if (!$l->{IS_FIXED}) {
184 check_null_pointer($size);
185 pidl "EJS_ALLOC_N(ejs, $var, $size);";
187 check_null_pointer($length);
188 pidl "ejs_pull_array_uint8(ejs, v, $name, $var, $length);";
191 my $avar = $var . "[i]";
195 if (!$l->{IS_FIXED}) {
196 pidl "EJS_ALLOC_N(ejs, $var, $size);";
198 pidl "for (i=0;i<$length;i++) {";
200 pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
201 EjsPullElement($e, $nl, $avar, "id", $env);
202 pidl "talloc_free(id);";
205 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
210 ###########################
211 # pull a switch element
212 sub EjsPullSwitch($$$$$)
214 my ($e, $l, $var, $name, $env) = @_;
215 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
216 pidl "ejs_set_switch(ejs, $switch_var);";
217 EjsPullElement($e, GetNextLevel($e, $l), $var, $name, $env);
220 ###########################
221 # pull a structure element
222 sub EjsPullElement($$$$$)
224 my ($e, $l, $var, $name, $env) = @_;
225 if (($l->{TYPE} eq "POINTER")) {
226 EjsPullPointer($e, $l, $var, $name, $env);
227 } elsif (has_property($e, "charset")) {
228 EjsPullString($e, $l, $var, $name, $env);
229 } elsif ($l->{TYPE} eq "ARRAY") {
230 EjsPullArray($e, $l, $var, $name, $env);
231 } elsif ($l->{TYPE} eq "DATA") {
232 EjsPullScalar($e, $l, $var, $name, $env);
233 } elsif (($l->{TYPE} eq "SWITCH")) {
234 EjsPullSwitch($e, $l, $var, $name, $env);
236 pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
240 #############################################
241 # pull a structure/union element at top level
242 sub EjsPullElementTop($$)
245 my $l = $e->{LEVELS}[0];
246 my $var = ParseExpr($e->{NAME}, $env, $e);
247 my $name = "\"$e->{NAME}\"";
248 EjsPullElement($e, $l, $var, $name, $env);
251 ###########################
253 sub EjsStructPull($$)
255 my ($d, $varname) = @_;
256 my $env = GenerateStructEnv($d, $varname);
257 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
258 foreach my $e (@{$d->{ELEMENTS}}) {
259 EjsPullElementTop($e, $env);
263 ###########################
267 my ($d, $varname) = @_;
268 my $have_default = 0;
269 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
270 pidl "switch (ejs->switch_var) {";
272 foreach my $e (@{$d->{ELEMENTS}}) {
273 if ($e->{CASE} eq "default") {
278 if ($e->{TYPE} ne "EMPTY") {
279 EjsPullElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"});
284 if (! $have_default) {
287 pidl "return ejs_panic(ejs, \"Bad switch value\");";
294 ##############################################
295 # put the enum elements in the constants array
296 sub EjsEnumConstant($)
300 foreach my $e (@{$d->{ELEMENTS}}) {
303 if ($el =~ /^(.*)=\s*(.*)\s*$/) {
307 $constants{$el} = $v;
312 ###########################
316 my ($d, $varname) = @_;
319 pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
320 pidl "*$varname = e;";
323 ###########################
325 sub EjsBitmapPull($$)
327 my ($d, $varname) = @_;
328 my $type_fn = $d->{BASE_TYPE};
329 pidl "NDR_CHECK(ejs_pull_$type_fn(ejs, v, name, $varname));";
332 sub EjsTypePullFunction($$)
334 sub EjsTypePullFunction($$);
336 return if (has_property($d, "noejs"));
338 if ($d->{TYPE} eq "TYPEDEF") {
339 EjsTypePullFunction($d->{DATA}, $name);
343 if ($d->{TYPE} eq "STRUCT") {
344 fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)");
345 } elsif ($d->{TYPE} eq "UNION") {
346 fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)");
347 } elsif ($d->{TYPE} eq "ENUM") {
348 fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)");
349 } elsif ($d->{TYPE} eq "BITMAP") {
350 my($type_decl) = Parse::Pidl::Typelist::mapTypeName($d->{BASE_TYPE});
351 fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)");
356 EjsTypePull($d, "r");
358 pidl "return NT_STATUS_OK;";
365 my ($d, $varname) = @_;
366 if ($d->{TYPE} eq 'STRUCT') {
367 EjsStructPull($d, $varname);
368 } elsif ($d->{TYPE} eq 'UNION') {
369 EjsUnionPull($d, $varname);
370 } elsif ($d->{TYPE} eq 'ENUM') {
371 EjsEnumPull($d, $varname);
372 } elsif ($d->{TYPE} eq 'BITMAP') {
373 EjsBitmapPull($d, $varname);
375 warn "Unhandled pull $varname of type $d->{TYPE}";
379 #####################
380 # generate a function
381 sub EjsPullFunction($)
384 my $env = GenerateFunctionInEnv($d);
385 my $name = $d->{NAME};
387 pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
390 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
392 # we pull non-array elements before array elements as arrays
393 # may have length_is() or size_is() properties that depend
394 # on the non-array elements
395 foreach my $e (@{$d->{ELEMENTS}}) {
396 next unless (grep(/in/, @{$e->{DIRECTION}}));
397 next if (has_property($e, "length_is") || has_property($e, "size_is"));
398 EjsPullElementTop($e, $env);
401 foreach my $e (@{$d->{ELEMENTS}}) {
402 next unless (grep(/in/, @{$e->{DIRECTION}}));
403 next unless (has_property($e, "length_is") || has_property($e, "size_is"));
404 EjsPullElementTop($e, $env);
407 pidl "return NT_STATUS_OK;";
412 ###########################
413 # push a scalar element
414 sub EjsPushScalar($$$$$)
416 my ($e, $l, $var, $name, $env) = @_;
418 if (ref($e->{TYPE}) eq "HASH" and not defined($e->{TYPE}->{NAME})) {
419 EjsTypePush($e->{TYPE}, get_pointer_to($var));
421 # have to handle strings specially :(
422 my $pl = GetPrevLevel($e, $l);
424 if ((not Parse::Pidl::Typelist::scalar_is_reference($e->{TYPE}))
425 or (defined($pl) and $pl->{TYPE} eq "POINTER")) {
426 $var = get_pointer_to($var);
430 if (ref($e->{TYPE}) eq "HASH") {
431 $t = "$e->{TYPE}->{TYPE}_$e->{TYPE}->{NAME}";
436 pidl "NDR_CHECK(ejs_push_$t(ejs, v, $name, $var));";
440 ###########################
441 # push a string element
442 sub EjsPushString($$$$$)
444 my ($e, $l, $var, $name, $env) = @_;
445 my $pl = GetPrevLevel($e, $l);
446 if (defined($pl) and $pl->{TYPE} eq "POINTER") {
447 $var = get_pointer_to($var);
449 pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
452 ###########################
453 # push a pointer element
454 sub EjsPushPointer($$$$$)
456 my ($e, $l, $var, $name, $env) = @_;
457 pidl "if (NULL == $var) {";
459 if ($l->{POINTER_TYPE} eq "ref") {
460 pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
462 pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
467 $var = get_value_of($var);
468 EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
473 ###########################
474 # push a switch element
475 sub EjsPushSwitch($$$$$)
477 my ($e, $l, $var, $name, $env) = @_;
478 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
479 pidl "ejs_set_switch(ejs, $switch_var);";
480 EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
483 ###########################
484 # push an array element
485 sub EjsPushArray($$$$$)
487 my ($e, $l, $var, $name, $env) = @_;
488 my $nl = GetNextLevel($e, $l);
489 my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
490 my $pl = GetPrevLevel($e, $l);
491 if ($pl && $pl->{TYPE} eq "POINTER") {
492 $var = get_pointer_to($var);
494 # uint8 arrays are treated as data blobs
495 if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
496 check_null_pointer($length);
497 pidl "ejs_push_array_uint8(ejs, v, $name, $var, $length);";
500 my $avar = $var . "[i]";
504 pidl "for (i=0;i<$length;i++) {";
506 pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
507 EjsPushElement($e, $nl, $avar, "id", $env);
510 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
515 ################################
516 # push a structure/union element
517 sub EjsPushElement($$$$$)
519 my ($e, $l, $var, $name, $env) = @_;
520 if (($l->{TYPE} eq "POINTER")) {
521 EjsPushPointer($e, $l, $var, $name, $env);
522 } elsif (has_property($e, "charset")) {
523 EjsPushString($e, $l, $var, $name, $env);
524 } elsif ($l->{TYPE} eq "ARRAY") {
525 EjsPushArray($e, $l, $var, $name, $env);
526 } elsif ($l->{TYPE} eq "DATA") {
527 EjsPushScalar($e, $l, $var, $name, $env);
528 } elsif (($l->{TYPE} eq "SWITCH")) {
529 EjsPushSwitch($e, $l, $var, $name, $env);
531 pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
535 #############################################
536 # push a structure/union element at top level
537 sub EjsPushElementTop($$)
540 my $l = $e->{LEVELS}[0];
541 my $var = ParseExpr($e->{NAME}, $env, $e);
542 my $name = "\"$e->{NAME}\"";
543 EjsPushElement($e, $l, $var, $name, $env);
546 ###########################
548 sub EjsStructPush($$)
550 my ($d, $varname) = @_;
551 my $env = GenerateStructEnv($d, $varname);
552 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
553 foreach my $e (@{$d->{ELEMENTS}}) {
554 EjsPushElementTop($e, $env);
558 ###########################
562 my ($d, $varname) = @_;
563 my $have_default = 0;
564 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
565 pidl "switch (ejs->switch_var) {";
567 foreach my $e (@{$d->{ELEMENTS}}) {
568 if ($e->{CASE} eq "default") {
573 if ($e->{TYPE} ne "EMPTY") {
574 EjsPushElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"} );
579 if (! $have_default) {
582 pidl "return ejs_panic(ejs, \"Bad switch value\");";
589 ###########################
593 my ($d, $varname) = @_;
595 pidl "unsigned e = ".get_value_of($varname).";";
596 pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
599 ###########################
601 sub EjsBitmapPush($$)
603 my ($d, $varname) = @_;
604 my $type_fn = $d->{BASE_TYPE};
605 # put the bitmap elements in the constants array
606 foreach my $e (@{$d->{ELEMENTS}}) {
607 if ($e =~ /^(\w*)\s*(.*)\s*$/) {
610 $constants{$bname} = $v;
613 pidl "NDR_CHECK(ejs_push_$type_fn(ejs, v, name, $varname));";
616 sub EjsTypePushFunction($$)
618 sub EjsTypePushFunction($$);
620 return if (has_property($d, "noejs"));
622 if ($d->{TYPE} eq "TYPEDEF") {
623 EjsTypePushFunction($d->{DATA}, $name);
627 if ($d->{TYPE} eq "STRUCT") {
628 fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)");
629 } elsif ($d->{TYPE} eq "UNION") {
630 fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)");
631 } elsif ($d->{TYPE} eq "ENUM") {
632 fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)");
633 } elsif ($d->{TYPE} eq "BITMAP") {
634 my($type_decl) = Parse::Pidl::Typelist::mapTypeName($d->{BASE_TYPE});
635 fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)");
639 EjsTypePush($d, "r");
640 pidl "return NT_STATUS_OK;";
647 my ($d, $varname) = @_;
649 if ($d->{TYPE} eq 'STRUCT') {
650 EjsStructPush($d, $varname);
651 } elsif ($d->{TYPE} eq 'UNION') {
652 EjsUnionPush($d, $varname);
653 } elsif ($d->{TYPE} eq 'ENUM') {
654 EjsEnumPush($d, $varname);
655 } elsif ($d->{TYPE} eq 'BITMAP') {
656 EjsBitmapPush($d, $varname);
658 warn "Unhandled push $varname of type $d->{TYPE}";
662 #####################
663 # generate a function
664 sub EjsPushFunction($)
667 my $env = GenerateFunctionOutEnv($d);
669 pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
672 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
674 foreach my $e (@{$d->{ELEMENTS}}) {
675 next unless (grep(/out/, @{$e->{DIRECTION}}));
676 EjsPushElementTop($e, $env);
679 if ($d->{RETURN_TYPE}) {
680 my $t = $d->{RETURN_TYPE};
681 pidl "NDR_CHECK(ejs_push_$t(ejs, v, \"result\", &r->out.result));";
684 pidl "return NT_STATUS_OK;";
689 #################################
690 # generate a ejs mapping function
693 my ($d, $iface) = @_;
694 my $name = $d->{NAME};
695 my $callnum = uc("DCERPC_$name");
696 my $table = "&dcerpc_table_$iface";
698 pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
701 pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
711 $constants{$const->{NAME}} = $const->{VALUE};
720 pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
724 #####################################################################
725 # parse the interface definitions
728 my($interface,$needed) = @_;
730 my $name = $interface->{NAME};
734 pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
735 pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
739 foreach my $d (@{$interface->{TYPES}}) {
740 ($needed->{"push_$d->{NAME}"}) && EjsTypePushFunction($d, $d->{NAME});
741 ($needed->{"pull_$d->{NAME}"}) && EjsTypePullFunction($d, $d->{NAME});
744 foreach my $d (@{$interface->{FUNCTIONS}}) {
745 next if not defined($d->{OPNUM});
746 next if has_property($d, "noejs");
750 EjsFunction($d, $name);
752 push (@fns, $d->{NAME});
755 foreach my $d (@{$interface->{CONSTS}}) {
759 pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
762 pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
764 pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
766 foreach my $v (keys %constants) {
767 my $value = $constants{$v};
768 if (substr($value, 0, 1) eq "\"") {
769 pidl "mprSetVar(obj, \"$v\", mprString($value));";
771 pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
774 pidl "return ejs_rpc_init(obj, \"$name\");";
778 pidl "NTSTATUS ejs_init_$name(void)";
781 pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
782 pidl "return NT_STATUS_OK;";
787 pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
790 #####################################################################
791 # parse a parsed IDL into a C header
797 $ejs_hdr =~ s/.h$/_ejs.h/;
801 pidl_hdr "/* header auto-generated by pidl */\n\n";
804 /* EJS wrapper functions auto-generated by pidl */
805 #include \"includes.h\"
806 #include \"librpc/rpc/dcerpc.h\"
807 #include \"lib/appweb/ejs/ejs.h\"
808 #include \"scripting/ejs/ejsrpc.h\"
809 #include \"scripting/ejs/smbcalls.h\"
810 #include \"librpc/gen_ndr/ndr_misc_ejs.h\"
812 #include \"$ejs_hdr\"
818 foreach my $x (@{$ndr}) {
819 ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
822 foreach my $x (@$ndr) {
823 ($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
824 ($x->{TYPE} eq "IMPORT") && EjsImport(@{$x->{PATHS}});
827 return ($res_hdr, $res);
830 sub NeededFunction($$)
832 my ($fn,$needed) = @_;
834 $needed->{"pull_$fn->{NAME}"} = 1;
835 $needed->{"push_$fn->{NAME}"} = 1;
837 foreach (@{$fn->{ELEMENTS}}) {
838 next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
839 if (grep(/in/, @{$_->{DIRECTION}})) {
840 $needed->{"pull_$_->{TYPE}"} = 1;
842 if (grep(/out/, @{$_->{DIRECTION}})) {
843 $needed->{"push_$_->{TYPE}"} = 1;
851 my ($t,$needed,$req) = @_;
853 NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
855 return if (($t->{TYPE} ne "STRUCT") and
856 ($t->{TYPE} ne "UNION"));
858 foreach (@{$t->{ELEMENTS}}) {
859 next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
861 if (ref($_->{TYPE}) eq "HASH" and defined($_->{TYPE}->{NAME})) {
862 $needed->{"$req\_$_->{TYPE}->{TYPE}_$_->{TYPE}->{NAME}"} = 1;
863 } elsif (ref($_->{TYPE}) ne "HASH") {
864 $needed->{$req."_".$_->{TYPE}} = 1;
866 NeededType($_->{TYPE}, $needed, $req) if (ref($_->{TYPE}) eq "HASH");
870 #####################################################################
871 # work out what parse functions are needed
872 sub NeededInterface($$)
874 my ($interface,$needed) = @_;
876 NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
878 foreach (reverse @{$interface->{TYPES}}) {
879 if (has_property($_, "public")) {
880 $needed->{"pull_$_->{NAME}"} = not has_property($_, "noejs");
881 $needed->{"push_$_->{NAME}"} = not has_property($_, "noejs");
884 NeededType($_, $needed, "pull") if ($needed->{"pull_$_->{NAME}"});
885 NeededType($_, $needed, "push") if ($needed->{"push_$_->{NAME}"});