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
12 $res_hdr fn_declare TypeFunctionName);
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);
429 pidl "NDR_CHECK(".TypeFunctionName("ejs_push", $e->{TYPE})."(ejs, v, $name, $var));";
433 ###########################
434 # push a string element
435 sub EjsPushString($$$$$)
437 my ($e, $l, $var, $name, $env) = @_;
438 my $pl = GetPrevLevel($e, $l);
439 if (defined($pl) and $pl->{TYPE} eq "POINTER") {
440 $var = get_pointer_to($var);
442 pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
445 ###########################
446 # push a pointer element
447 sub EjsPushPointer($$$$$)
449 my ($e, $l, $var, $name, $env) = @_;
450 pidl "if (NULL == $var) {";
452 if ($l->{POINTER_TYPE} eq "ref") {
453 pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
455 pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
460 $var = get_value_of($var);
461 EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
466 ###########################
467 # push a switch element
468 sub EjsPushSwitch($$$$$)
470 my ($e, $l, $var, $name, $env) = @_;
471 my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
472 pidl "ejs_set_switch(ejs, $switch_var);";
473 EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
476 ###########################
477 # push an array element
478 sub EjsPushArray($$$$$)
480 my ($e, $l, $var, $name, $env) = @_;
481 my $nl = GetNextLevel($e, $l);
482 my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
483 my $pl = GetPrevLevel($e, $l);
484 if ($pl && $pl->{TYPE} eq "POINTER") {
485 $var = get_pointer_to($var);
487 # uint8 arrays are treated as data blobs
488 if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
489 check_null_pointer($length);
490 pidl "ejs_push_array_uint8(ejs, v, $name, $var, $length);";
493 my $avar = $var . "[i]";
497 pidl "for (i=0;i<$length;i++) {";
499 pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
500 EjsPushElement($e, $nl, $avar, "id", $env);
503 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
508 ################################
509 # push a structure/union element
510 sub EjsPushElement($$$$$)
512 my ($e, $l, $var, $name, $env) = @_;
513 if (($l->{TYPE} eq "POINTER")) {
514 EjsPushPointer($e, $l, $var, $name, $env);
515 } elsif (has_property($e, "charset")) {
516 EjsPushString($e, $l, $var, $name, $env);
517 } elsif ($l->{TYPE} eq "ARRAY") {
518 EjsPushArray($e, $l, $var, $name, $env);
519 } elsif ($l->{TYPE} eq "DATA") {
520 EjsPushScalar($e, $l, $var, $name, $env);
521 } elsif (($l->{TYPE} eq "SWITCH")) {
522 EjsPushSwitch($e, $l, $var, $name, $env);
524 pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
528 #############################################
529 # push a structure/union element at top level
530 sub EjsPushElementTop($$)
533 my $l = $e->{LEVELS}[0];
534 my $var = ParseExpr($e->{NAME}, $env, $e);
535 my $name = "\"$e->{NAME}\"";
536 EjsPushElement($e, $l, $var, $name, $env);
539 ###########################
541 sub EjsStructPush($$)
543 my ($d, $varname) = @_;
544 my $env = GenerateStructEnv($d, $varname);
545 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
546 foreach my $e (@{$d->{ELEMENTS}}) {
547 EjsPushElementTop($e, $env);
551 ###########################
555 my ($d, $varname) = @_;
556 my $have_default = 0;
557 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
558 pidl "switch (ejs->switch_var) {";
560 foreach my $e (@{$d->{ELEMENTS}}) {
561 if ($e->{CASE} eq "default") {
566 if ($e->{TYPE} ne "EMPTY") {
567 EjsPushElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"} );
572 if (! $have_default) {
575 pidl "return ejs_panic(ejs, \"Bad switch value\");";
582 ###########################
586 my ($d, $varname) = @_;
588 pidl "unsigned e = ".get_value_of($varname).";";
589 pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
592 ###########################
594 sub EjsBitmapPush($$)
596 my ($d, $varname) = @_;
597 my $type_fn = $d->{BASE_TYPE};
598 # put the bitmap elements in the constants array
599 foreach my $e (@{$d->{ELEMENTS}}) {
600 if ($e =~ /^(\w*)\s*(.*)\s*$/) {
603 $constants{$bname} = $v;
606 pidl "NDR_CHECK(ejs_push_$type_fn(ejs, v, name, $varname));";
609 sub EjsTypePushFunction($$)
611 sub EjsTypePushFunction($$);
613 return if (has_property($d, "noejs"));
617 if ($dt->{TYPE} eq "TYPEDEF") {
620 if ($dt->{TYPE} eq "STRUCT") {
621 $var = "const struct $name *r";
622 } elsif ($dt->{TYPE} eq "UNION") {
623 $var = "const union $name *r";
624 } elsif ($dt->{TYPE} eq "ENUM") {
625 $var = "const enum $name *r";
626 } elsif ($dt->{TYPE} eq "BITMAP") {
627 my($type_decl) = Parse::Pidl::Typelist::mapTypeName($dt->{BASE_TYPE});
628 $var = "const $type_decl *r";
630 fn_declare($d, "NTSTATUS ".TypeFunctionName("ejs_push", $d) . "(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $var)");
633 EjsTypePush($d, "r");
634 pidl "return NT_STATUS_OK;";
642 my ($d, $varname) = @_;
644 if ($d->{TYPE} eq 'STRUCT') {
645 EjsStructPush($d, $varname);
646 } elsif ($d->{TYPE} eq 'UNION') {
647 EjsUnionPush($d, $varname);
648 } elsif ($d->{TYPE} eq 'ENUM') {
649 EjsEnumPush($d, $varname);
650 } elsif ($d->{TYPE} eq 'BITMAP') {
651 EjsBitmapPush($d, $varname);
652 } elsif ($d->{TYPE} eq 'TYPEDEF') {
653 EjsTypePush($d->{DATA}, $varname);
655 warn "Unhandled push $varname of type $d->{TYPE}";
659 #####################
660 # generate a function
661 sub EjsPushFunction($)
664 my $env = GenerateFunctionOutEnv($d);
666 pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
669 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
671 foreach my $e (@{$d->{ELEMENTS}}) {
672 next unless (grep(/out/, @{$e->{DIRECTION}}));
673 EjsPushElementTop($e, $env);
676 if ($d->{RETURN_TYPE}) {
677 pidl "NDR_CHECK(".TypeFunctionName("ejs_push", $d->{RETURN_TYPE})."(ejs, v, \"result\", &r->out.result));";
680 pidl "return NT_STATUS_OK;";
685 #################################
686 # generate a ejs mapping function
689 my ($d, $iface) = @_;
690 my $name = $d->{NAME};
691 my $callnum = uc("DCERPC_$name");
692 my $table = "&dcerpc_table_$iface";
694 pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
697 pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
707 $constants{$const->{NAME}} = $const->{VALUE};
716 pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
720 #####################################################################
721 # parse the interface definitions
724 my($interface,$needed) = @_;
726 my $name = $interface->{NAME};
730 pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
731 pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
735 foreach my $d (@{$interface->{TYPES}}) {
736 ($needed->{TypeFunctionName("ejs_push", $d)}) && EjsTypePushFunction($d, $d->{NAME});
737 ($needed->{TypeFunctionName("ejs_pull", $d)}) && EjsTypePullFunction($d, $d->{NAME});
740 foreach my $d (@{$interface->{FUNCTIONS}}) {
741 next if not defined($d->{OPNUM});
742 next if has_property($d, "noejs");
746 EjsFunction($d, $name);
748 push (@fns, $d->{NAME});
751 foreach my $d (@{$interface->{CONSTS}}) {
755 pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
758 pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
760 pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
762 foreach my $v (keys %constants) {
763 my $value = $constants{$v};
764 if (substr($value, 0, 1) eq "\"") {
765 pidl "mprSetVar(obj, \"$v\", mprString($value));";
767 pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
770 pidl "return ejs_rpc_init(obj, \"$name\");";
774 pidl "NTSTATUS ejs_init_$name(void)";
777 pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
778 pidl "return NT_STATUS_OK;";
783 pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
786 #####################################################################
787 # parse a parsed IDL into a C header
793 $ejs_hdr =~ s/.h$/_ejs.h/;
797 pidl_hdr "/* header auto-generated by pidl */\n\n";
800 /* EJS wrapper functions auto-generated by pidl */
801 #include \"includes.h\"
802 #include \"librpc/rpc/dcerpc.h\"
803 #include \"lib/appweb/ejs/ejs.h\"
804 #include \"scripting/ejs/ejsrpc.h\"
805 #include \"scripting/ejs/smbcalls.h\"
806 #include \"librpc/gen_ndr/ndr_misc_ejs.h\"
808 #include \"$ejs_hdr\"
814 foreach my $x (@{$ndr}) {
815 ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
818 foreach my $x (@$ndr) {
819 ($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
820 ($x->{TYPE} eq "IMPORT") && EjsImport(@{$x->{PATHS}});
823 return ($res_hdr, $res);
826 sub NeededFunction($$)
828 my ($fn,$needed) = @_;
830 $needed->{"ejs_pull_$fn->{NAME}"} = 1;
831 $needed->{"ejs_push_$fn->{NAME}"} = 1;
833 foreach (@{$fn->{ELEMENTS}}) {
834 next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
835 if (grep(/in/, @{$_->{DIRECTION}})) {
836 $needed->{TypeFunctionName("ejs_pull", $_->{TYPE})} = 1;
838 if (grep(/out/, @{$_->{DIRECTION}})) {
839 $needed->{TypeFunctionName("ejs_push", $_->{TYPE})} = 1;
847 my ($t,$needed,$req) = @_;
849 NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
851 return if (($t->{TYPE} ne "STRUCT") and
852 ($t->{TYPE} ne "UNION"));
854 foreach (@{$t->{ELEMENTS}}) {
855 next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
857 if (ref($_->{TYPE}) ne "HASH" or defined($_->{TYPE}->{NAME})) {
858 $needed->{TypeFunctionName("ejs_$req", $_->{TYPE})} = 1;
860 NeededType($_->{TYPE}, $needed, $req) if (ref($_->{TYPE}) eq "HASH");
864 #####################################################################
865 # work out what parse functions are needed
866 sub NeededInterface($$)
868 my ($interface,$needed) = @_;
870 NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
872 foreach (reverse @{$interface->{TYPES}}) {
873 if (has_property($_, "public")) {
874 $needed->{TypeFunctionName("ejs_pull", $_)} = not has_property($_, "noejs");
875 $needed->{TypeFunctionName("ejs_push", $_)} = not has_property($_, "noejs");
878 NeededType($_, $needed, "pull") if ($needed->{TypeFunctionName("ejs_pull", $_)});
879 NeededType($_, $needed, "push") if ($needed->{TypeFunctionName("ejs_push", $_)});
883 sub TypeFunctionName($$)
885 my ($prefix, $t) = @_;
887 return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and
888 ($t->{TYPE} eq "TYPEDEF" or $t->{TYPE} eq "DECLARE"));
889 return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH");
890 return "$prefix\_$t";