1 ###################################################
2 # EJS function wrapper generator
3 # Copyright jelmer@samba.org 2005
4 # Copyright Andrew Tridgell 2005
5 # released under the GNU GPL
33 $tabs = substr($tabs, 0, -1);
36 # this should probably be in ndr.pm
37 sub GenerateStructEnv($)
42 foreach my $e (@{$x->{ELEMENTS}}) {
44 $env{$e->{NAME}} = "r->$e->{NAME}";
53 sub GenerateFunctionInEnv($)
58 foreach my $e (@{$fn->{ELEMENTS}}) {
59 if (grep (/in/, @{$e->{DIRECTION}})) {
60 $env{$e->{NAME}} = "r->in.$e->{NAME}";
67 sub GenerateFunctionOutEnv($)
72 foreach my $e (@{$fn->{ELEMENTS}}) {
73 if (grep (/out/, @{$e->{DIRECTION}})) {
74 $env{$e->{NAME}} = "r->out.$e->{NAME}";
75 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
76 $env{$e->{NAME}} = "r->in.$e->{NAME}";
87 if ($var_name =~ /^\*(.*)$/) {
89 } elsif ($var_name =~ /^\&(.*)$/) {
90 return "&($var_name)";
100 if ($var_name =~ /^\&(.*)$/) {
107 #####################################################################
108 # work out is a parse function should be declared static or not
113 return "" if (util::has_property($fn, "public"));
117 ###########################
118 # pull a scalar element
119 sub EjsPullScalar($$$$$)
121 my ($e, $l, $var, $name, $env) = @_;
123 return if (util::has_property($e, "value"));
125 $var = get_pointer_to($var);
126 # have to handle strings specially :(
127 if ($e->{TYPE} eq "string") {
128 $var = get_pointer_to($var);
130 pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
133 ###########################
134 # pull a pointer element
135 sub EjsPullPointer($$$$$)
137 my ($e, $l, $var, $name, $env) = @_;
138 pidl "if (ejs_pull_null(ejs, v, $name)) {";
144 pidl "EJS_ALLOC(ejs, $var);";
145 $var = get_value_of($var);
146 EjsPullElement($e, Ndr::GetNextLevel($e, $l), $var, $name, $env);
151 ###########################
152 # pull a string element
153 sub EjsPullString($$$$$)
155 my ($e, $l, $var, $name, $env) = @_;
156 $var = get_pointer_to($var);
157 pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
161 ###########################
162 # pull an arrar element
163 sub EjsPullArray($$$$$)
165 my ($e, $l, $var, $name, $env) = @_;
166 my $length = util::ParseExpr($l->{LENGTH_IS}, $env);
167 my $pl = Ndr::GetPrevLevel($e, $l);
168 if ($pl && $pl->{TYPE} eq "POINTER") {
169 $var = get_pointer_to($var);
171 my $avar = $var . "[i]";
175 if (!$l->{IS_FIXED}) {
176 pidl "EJS_ALLOC_N(ejs, $var, $length);";
178 pidl "for (i=0;i<$length;i++) {";
180 pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
181 EjsPullElement($e, Ndr::GetNextLevel($e, $l), $avar, "id", $env);
182 pidl "talloc_free(id);";
185 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
190 ###########################
191 # pull a switch element
192 sub EjsPullSwitch($$$$$)
194 my ($e, $l, $var, $name, $env) = @_;
195 my $switch_var = util::ParseExpr($l->{SWITCH_IS}, $env);
196 pidl "ejs_set_switch(ejs, $switch_var);";
197 EjsPullElement($e, Ndr::GetNextLevel($e, $l), $var, $name, $env);
200 ###########################
201 # pull a structure element
202 sub EjsPullElement($$$$$)
204 my ($e, $l, $var, $name, $env) = @_;
205 if (util::has_property($e, "charset")) {
206 EjsPullString($e, $l, $var, $name, $env);
207 } elsif ($l->{TYPE} eq "ARRAY") {
208 EjsPullArray($e, $l, $var, $name, $env);
209 } elsif ($l->{TYPE} eq "DATA") {
210 EjsPullScalar($e, $l, $var, $name, $env);
211 } elsif (($l->{TYPE} eq "POINTER")) {
212 EjsPullPointer($e, $l, $var, $name, $env);
213 } elsif (($l->{TYPE} eq "SWITCH")) {
214 EjsPullSwitch($e, $l, $var, $name, $env);
216 pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
220 #############################################
221 # pull a structure/union element at top level
222 sub EjsPullElementTop($$)
226 my $l = $e->{LEVELS}[0];
227 my $var = util::ParseExpr($e->{NAME}, $env);
228 my $name = "\"$e->{NAME}\"";
229 EjsPullElement($e, $l, $var, $name, $env);
232 ###########################
234 sub EjsStructPull($$)
238 my $env = GenerateStructEnv($d);
240 pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)\n{";
242 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
243 foreach my $e (@{$d->{ELEMENTS}}) {
244 EjsPullElementTop($e, $env);
246 pidl "return NT_STATUS_OK;";
251 ###########################
257 my $have_default = 0;
258 my $env = GenerateStructEnv($d);
260 pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)\n{";
262 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
263 pidl "switch (ejs->switch_var) {";
265 foreach my $e (@{$d->{ELEMENTS}}) {
266 if ($e->{CASE} eq "default") {
271 if ($e->{TYPE} ne "EMPTY") {
272 EjsPullElementTop($e, $env);
277 if (! $have_default) {
280 pidl "return ejs_panic(ejs, \"Bad switch value\");";
285 pidl "return NT_STATUS_OK;";
290 ###########################
297 pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)\n{";
300 pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
302 pidl "return NT_STATUS_OK;";
307 ###########################
309 sub EjsBitmapPull($$)
313 my $type_fn = $d->{BASE_TYPE};
314 my($type_decl) = typelist::mapType($d->{BASE_TYPE});
316 pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)\n{";
318 pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
324 ###########################
325 # generate a structure pull
326 sub EjsTypedefPull($)
329 return if (util::has_property($d, "noejs"));
330 if ($d->{DATA}->{TYPE} eq 'STRUCT') {
331 EjsStructPull($d->{NAME}, $d->{DATA});
332 } elsif ($d->{DATA}->{TYPE} eq 'UNION') {
333 EjsUnionPull($d->{NAME}, $d->{DATA});
334 } elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
335 EjsEnumPull($d->{NAME}, $d->{DATA});
336 } elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
337 EjsBitmapPull($d->{NAME}, $d->{DATA});
339 warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
343 #####################
344 # generate a function
345 sub EjsPullFunction($)
348 my $env = GenerateFunctionInEnv($d);
349 my $name = $d->{NAME};
351 pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
354 pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
356 foreach my $e (@{$d->{ELEMENTS}}) {
357 next unless (grep(/in/, @{$e->{DIRECTION}}));
358 EjsPullElementTop($e, $env);
361 pidl "return NT_STATUS_OK;";
367 ###########################
368 # push a scalar element
369 sub EjsPushScalar($$$$$)
371 my ($e, $l, $var, $name, $env) = @_;
372 $var = get_pointer_to($var);
373 pidl "NDR_CHECK(ejs_push_$e->{TYPE}(ejs, v, $name, $var));";
376 ###########################
377 # push a string element
378 sub EjsPushString($$$$$)
380 my ($e, $l, $var, $name, $env) = @_;
381 pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
384 ###########################
385 # push a pointer element
386 sub EjsPushPointer($$$$$)
388 my ($e, $l, $var, $name, $env) = @_;
389 pidl "if (NULL == $var) {";
391 pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
395 $var = get_value_of($var);
396 EjsPushElement($e, Ndr::GetNextLevel($e, $l), $var, $name, $env);
401 ###########################
402 # push a switch element
403 sub EjsPushSwitch($$$$$)
405 my ($e, $l, $var, $name, $env) = @_;
406 my $switch_var = util::ParseExpr($l->{SWITCH_IS}, $env);
407 pidl "ejs_set_switch(ejs, $switch_var);";
408 EjsPushElement($e, Ndr::GetNextLevel($e, $l), $var, $name, $env);
412 ###########################
413 # push an arrar element
414 sub EjsPushArray($$$$$)
416 my ($e, $l, $var, $name, $env) = @_;
417 my $length = util::ParseExpr($l->{LENGTH_IS}, $env);
418 my $pl = Ndr::GetPrevLevel($e, $l);
419 if ($pl && $pl->{TYPE} eq "POINTER") {
420 $var = get_pointer_to($var);
422 my $avar = $var . "[i]";
426 pidl "for (i=0;i<$length;i++) {";
428 pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
429 EjsPushElement($e, Ndr::GetNextLevel($e, $l), $avar, "id", $env);
432 pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
437 ################################
438 # push a structure/union element
439 sub EjsPushElement($$$$$)
441 my ($e, $l, $var, $name, $env) = @_;
442 if (util::has_property($e, "charset")) {
443 EjsPushString($e, $l, $var, $name, $env);
444 } elsif ($l->{TYPE} eq "ARRAY") {
445 EjsPushArray($e, $l, $var, $name, $env);
446 } elsif ($l->{TYPE} eq "DATA") {
447 EjsPushScalar($e, $l, $var, $name, $env);
448 } elsif (($l->{TYPE} eq "POINTER")) {
449 EjsPushPointer($e, $l, $var, $name, $env);
450 } elsif (($l->{TYPE} eq "SWITCH")) {
451 EjsPushSwitch($e, $l, $var, $name, $env);
453 pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
457 #############################################
458 # push a structure/union element at top level
459 sub EjsPushElementTop($$)
463 my $l = $e->{LEVELS}[0];
464 my $var = util::ParseExpr($e->{NAME}, $env);
465 my $name = "\"$e->{NAME}\"";
466 EjsPushElement($e, $l, $var, $name, $env);
469 ###########################
471 sub EjsStructPush($$)
475 my $env = GenerateStructEnv($d);
477 pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)\n{";
479 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
480 foreach my $e (@{$d->{ELEMENTS}}) {
481 EjsPushElementTop($e, $env);
483 pidl "return NT_STATUS_OK;";
488 ###########################
494 my $have_default = 0;
495 my $env = GenerateStructEnv($d);
497 pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)\n{";
499 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
500 pidl "switch (ejs->switch_var) {";
502 foreach my $e (@{$d->{ELEMENTS}}) {
503 if ($e->{CASE} eq "default") {
508 if ($e->{TYPE} ne "EMPTY") {
509 EjsPushElementTop($e, $env);
514 if (! $have_default) {
517 pidl "return ejs_panic(ejs, \"Bad switch value\");";
522 pidl "return NT_STATUS_OK;";
527 ###########################
534 # put the enum elements in the constants array
535 foreach my $e (@{$d->{ELEMENTS}}) {
538 if ($el =~ /^(.*)=\s*(.*)\s*$/) {
542 $constants{$el} = $v;
546 pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)\n{";
548 pidl "unsigned e = *r;";
549 pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
550 pidl "return NT_STATUS_OK;";
555 ###########################
557 sub EjsBitmapPush($$)
561 my $type_fn = $d->{BASE_TYPE};
562 my($type_decl) = typelist::mapType($d->{BASE_TYPE});
563 # put the bitmap elements in the constants array
564 foreach my $e (@{$d->{ELEMENTS}}) {
565 if ($e =~ /^(\w*)\s*(.*)\s*$/) {
568 $constants{$bname} = $v;
572 pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)\n{";
574 pidl "return ejs_push_$type_fn(ejs, v, name, r);";
580 ###########################
581 # generate a structure push
582 sub EjsTypedefPush($)
585 return if (util::has_property($d, "noejs"));
586 if ($d->{DATA}->{TYPE} eq 'STRUCT') {
587 EjsStructPush($d->{NAME}, $d->{DATA});
588 } elsif ($d->{DATA}->{TYPE} eq 'UNION') {
589 EjsUnionPush($d->{NAME}, $d->{DATA});
590 } elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
591 EjsEnumPush($d->{NAME}, $d->{DATA});
592 } elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
593 EjsBitmapPush($d->{NAME}, $d->{DATA});
595 warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
600 #####################
601 # generate a function
602 sub EjsPushFunction($)
605 my $env = GenerateFunctionOutEnv($d);
607 pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
610 pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
612 foreach my $e (@{$d->{ELEMENTS}}) {
613 next unless (grep(/out/, @{$e->{DIRECTION}}));
614 EjsPushElementTop($e, $env);
617 pidl "return NT_STATUS_OK;";
623 #################################
624 # generate a ejs mapping function
628 my $name = $d->{NAME};
630 pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
633 pidl "return ejs_rpc_call(eid, argc, argv, \"$name\", (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
643 $constants{$const->{NAME}} = $const->{VALUE};
646 #####################################################################
647 # parse the interface definitions
650 my($interface) = shift;
652 my $name = $interface->{NAME};
656 foreach my $d (@{$interface->{TYPEDEFS}}) {
661 foreach my $d (@{$interface->{FUNCTIONS}}) {
662 next if not defined($d->{OPNUM});
668 push (@fns, $d->{NAME});
671 foreach my $d (@{$interface->{CONSTS}}) {
675 pidl "void setup_ejs_$name(void)";
679 pidl "ejsDefineCFunction(-1, \"dcerpc_$_\", ejs_$_, NULL, MPR_VAR_SCRIPT_HANDLE);";
684 pidl "void setup_ejs_constants_$name(int eid)";
687 foreach my $v (keys %constants) {
688 my $value = $constants{$v};
689 if (substr($value, 0, 1) eq "\"") {
690 pidl "ejs_set_constant_string(eid, \"$v\", $value);";
692 pidl "ejs_set_constant_int(eid, \"$v\", $value);";
698 pidl "NTSTATUS ejs_init_$name(void)";
701 pidl "return smbcalls_register_ejs(\"$name\", setup_ejs_$name, setup_ejs_constants_$name);";
706 #####################################################################
707 # parse a parsed IDL into a C header
713 $ejs_hdr =~ s/.h$/_ejs.h/;
716 /* EJS wrapper functions auto-generated by pidl */
717 #include \"includes.h\"
718 #include \"lib/ejs/ejs.h\"
719 #include \"scripting/ejs/ejsrpc.h\"
720 #include \"librpc/gen_ndr/ndr_misc_ejs.h\"
722 #include \"$ejs_hdr\"
725 foreach my $x (@{$ndr}) {
726 if ($x->{TYPE} eq "INTERFACE") {
727 ($x->{TYPE} eq "INTERFACE") && EjsInterface($x);