r8806: Move data representation-independent data into seperate header
[sfrench/samba-autobuild/.git] / source4 / build / pidl / Parse / Pidl / Samba / EJS.pm
1 ###################################################
2 # EJS function wrapper generator
3 # Copyright jelmer@samba.org 2005
4 # Copyright Andrew Tridgell 2005
5 # released under the GNU GPL
6
7 package Parse::Pidl::Samba::EJS;
8
9 use strict;
10 use Parse::Pidl::Typelist;
11 use Parse::Pidl::Util qw(has_property);
12
13 my($res);
14 my %constants;
15
16 my $tabs = "";
17 sub pidl($)
18 {
19         my $d = shift;
20         if ($d) {
21                 $res .= $tabs;
22                 $res .= $d;
23         }
24         $res .= "\n";
25 }
26
27 sub indent()
28 {
29         $tabs .= "\t";
30 }
31
32 sub deindent()
33 {
34         $tabs = substr($tabs, 0, -1);
35 }
36
37 # this should probably be in ndr.pm
38 sub GenerateStructEnv($)
39 {
40         my $x = shift;
41         my %env;
42
43         foreach my $e (@{$x->{ELEMENTS}}) {
44                 if ($e->{NAME}) {
45                         $env{$e->{NAME}} = "r->$e->{NAME}";
46                 }
47         }
48
49         $env{"this"} = "r";
50
51         return \%env;
52 }
53
54 sub GenerateFunctionInEnv($)
55 {
56         my $fn = shift;
57         my %env;
58
59         foreach my $e (@{$fn->{ELEMENTS}}) {
60                 if (grep (/in/, @{$e->{DIRECTION}})) {
61                         $env{$e->{NAME}} = "r->in.$e->{NAME}";
62                 }
63         }
64
65         return \%env;
66 }
67
68 sub GenerateFunctionOutEnv($)
69 {
70         my $fn = shift;
71         my %env;
72
73         foreach my $e (@{$fn->{ELEMENTS}}) {
74                 if (grep (/out/, @{$e->{DIRECTION}})) {
75                         $env{$e->{NAME}} = "r->out.$e->{NAME}";
76                 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
77                         $env{$e->{NAME}} = "r->in.$e->{NAME}";
78                 }
79         }
80
81         return \%env;
82 }
83
84 sub get_pointer_to($)
85 {
86         my $var_name = shift;
87         
88         if ($var_name =~ /^\*(.*)$/) {
89                 return $1;
90         } elsif ($var_name =~ /^\&(.*)$/) {
91                 return "&($var_name)";
92         } else {
93                 return "&$var_name";
94         }
95 }
96
97 sub get_value_of($)
98 {
99         my $var_name = shift;
100
101         if ($var_name =~ /^\&(.*)$/) {
102                 return $1;
103         } else {
104                 return "*$var_name";
105         }
106 }
107
108 #####################################################################
109 # work out is a parse function should be declared static or not
110 sub fn_prefix($)
111 {
112         my $fn = shift;
113
114         return "" if (has_property($fn, "public"));
115         return "static ";
116 }
117
118 ###########################
119 # pull a scalar element
120 sub EjsPullScalar($$$$$)
121 {
122         my ($e, $l, $var, $name, $env) = @_;
123
124         return if (has_property($e, "value"));
125
126         my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
127         $var = get_pointer_to($var);
128         # have to handle strings specially :(
129         if ($e->{TYPE} eq "string" && $pl && $pl->{TYPE} eq "POINTER") {
130                 $var = get_pointer_to($var);
131         }
132         pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
133 }
134
135 ###########################
136 # pull a pointer element
137 sub EjsPullPointer($$$$$)
138 {
139         my ($e, $l, $var, $name, $env) = @_;
140         pidl "if (ejs_pull_null(ejs, v, $name)) {";
141         indent;
142         pidl "$var = NULL;";
143         deindent;
144         pidl "} else {";
145         indent;
146         pidl "EJS_ALLOC(ejs, $var);";
147         $var = get_value_of($var);              
148         EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
149         deindent;
150         pidl "}";
151 }
152
153 ###########################
154 # pull a string element
155 sub EjsPullString($$$$$)
156 {
157         my ($e, $l, $var, $name, $env) = @_;
158         $var = get_pointer_to($var);
159         pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
160 }
161
162
163 ###########################
164 # pull an array element
165 sub EjsPullArray($$$$$)
166 {
167         my ($e, $l, $var, $name, $env) = @_;
168         my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
169         my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
170         if ($pl && $pl->{TYPE} eq "POINTER") {
171                 $var = get_pointer_to($var);
172         }
173         my $avar = $var . "[i]";
174         pidl "{";
175         indent;
176         pidl "uint32_t i;";
177         if (!$l->{IS_FIXED}) {
178                 pidl "EJS_ALLOC_N(ejs, $var, $length);";
179         }
180         pidl "for (i=0;i<$length;i++) {";
181         indent;
182         pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
183         EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $avar, "id", $env);
184         pidl "talloc_free(id);";
185         deindent;
186         pidl "}";
187         pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
188         deindent;
189         pidl "}";
190 }
191
192 ###########################
193 # pull a switch element
194 sub EjsPullSwitch($$$$$)
195 {
196         my ($e, $l, $var, $name, $env) = @_;
197         my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
198         pidl "ejs_set_switch(ejs, $switch_var);";
199         EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
200 }
201
202 ###########################
203 # pull a structure element
204 sub EjsPullElement($$$$$)
205 {
206         my ($e, $l, $var, $name, $env) = @_;
207         if (has_property($e, "charset")) {
208                 EjsPullString($e, $l, $var, $name, $env);
209         } elsif ($l->{TYPE} eq "ARRAY") {
210                 EjsPullArray($e, $l, $var, $name, $env);
211         } elsif ($l->{TYPE} eq "DATA") {
212                 EjsPullScalar($e, $l, $var, $name, $env);
213         } elsif (($l->{TYPE} eq "POINTER")) {
214                 EjsPullPointer($e, $l, $var, $name, $env);
215         } elsif (($l->{TYPE} eq "SWITCH")) {
216                 EjsPullSwitch($e, $l, $var, $name, $env);
217         } else {
218                 pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
219         }
220 }
221
222 #############################################
223 # pull a structure/union element at top level
224 sub EjsPullElementTop($$)
225 {
226         my $e = shift;
227         my $env = shift;
228         my $l = $e->{LEVELS}[0];
229         my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
230         my $name = "\"$e->{NAME}\"";
231         EjsPullElement($e, $l, $var, $name, $env);
232 }
233
234 ###########################
235 # pull a struct
236 sub EjsStructPull($$)
237 {
238         my $name = shift;
239         my $d = shift;
240         my $env = GenerateStructEnv($d);
241         pidl fn_prefix($d);
242         pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)\n{";
243         indent;
244         pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
245         foreach my $e (@{$d->{ELEMENTS}}) {
246                 EjsPullElementTop($e, $env);
247         }
248         pidl "return NT_STATUS_OK;";
249         deindent;
250         pidl "}\n";
251 }
252
253 ###########################
254 # pull a union
255 sub EjsUnionPull($$)
256 {
257         my $name = shift;
258         my $d = shift;
259         my $have_default = 0;
260         my $env = GenerateStructEnv($d);
261         pidl fn_prefix($d);
262         pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)\n{";
263         indent;
264         pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
265         pidl "switch (ejs->switch_var) {";
266         indent;
267         foreach my $e (@{$d->{ELEMENTS}}) {
268                 if ($e->{CASE} eq "default") {
269                         $have_default = 1;
270                 }
271                 pidl "$e->{CASE}:";
272                 indent;
273                 if ($e->{TYPE} ne "EMPTY") {
274                         EjsPullElementTop($e, $env);
275                 }
276                 pidl "break;";
277                 deindent;
278         }
279         if (! $have_default) {
280                 pidl "default:";
281                 indent;
282                 pidl "return ejs_panic(ejs, \"Bad switch value\");";
283                 deindent;
284         }
285         deindent;
286         pidl "}";
287         pidl "return NT_STATUS_OK;";
288         deindent;
289         pidl "}";
290 }
291
292 ##############################################
293 # put the enum elements in the constants array
294 sub EjsEnumConstant($)
295 {
296         my $d = shift;
297         my $v = 0;
298         foreach my $e (@{$d->{ELEMENTS}}) {
299                 my $el = $e;
300                 chomp $el;
301                 if ($el =~ /^(.*)=\s*(.*)\s*$/) {
302                         $el = $1;
303                         $v = $2;
304                 }
305                 $constants{$el} = $v;
306                 $v++;
307         }
308 }
309
310 ###########################
311 # pull a enum
312 sub EjsEnumPull($$)
313 {
314         my $name = shift;
315         my $d = shift;
316         EjsEnumConstant($d);
317         pidl fn_prefix($d);
318         pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)\n{";
319         indent;
320         pidl "unsigned e;";
321         pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
322         pidl "*r = e;";
323         pidl "return NT_STATUS_OK;";
324         deindent;
325         pidl "}\n";
326 }
327
328 ###########################
329 # pull a bitmap
330 sub EjsBitmapPull($$)
331 {
332         my $name = shift;
333         my $d = shift;
334         my $type_fn = $d->{BASE_TYPE};
335         my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
336         pidl fn_prefix($d);
337         pidl "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)\n{";
338         indent;
339         pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
340         deindent;
341         pidl "}";
342 }
343
344
345 ###########################
346 # generate a structure pull
347 sub EjsTypedefPull($)
348 {
349         my $d = shift;
350         return if (has_property($d, "noejs"));
351         if ($d->{DATA}->{TYPE} eq 'STRUCT') {
352                 EjsStructPull($d->{NAME}, $d->{DATA});
353         } elsif ($d->{DATA}->{TYPE} eq 'UNION') {
354                 EjsUnionPull($d->{NAME}, $d->{DATA});
355         } elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
356                 EjsEnumPull($d->{NAME}, $d->{DATA});
357         } elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
358                 EjsBitmapPull($d->{NAME}, $d->{DATA});
359         } else {
360                 warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
361         }
362 }
363
364 #####################
365 # generate a function
366 sub EjsPullFunction($)
367 {
368         my $d = shift;
369         my $env = GenerateFunctionInEnv($d);
370         my $name = $d->{NAME};
371
372         pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
373         pidl "{";
374         indent;
375         pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
376
377         foreach my $e (@{$d->{ELEMENTS}}) {
378                 next unless (grep(/in/, @{$e->{DIRECTION}}));
379                 EjsPullElementTop($e, $env);
380         }
381
382         pidl "return NT_STATUS_OK;";
383         deindent;
384         pidl "}\n";
385 }
386
387
388 ###########################
389 # push a scalar element
390 sub EjsPushScalar($$$$$)
391 {
392         my ($e, $l, $var, $name, $env) = @_;
393         # have to handle strings specially :(
394         my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
395         if ($e->{TYPE} ne "string" || ($pl && $pl->{TYPE} eq "POINTER")) {
396                 $var = get_pointer_to($var);
397         }
398         pidl "NDR_CHECK(ejs_push_$e->{TYPE}(ejs, v, $name, $var));";
399 }
400
401 ###########################
402 # push a string element
403 sub EjsPushString($$$$$)
404 {
405         my ($e, $l, $var, $name, $env) = @_;
406         pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
407 }
408
409 ###########################
410 # push a pointer element
411 sub EjsPushPointer($$$$$)
412 {
413         my ($e, $l, $var, $name, $env) = @_;
414         pidl "if (NULL == $var) {";
415         indent;
416         pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
417         deindent;
418         pidl "} else {";
419         indent;
420         $var = get_value_of($var);              
421         EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
422         deindent;
423         pidl "}";
424 }
425
426 ###########################
427 # push a switch element
428 sub EjsPushSwitch($$$$$)
429 {
430         my ($e, $l, $var, $name, $env) = @_;
431         my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
432         pidl "ejs_set_switch(ejs, $switch_var);";
433         EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
434 }
435
436
437 ###########################
438 # push an array element
439 sub EjsPushArray($$$$$)
440 {
441         my ($e, $l, $var, $name, $env) = @_;
442         my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
443         my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
444         if ($pl && $pl->{TYPE} eq "POINTER") {
445                 $var = get_pointer_to($var);
446         }
447         my $avar = $var . "[i]";
448         pidl "{";
449         indent;
450         pidl "uint32_t i;";
451         pidl "for (i=0;i<$length;i++) {";
452         indent;
453         pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
454         EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $avar, "id", $env);
455         deindent;
456         pidl "}";
457         pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
458         deindent;
459         pidl "}";
460 }
461
462 ################################
463 # push a structure/union element
464 sub EjsPushElement($$$$$)
465 {
466         my ($e, $l, $var, $name, $env) = @_;
467         if (has_property($e, "charset")) {
468                 EjsPushString($e, $l, $var, $name, $env);
469         } elsif ($l->{TYPE} eq "ARRAY") {
470                 EjsPushArray($e, $l, $var, $name, $env);
471         } elsif ($l->{TYPE} eq "DATA") {
472                 EjsPushScalar($e, $l, $var, $name, $env);
473         } elsif (($l->{TYPE} eq "POINTER")) {
474                 EjsPushPointer($e, $l, $var, $name, $env);
475         } elsif (($l->{TYPE} eq "SWITCH")) {
476                 EjsPushSwitch($e, $l, $var, $name, $env);
477         } else {
478                 pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
479         }
480 }
481
482 #############################################
483 # push a structure/union element at top level
484 sub EjsPushElementTop($$)
485 {
486         my $e = shift;
487         my $env = shift;
488         my $l = $e->{LEVELS}[0];
489         my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
490         my $name = "\"$e->{NAME}\"";
491         EjsPushElement($e, $l, $var, $name, $env);
492 }
493
494 ###########################
495 # push a struct
496 sub EjsStructPush($$)
497 {
498         my $name = shift;
499         my $d = shift;
500         my $env = GenerateStructEnv($d);
501         pidl fn_prefix($d);
502         pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)\n{";
503         indent;
504         pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
505         foreach my $e (@{$d->{ELEMENTS}}) {
506                 EjsPushElementTop($e, $env);
507         }
508         pidl "return NT_STATUS_OK;";
509         deindent;
510         pidl "}\n";
511 }
512
513 ###########################
514 # push a union
515 sub EjsUnionPush($$)
516 {
517         my $name = shift;
518         my $d = shift;
519         my $have_default = 0;
520         my $env = GenerateStructEnv($d);
521         pidl fn_prefix($d);
522         pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)\n{";
523         indent;
524         pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
525         pidl "switch (ejs->switch_var) {";
526         indent;
527         foreach my $e (@{$d->{ELEMENTS}}) {
528                 if ($e->{CASE} eq "default") {
529                         $have_default = 1;
530                 }
531                 pidl "$e->{CASE}:";
532                 indent;
533                 if ($e->{TYPE} ne "EMPTY") {
534                         EjsPushElementTop($e, $env);
535                 }
536                 pidl "break;";
537                 deindent;
538         }
539         if (! $have_default) {
540                 pidl "default:";
541                 indent;
542                 pidl "return ejs_panic(ejs, \"Bad switch value\");";
543                 deindent;
544         }
545         deindent;
546         pidl "}";
547         pidl "return NT_STATUS_OK;";
548         deindent;
549         pidl "}";
550 }
551
552 ###########################
553 # push a enum
554 sub EjsEnumPush($$)
555 {
556         my $name = shift;
557         my $d = shift;
558         EjsEnumConstant($d);
559         pidl fn_prefix($d);
560         pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)\n{";
561         indent;
562         pidl "unsigned e = *r;";
563         pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
564         pidl "return NT_STATUS_OK;";
565         deindent;
566         pidl "}\n";
567 }
568
569 ###########################
570 # push a bitmap
571 sub EjsBitmapPush($$)
572 {
573         my $name = shift;
574         my $d = shift;
575         my $type_fn = $d->{BASE_TYPE};
576         my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
577         # put the bitmap elements in the constants array
578         foreach my $e (@{$d->{ELEMENTS}}) {
579                 if ($e =~ /^(\w*)\s*(.*)\s*$/) {
580                         my $bname = $1;
581                         my $v = $2;
582                         $constants{$bname} = $v;
583                 }
584         }
585         pidl fn_prefix($d);
586         pidl "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)\n{";
587         indent;
588         pidl "return ejs_push_$type_fn(ejs, v, name, r);";
589         deindent;
590         pidl "}";
591 }
592
593
594 ###########################
595 # generate a structure push
596 sub EjsTypedefPush($)
597 {
598         my $d = shift;
599         return if (has_property($d, "noejs"));
600         if ($d->{DATA}->{TYPE} eq 'STRUCT') {
601                 EjsStructPush($d->{NAME}, $d->{DATA});
602         } elsif ($d->{DATA}->{TYPE} eq 'UNION') {
603                 EjsUnionPush($d->{NAME}, $d->{DATA});
604         } elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
605                 EjsEnumPush($d->{NAME}, $d->{DATA});
606         } elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
607                 EjsBitmapPush($d->{NAME}, $d->{DATA});
608         } else {
609                 warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
610         }
611 }
612
613
614 #####################
615 # generate a function
616 sub EjsPushFunction($)
617 {
618         my $d = shift;
619         my $env = GenerateFunctionOutEnv($d);
620
621         pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
622         pidl "{";
623         indent;
624         pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
625
626         foreach my $e (@{$d->{ELEMENTS}}) {
627                 next unless (grep(/out/, @{$e->{DIRECTION}}));
628                 EjsPushElementTop($e, $env);
629         }
630
631         pidl "return NT_STATUS_OK;";
632         deindent;
633         pidl "}\n";
634 }
635
636
637 #################################
638 # generate a ejs mapping function
639 sub EjsFunction($$)
640 {
641         my $d = shift;
642         my $iface = shift;
643         my $name = $d->{NAME};
644         my $callnum = uc("DCERPC_$name");
645         my $table = "&dcerpc_table_$iface";
646
647         pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
648         pidl "{";
649         indent;
650         pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
651         deindent;
652         pidl "}\n";
653 }
654
655 ###################
656 # handle a constant
657 sub EjsConst($)
658 {
659     my $const = shift;
660     $constants{$const->{NAME}} = $const->{VALUE};
661 }
662
663 #####################################################################
664 # parse the interface definitions
665 sub EjsInterface($$)
666 {
667         my($interface,$needed) = @_;
668         my @fns = ();
669         my $name = $interface->{NAME};
670
671         %constants = ();
672
673         foreach my $d (@{$interface->{TYPEDEFS}}) {
674                 ($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
675                 ($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
676         }
677
678         foreach my $d (@{$interface->{FUNCTIONS}}) {
679                 next if not defined($d->{OPNUM});
680                 
681                 EjsPullFunction($d);
682                 EjsPushFunction($d);
683                 EjsFunction($d, $name);
684
685                 push (@fns, $d->{NAME});
686         }
687
688         foreach my $d (@{$interface->{CONSTS}}) {
689                 EjsConst($d);
690         }
691
692         pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
693         pidl "{";
694         indent;
695         pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
696         foreach (@fns) {
697                 pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
698         }
699         foreach my $v (keys %constants) {
700                 my $value = $constants{$v};
701                 if (substr($value, 0, 1) eq "\"") {
702                         pidl "mprSetVar(obj, \"$v\", mprString($value));";
703                 } else {
704                         pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
705                 }
706         }
707         pidl "return 0;";
708         deindent;
709         pidl "}\n";
710
711         pidl "NTSTATUS ejs_init_$name(void)";
712         pidl "{";
713         indent;
714         pidl "return smbcalls_register_ejs(\"$name\_init\", ejs_$name\_init);";
715         deindent;
716         pidl "}";
717 }
718
719 #####################################################################
720 # parse a parsed IDL into a C header
721 sub Parse($$)
722 {
723     my($ndr,$hdr) = @_;
724     
725     my $ejs_hdr = $hdr;
726     $ejs_hdr =~ s/.h$/_ejs.h/;
727     $res = "";
728     pidl "
729 /* EJS wrapper functions auto-generated by pidl */
730 #include \"includes.h\"
731 #include \"lib/appweb/ejs/ejs.h\"
732 #include \"scripting/ejs/ejsrpc.h\"
733 #include \"scripting/ejs/smbcalls.h\"
734 #include \"librpc/gen_ndr/ndr_misc_ejs.h\"
735 #include \"$hdr\"
736 #include \"$ejs_hdr\"
737
738 ";
739
740     my %needed = ();
741
742     foreach my $x (@{$ndr}) {
743             ($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
744     }
745
746     foreach my $x (@{$ndr}) {
747             ($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
748     }
749
750     return $res;
751 }
752
753 sub NeededFunction($$)
754 {
755         my ($fn,$needed) = @_;
756         $needed->{"pull_$fn->{NAME}"} = 1;
757         $needed->{"push_$fn->{NAME}"} = 1;
758         foreach my $e (@{$fn->{ELEMENTS}}) {
759                 if (grep (/in/, @{$e->{DIRECTION}})) {
760                         $needed->{"pull_$e->{TYPE}"} = 1;
761                 }
762                 if (grep (/out/, @{$e->{DIRECTION}})) {
763                         $needed->{"push_$e->{TYPE}"} = 1;
764                 }
765         }
766 }
767
768 sub NeededTypedef($$)
769 {
770         my ($t,$needed) = @_;
771         if (Parse::Pidl::Util::has_property($t, "public")) {
772                 $needed->{"pull_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
773                 $needed->{"push_$t->{NAME}"} = not Parse::Pidl::Util::has_property($t, "noejs");
774         }
775         if ($t->{DATA}->{TYPE} ne "STRUCT" && 
776             $t->{DATA}->{TYPE} ne "UNION") {
777                 return;
778         }
779         for my $e (@{$t->{DATA}->{ELEMENTS}}) {
780                 if ($needed->{"pull_$t->{NAME}"}) {
781                         $needed->{"pull_$e->{TYPE}"} = 1;
782                 }
783                 if ($needed->{"push_$t->{NAME}"}) {
784                         $needed->{"push_$e->{TYPE}"} = 1;
785                 }
786         }
787 }
788
789 #####################################################################
790 # work out what parse functions are needed
791 sub NeededInterface($$)
792 {
793         my ($interface,$needed) = @_;
794         foreach my $d (@{$interface->{FUNCTIONS}}) {
795             NeededFunction($d, $needed);
796         }
797         foreach my $d (reverse @{$interface->{TYPEDEFS}}) {
798             NeededTypedef($d, $needed);
799         }
800 }
801
802 1;