r21584: Support for tagged types has landed!
[Samba/ekacnet.git] / source4 / pidl / lib / Parse / Pidl / Samba4 / EJS.pm
blob054074297bc51fb680ed8d7aa6e163a5a05177a5
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;
9 use Exporter;
10 @ISA = qw(Exporter);
11 @EXPORT_OK = qw(get_pointer_to get_value_of check_null_pointer $res
12 $res_hdr fn_declare TypeFunctionName);
14 use strict;
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);
22 $VERSION = '0.01';
24 our $res;
25 our $res_hdr;
27 my %constants;
29 my $tabs = "";
31 sub pidl_hdr ($)
33 $res_hdr .= shift;
36 sub pidl($)
38 my $d = shift;
39 if ($d) {
40 $res .= $tabs;
41 $res .= $d;
43 $res .= "\n";
46 sub indent()
48 $tabs .= "\t";
51 sub deindent()
53 $tabs = substr($tabs, 0, -1);
56 sub get_pointer_to($)
58 my $var_name = shift;
60 if ($var_name =~ /^\*(.*)$/) {
61 return $1;
62 } elsif ($var_name =~ /^\&(.*)$/) {
63 return "&($var_name)";
64 } else {
65 return "&$var_name";
69 sub get_value_of($)
71 my $var_name = shift;
73 if ($var_name =~ /^\&(.*)$/) {
74 return $1;
75 } else {
76 return "*$var_name";
80 #####################################################################
81 # check that a variable we get from ParseExpr isn't a null pointer
82 sub check_null_pointer($)
84 my $size = shift;
85 if ($size =~ /^\*/) {
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
93 sub fn_declare($$)
95 my ($fn,$decl) = @_;
97 if (has_property($fn, "public")) {
98 pidl_hdr "$decl;\n";
99 pidl "_PUBLIC_ $decl";
100 } else {
101 pidl "static $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);
115 } else {
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);
124 my $t;
125 if (ref($e->{TYPE}) eq "HASH") {
126 $t = "$e->{TYPE}->{TYPE}_$e->{TYPE}->{NAME}";
127 } else {
128 $t = $e->{TYPE};
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)) {";
140 indent;
141 if ($l->{POINTER_TYPE} eq "ref") {
142 pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
143 } else {
144 pidl "$var = NULL;";
146 deindent;
147 pidl "} else {";
148 indent;
149 pidl "EJS_ALLOC(ejs, $var);";
150 $var = get_value_of($var);
151 EjsPullElement($e, GetNextLevel($e, $l), $var, $name, $env);
152 deindent;
153 pidl "}";
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);";
189 return;
191 my $avar = $var . "[i]";
192 pidl "{";
193 indent;
194 pidl "uint32_t i;";
195 if (!$l->{IS_FIXED}) {
196 pidl "EJS_ALLOC_N(ejs, $var, $size);";
198 pidl "for (i=0;i<$length;i++) {";
199 indent;
200 pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
201 EjsPullElement($e, $nl, $avar, "id", $env);
202 pidl "talloc_free(id);";
203 deindent;
204 pidl "}";
205 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
206 deindent;
207 pidl "}";
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);
235 } else {
236 pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
240 #############################################
241 # pull a structure/union element at top level
242 sub EjsPullElementTop($$)
244 my ($e, $env) = @_;
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 ###########################
252 # pull a struct
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 ###########################
264 # pull a union
265 sub EjsUnionPull($$)
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) {";
271 indent;
272 foreach my $e (@{$d->{ELEMENTS}}) {
273 if ($e->{CASE} eq "default") {
274 $have_default = 1;
276 pidl "$e->{CASE}:";
277 indent;
278 if ($e->{TYPE} ne "EMPTY") {
279 EjsPullElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"});
281 pidl "break;";
282 deindent;
284 if (! $have_default) {
285 pidl "default:";
286 indent;
287 pidl "return ejs_panic(ejs, \"Bad switch value\");";
288 deindent;
290 deindent;
291 pidl "}";
294 ##############################################
295 # put the enum elements in the constants array
296 sub EjsEnumConstant($)
298 my $d = shift;
299 my $v = 0;
300 foreach my $e (@{$d->{ELEMENTS}}) {
301 my $el = $e;
302 chomp $el;
303 if ($el =~ /^(.*)=\s*(.*)\s*$/) {
304 $el = $1;
305 $v = $2;
307 $constants{$el} = $v;
308 $v++;
312 ###########################
313 # pull a enum
314 sub EjsEnumPull($$)
316 my ($d, $varname) = @_;
317 EjsEnumConstant($d);
318 pidl "unsigned e;";
319 pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
320 pidl "*$varname = e;";
323 ###########################
324 # pull a bitmap
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($$);
335 my ($d, $name) = @_;
336 return if (has_property($d, "noejs"));
338 if ($d->{TYPE} eq "TYPEDEF") {
339 EjsTypePullFunction($d->{DATA}, $name);
340 return;
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)");
353 pidl "{";
354 indent;
356 EjsTypePull($d, "r");
358 pidl "return NT_STATUS_OK;";
359 deindent;
360 pidl "}\n";
363 sub EjsTypePull($$)
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);
374 } else {
375 warn "Unhandled pull $varname of type $d->{TYPE}";
379 #####################
380 # generate a function
381 sub EjsPullFunction($)
383 my $d = shift;
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)";
388 pidl "{";
389 indent;
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;";
408 deindent;
409 pidl "}\n";
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));
420 } else {
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) {";
451 indent;
452 if ($l->{POINTER_TYPE} eq "ref") {
453 pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
454 } else {
455 pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
457 deindent;
458 pidl "} else {";
459 indent;
460 $var = get_value_of($var);
461 EjsPushElement($e, GetNextLevel($e, $l), $var, $name, $env);
462 deindent;
463 pidl "}";
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);";
491 return;
493 my $avar = $var . "[i]";
494 pidl "{";
495 indent;
496 pidl "uint32_t i;";
497 pidl "for (i=0;i<$length;i++) {";
498 indent;
499 pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
500 EjsPushElement($e, $nl, $avar, "id", $env);
501 deindent;
502 pidl "}";
503 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
504 deindent;
505 pidl "}";
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);
523 } else {
524 pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
528 #############################################
529 # push a structure/union element at top level
530 sub EjsPushElementTop($$)
532 my ($e, $env) = @_;
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 ###########################
540 # push a struct
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 ###########################
552 # push a union
553 sub EjsUnionPush($$)
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) {";
559 indent;
560 foreach my $e (@{$d->{ELEMENTS}}) {
561 if ($e->{CASE} eq "default") {
562 $have_default = 1;
564 pidl "$e->{CASE}:";
565 indent;
566 if ($e->{TYPE} ne "EMPTY") {
567 EjsPushElementTop($e, { $e->{NAME} => "$varname->$e->{NAME}"} );
569 pidl "break;";
570 deindent;
572 if (! $have_default) {
573 pidl "default:";
574 indent;
575 pidl "return ejs_panic(ejs, \"Bad switch value\");";
576 deindent;
578 deindent;
579 pidl "}";
582 ###########################
583 # push a enum
584 sub EjsEnumPush($$)
586 my ($d, $varname) = @_;
587 EjsEnumConstant($d);
588 pidl "unsigned e = ".get_value_of($varname).";";
589 pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
592 ###########################
593 # push a bitmap
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*$/) {
601 my $bname = $1;
602 my $v = $2;
603 $constants{$bname} = $v;
606 pidl "NDR_CHECK(ejs_push_$type_fn(ejs, v, name, $varname));";
609 sub EjsTypePushFunction($$)
611 sub EjsTypePushFunction($$);
612 my ($d, $name) = @_;
613 return if (has_property($d, "noejs"));
615 my $var = undef;
616 my $dt = $d;
617 if ($dt->{TYPE} eq "TYPEDEF") {
618 $dt = $dt->{DATA};
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)");
631 pidl "{";
632 indent;
633 EjsTypePush($d, "r");
634 pidl "return NT_STATUS_OK;";
635 deindent;
636 pidl "}\n";
639 sub EjsTypePush($$)
641 sub EjsTypePush($$);
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);
654 } else {
655 warn "Unhandled push $varname of type $d->{TYPE}";
659 #####################
660 # generate a function
661 sub EjsPushFunction($)
663 my $d = shift;
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)";
667 pidl "{";
668 indent;
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;";
681 deindent;
682 pidl "}\n";
685 #################################
686 # generate a ejs mapping function
687 sub EjsFunction($$)
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)";
695 pidl "{";
696 indent;
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);";
698 deindent;
699 pidl "}\n";
702 ###################
703 # handle a constant
704 sub EjsConst($)
706 my $const = shift;
707 $constants{$const->{NAME}} = $const->{VALUE};
710 sub EjsImport
712 my @imports = @_;
713 foreach (@imports) {
714 s/\.idl\"$//;
715 s/^\"//;
716 pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
720 #####################################################################
721 # parse the interface definitions
722 sub EjsInterface($$)
724 my($interface,$needed) = @_;
725 my @fns = ();
726 my $name = $interface->{NAME};
728 %constants = ();
730 pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
731 pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
733 pidl_hdr "\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");
744 EjsPullFunction($d);
745 EjsPushFunction($d);
746 EjsFunction($d, $name);
748 push (@fns, $d->{NAME});
751 foreach my $d (@{$interface->{CONSTS}}) {
752 EjsConst($d);
755 pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
756 pidl "{";
757 indent;
758 pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
759 foreach (@fns) {
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));";
766 } else {
767 pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
770 pidl "return ejs_rpc_init(obj, \"$name\");";
771 deindent;
772 pidl "}\n";
774 pidl "NTSTATUS ejs_init_$name(void)";
775 pidl "{";
776 indent;
777 pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
778 pidl "return NT_STATUS_OK;";
779 deindent;
780 pidl "}";
782 pidl_hdr "\n";
783 pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
786 #####################################################################
787 # parse a parsed IDL into a C header
788 sub Parse($$)
790 my($ndr,$hdr) = @_;
792 my $ejs_hdr = $hdr;
793 $ejs_hdr =~ s/.h$/_ejs.h/;
794 $res = "";
795 $res_hdr = "";
797 pidl_hdr "/* header auto-generated by pidl */\n\n";
799 pidl "
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\"
807 #include \"$hdr\"
808 #include \"$ejs_hdr\"
812 my %needed = ();
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;
844 sub NeededType($$$)
846 sub NeededType($$$);
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
856 my $n;
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";