d0eba81beffcab592a0a175442c4ac65e3aa8d4e
[samba.git] / source / build / pidl / ndr_parser.pm
1 ###################################################
2 # Samba4 NDR parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # Copyright jelmer@samba.org 2004-2005
6 # released under the GNU GPL
7
8 package NdrParser;
9
10 use strict;
11 use needed;
12 use typelist;
13 use ndr;
14
15 # list of known types
16 my %typefamily;
17
18 sub get_typefamily($)
19 {
20         my $n = shift;
21         return $typefamily{$n};
22 }
23
24 # determine if an element needs a "buffers" section in NDR
25 sub need_buffers_section($)
26 {
27         my $e = shift;
28         if (!Ndr::can_contain_deferred($e) &&
29             !util::array_size($e)) {
30                 return 0;
31         }
32         return 1;
33 }
34
35 # see if a variable needs to be allocated by the NDR subsystem on pull
36 sub need_alloc($)
37 {
38         my $e = shift;
39
40         return 0 if (util::has_property($e, "ref") && $e->{PARENT}->{TYPE} eq "FUNCTION");
41         return 1 if ($e->{POINTERS} || util::array_size($e));
42         return 0;
43 }
44
45 # Prefix to get the actual value of a variable
46 sub c_ptr_prefix($)
47 {
48         my $e = shift;
49         my $pointers = "";
50         foreach my $i (Ndr::need_wire_pointer($e)..$e->{POINTERS}-1) { $pointers.="*"; }
51         return $pointers;
52 }
53
54 # determine the C prefix used to refer to a variable when passing to a push
55 # function. This will be '*' for pointers to scalar types, '' for scalar
56 # types and normal pointers and '&' for pass-by-reference structures
57 sub c_push_prefix($)
58 {
59         my $e = shift;
60
61         my $ret = "";
62
63         if ($e->{TYPE} =~ "string") {
64                 $ret = "";
65         } elsif (Ndr::is_scalar_type($e->{TYPE}) and $e->{POINTERS} and 
66                 !util::array_size($e)) {
67                 $ret .="*";
68         } elsif (!Ndr::is_scalar_type($e->{TYPE}) &&
69             !$e->{POINTERS} &&
70             !util::array_size($e)) {
71                 return "&";
72         }
73
74         foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
75         
76         return $ret;
77 }
78
79 # determine the C prefix used to refer to a variable when passing to a pull
80 # return '&' or ''
81 sub c_pull_prefix($)
82 {
83         my $e = shift;
84
85         if (!$e->{POINTERS} && !util::array_size($e)) {
86                 return "&";
87         }
88
89         if ($e->{TYPE} =~ "string") {
90                 return "&";
91         }
92
93         my $ret = "";
94         foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
95         return $ret;
96 }
97 my $res = "";
98 my $tabs = "";
99 sub pidl($)
100 {
101         my $d = shift;
102         if ($d) {
103                 $res .= $tabs;
104                 $res .= $d;
105         }
106         $res .="\n";
107 }
108
109 sub indent()
110 {
111         $tabs .= "\t";
112 }
113
114 sub deindent()
115 {
116         $tabs = substr($tabs, 0, -1);
117 }
118
119 ####################################################################
120 # work out the name of a size_is() variable
121 sub ParseExpr($$$)
122 {
123         my($e) = shift;
124         my($size) = shift;
125         my($var_prefix) = shift;
126
127         my($fn) = $e->{PARENT};
128
129         return $size if (util::is_constant($size));
130
131         return $size if ($size =~ /ndr->|\(/);
132
133         my $prefix = "";
134
135         if ($size =~ /\*(.*)/) {
136                 $size = $1;
137                 $prefix = "*";
138         }
139
140         if ($fn->{TYPE} ne "FUNCTION") {
141                 return $prefix . "r->$size";
142         }
143
144         my $e2 = util::find_sibling($e, $size);
145
146         die("Invalid sibling '$size'") unless defined($e2);
147
148         if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
149                 return $prefix . "$var_prefix$size";
150         }
151         
152         if (util::has_property($e2, "in")) {
153                 return $prefix . "r->in.$size";
154         }
155         
156         if (util::has_property($e2, "out")) {
157                 return $prefix . "r->out.$size";
158         }
159
160         die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
161 }
162
163 #####################################################################
164 # check that a variable we get from ParseExpr isn't a null pointer
165 sub check_null_pointer($)
166 {
167         my $size = shift;
168         if ($size =~ /^\*/) {
169                 my $size2 = substr($size, 1);
170                 pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
171         }
172 }
173
174 #####################################################################
175 # check that a variable we get from ParseExpr isn't a null pointer
176 # void return varient
177 sub check_null_pointer_void($)
178 {
179         my $size = shift;
180         if ($size =~ /^\*/) {
181                 my $size2 = substr($size, 1);
182                 pidl "if ($size2 == NULL) return;";
183         }
184 }
185
186 #####################################################################
187 # work out is a parse function should be declared static or not
188 sub fn_prefix($)
189 {
190         my $fn = shift;
191
192         if ($fn->{TYPE} eq "TYPEDEF" or 
193             $fn->{TYPE} eq "FUNCTION") {
194                 return "" if (util::has_property($fn, "public"));
195         }
196
197         return "static ";
198 }
199
200 ###################################################################
201 # setup any special flags for an element or structure
202 sub start_flags($)
203 {
204         my $e = shift;
205         my $flags = util::has_property($e, "flag");
206         if (defined $flags) {
207                 pidl "{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;";
208                 pidl "ndr_set_flags(&ndr->flags, $flags);";
209         }
210 }
211
212 ###################################################################
213 # end any special flags for an element or structure
214 sub end_flags($)
215 {
216         my $e = shift;
217         my $flags = util::has_property($e, "flag");
218         if (defined $flags) {
219                 pidl "ndr->flags = _flags_save_$e->{TYPE};\n\t}";
220         }
221 }
222
223 #####################################################################
224 # parse array preceding data - push side
225 sub ParseArrayPushPreceding($$$)
226 {
227         my $e = shift;
228         my $var_prefix = shift;
229         my $ndr_flags = shift;
230
231         my $size = ParseExpr($e, util::array_size($e), $var_prefix);
232
233         if (!Ndr::is_inline_array($e)) {
234                 # we need to emit the array size
235                 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));";
236         }
237 }
238
239 #####################################################################
240 # parse the data of an array - push side
241 sub ParseArrayPush($$$$)
242 {
243         my $e = shift;
244         my $ndr = shift;
245         my $var_prefix = shift;
246         my $ndr_flags = shift;
247         my $cprefix = c_push_prefix($e);
248
249         my $size = ParseExpr($e, util::array_size($e), $var_prefix);
250
251         # See whether the array size has been pushed yet
252         if (!Ndr::is_surrounding_array($e)) {
253                 ParseArrayPushPreceding($e, $var_prefix, $ndr_flags);
254         }
255         
256         if (Ndr::is_varying_array($e)) {
257                 my $length = util::has_property($e, "length_is");
258                 $length = ParseExpr($e, $length, $var_prefix);
259                 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));";
260                 pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));";
261                 $size = $length;
262         }
263
264         if (Ndr::is_scalar_type($e->{TYPE})) {
265                 pidl "NDR_CHECK(ndr_push_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $size));";
266         } else {
267                 pidl "NDR_CHECK(ndr_push_array($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE}));";
268         }
269 }
270
271 #####################################################################
272 # print an array
273 sub ParseArrayPrint($$)
274 {
275         my $e = shift;
276         my $var_prefix = shift;
277         my $size = ParseExpr($e, util::array_size($e), $var_prefix);
278         my $cprefix = c_push_prefix($e);
279
280         if (Ndr::is_varying_array($e)) {
281                 $size = ParseExpr($e, util::has_property($e, "length_is"), $var_prefix);
282         }
283
284         if (Ndr::is_scalar_type($e->{TYPE})) {
285                 pidl "ndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, $size);";
286         } else {
287                 pidl "ndr_print_array(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $size, (ndr_print_fn_t)ndr_print_$e->{TYPE});";
288         }
289 }
290
291 #####################################################################
292 # check the size_is and length_is constraints
293 sub CheckArraySizes($$)
294 {
295         my $e = shift;
296         my $var_prefix = shift;
297
298         if (Ndr::is_conformant_array($e)) {
299                 my $size = ParseExpr($e, util::array_size($e), $var_prefix);
300                 pidl "if ($var_prefix$e->{NAME}) {";
301                 indent;
302                 check_null_pointer($size);
303                 pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));";
304                 deindent;
305                 pidl "}";
306         }
307
308         if (Ndr::is_varying_array($e)) {
309                 my $length = util::has_property($e, "length_is");
310                 $length = ParseExpr($e, $length, $var_prefix);
311                 pidl "if ($var_prefix$e->{NAME}) {";
312                 indent;
313                 check_null_pointer($length);
314                 pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));";
315                 deindent;
316                 pidl "}"
317         }
318 }
319
320 sub ParseArrayPullPreceding($$$)
321 {
322         my $e = shift;
323         my $var_prefix = shift;
324         my $ndr_flags = shift;
325
326         if (!Ndr::is_inline_array($e)) {
327                 # non fixed arrays encode the size just before the array
328                 pidl "NDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));";
329         }
330 }
331
332 #####################################################################
333 # parse an array - pull side
334 sub ParseArrayPull($$$$)
335 {
336         my $e = shift;
337         my $ndr = shift;
338         my $var_prefix = shift;
339         my $ndr_flags = shift;
340
341         my $cprefix = c_pull_prefix($e);
342         my $length = ParseExpr($e, util::array_size($e), $var_prefix);
343         my $size = $length;
344
345         if (Ndr::is_conformant_array($e)) {
346                 $length = $size = "ndr_get_array_size($ndr, &$var_prefix$e->{NAME})";
347         }
348
349         # if this is a conformant array then we use that size to allocate, and make sure
350         # we allocate enough to pull the elements
351         if (!Ndr::is_inline_array($e) and not Ndr::is_surrounding_array($e)) {
352                 if ($var_prefix =~ /^r->out/ && $length =~ /^\*r->in/) {
353                         my $length2 = substr($length, 1);
354                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_ALLOC($ndr, $length2); }";
355                 }
356
357                 ParseArrayPullPreceding($e, $var_prefix, $ndr_flags);
358         }
359
360         if (Ndr::is_varying_array($e)) {
361                 pidl "NDR_CHECK(ndr_pull_array_length($ndr, &$var_prefix$e->{NAME}));";
362                 $length = "ndr_get_array_length($ndr, &$var_prefix$e->{NAME})";
363         }
364
365         check_null_pointer($length);
366
367         if ($length ne $size) {
368                 pidl "if ($length > $size) {";
369                 indent;
370                 pidl "return ndr_pull_error($ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $size, $length);";
371                 deindent;
372                 pidl "}";
373         }
374
375         if ((need_alloc($e) && !Ndr::is_fixed_array($e)) ||
376             ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
377                 if (!Ndr::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
378                         pidl "NDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);";
379                 }
380         }
381
382         if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
383                 if (!Ndr::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
384                         pidl "if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
385                         pidl "\tNDR_ALLOC_N($ndr, $var_prefix$e->{NAME}, $size);";
386                         pidl "}";
387                 }
388         }
389
390         if (Ndr::is_scalar_type($e->{TYPE})) {
391                 pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}, $length));";
392         } else {
393                 pidl "NDR_CHECK(ndr_pull_array($ndr, $ndr_flags, (void **)$cprefix$var_prefix$e->{NAME}, sizeof($cprefix$var_prefix$e->{NAME}\[0]), $length, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE}));";
394         }
395 }
396
397 sub compression_alg($)
398 {
399         my $e = shift;
400         my $compression = util::has_property($e, "compression");
401         my ($alg, $clen, $dlen) = split(/ /, $compression);
402
403         return $alg;
404 }
405
406 sub compression_clen($)
407 {
408         my $e = shift;
409         my $compression = util::has_property($e, "compression");
410         my ($alg, $clen, $dlen) = split(/ /, $compression);
411
412         return ParseExpr($e, $clen, "r->");
413 }
414
415 sub compression_dlen($)
416 {
417         my $e = shift;
418         my $compression = util::has_property($e, "compression");
419         my ($alg, $clen, $dlen) = split(/ /, $compression);
420
421         return ParseExpr($e, $dlen, "r->");
422 }
423
424 sub ParseCompressionPushStart($$)
425 {
426         my $e = shift;
427         my $subndr = shift;
428         my $comndr = $subndr."_compressed";
429
430         pidl "{";
431         indent;
432         pidl "struct ndr_push *$comndr;";
433         pidl "";
434         pidl "$comndr = ndr_push_init_ctx($subndr);";
435         pidl "if (!$comndr) return NT_STATUS_NO_MEMORY;";
436         pidl "$comndr->flags = $subndr->flags;";
437         pidl "";
438         
439         return $comndr;
440 }
441
442 sub ParseCompressionPushEnd($$)
443 {
444         my $e = shift;
445         my $subndr = shift;
446         my $comndr = $subndr."_compressed";
447         my $alg = compression_alg($e);
448
449         pidl "NDR_CHECK(ndr_push_compression($subndr, $comndr, $alg));";
450         deindent;
451         pidl "}";
452 }
453
454 sub ParseCompressionPullStart($$)
455 {
456         my $e = shift;
457         my $subndr = shift;
458         my $comndr = $subndr."_compressed";
459         my $alg = compression_alg($e);
460         my $dlen = compression_dlen($e);
461
462         pidl "{";
463         indent;
464         pidl "struct ndr_pull *$comndr;";
465         pidl "NDR_ALLOC($subndr, $comndr);";
466         pidl "NDR_CHECK(ndr_pull_compression($subndr, $comndr, $alg, $dlen));";
467
468         return $comndr;
469 }
470
471 sub ParseCompressionPullEnd($$)
472 {
473         my $e = shift;
474         my $subndr = shift;
475         my $comndr = $subndr."_compressed";
476
477         deindent;
478         pidl "}";
479 }
480
481 sub ParseObfuscationPushStart($$)
482 {
483         my $e = shift;
484         my $ndr = shift;
485
486         # nothing to do here
487
488         return $ndr;
489 }
490
491 sub ParseObfuscationPushEnd($$)
492 {
493         my $e = shift;
494         my $ndr = shift;
495         my $obfuscation = util::has_property($e, "obfuscation");
496
497         pidl "NDR_CHECK(ndr_push_obfuscation($ndr, $obfuscation));";
498 }
499
500 sub ParseObfuscationPullStart($$)
501 {
502         my $e = shift;
503         my $ndr = shift;
504         my $obfuscation = util::has_property($e, "obfuscation");
505
506         pidl "NDR_CHECK(ndr_pull_obfuscation($ndr, $obfuscation));";
507
508         return $ndr;
509 }
510
511 sub ParseObfuscationPullEnd($$)
512 {
513         my $e = shift;
514         my $ndr = shift;
515
516         # nothing to do here
517 }
518
519 sub ParseSubcontextPushStart($$)
520 {
521         my $e = shift;
522         my $ndr_flags = shift;
523         my $compression = util::has_property($e, "compression");
524         my $obfuscation = util::has_property($e, "obfuscation");
525         my $retndr = "_ndr_$e->{NAME}";
526
527         pidl "if (($ndr_flags) & NDR_SCALARS) {";
528         indent;
529         pidl "struct ndr_push *$retndr;";
530         pidl "";
531         pidl "$retndr = ndr_push_init_ctx(ndr);";
532         pidl "if (!$retndr) return NT_STATUS_NO_MEMORY;";
533         pidl "$retndr->flags = ndr->flags;";
534         pidl "";
535
536         if (defined $compression) {
537                 $retndr = ParseCompressionPushStart($e, $retndr);
538         }
539
540         if (defined $obfuscation) {
541                 $retndr = ParseObfuscationPushStart($e, $retndr);
542         }
543
544         return $retndr
545 }
546
547 sub ParseSubcontextPushEnd($)
548 {
549         my $e = shift;
550         my $header_size = util::has_property($e, "subcontext");
551         my $size_is = util::has_property($e, "subcontext_size");
552         my $compression = util::has_property($e, "compression");
553         my $obfuscation = util::has_property($e, "obfuscation");
554         my $ndr = "_ndr_$e->{NAME}";
555
556         if (defined $obfuscation) {
557                 ParseObfuscationPushEnd($e, $ndr);
558         }
559
560         if (defined $compression) {
561                 ParseCompressionPushEnd($e, $ndr);
562         }
563
564         if (not defined($size_is)) {
565                 $size_is = "-1";
566         }
567
568         pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $header_size, $size_is, $ndr));";
569         pidl "NDR_CHECK(ndr_push_bytes(ndr, $ndr->data, $ndr->offset));";
570         deindent;
571         pidl "}";
572 }
573
574 sub ParseSubcontextPullStart($$)
575 {
576         my $e = shift;
577         my $ndr_flags = shift;
578         my $header_size = util::has_property($e, "subcontext");
579         my $size_is = util::has_property($e, "subcontext_size");
580         my $compression = util::has_property($e, "compression");
581         my $obfuscation = util::has_property($e, "obfuscation");
582         my $retndr = "_ndr_$e->{NAME}";
583
584         if (not defined($size_is)) {
585                 $size_is = "-1";
586         }
587
588         pidl "if (($ndr_flags) & NDR_SCALARS) {";
589         indent;
590         pidl "struct ndr_pull *$retndr;";
591         pidl "NDR_ALLOC(ndr, $retndr);";
592         pidl "NDR_CHECK(ndr_pull_subcontext_header(ndr, $header_size, $size_is, $retndr));";
593
594         if (defined $compression) {
595                 $retndr = ParseCompressionPullStart($e, $retndr);
596         }
597
598         if (defined $obfuscation) {
599                 $retndr = ParseObfuscationPullStart($e, $retndr);
600         }
601         
602         return $retndr;
603 }
604
605 sub ParseSubcontextPullEnd($)
606 {
607         my $e = shift;
608         my $header_size = util::has_property($e, "subcontext");
609         my $size_is = util::has_property($e, "subcontext_size");
610         my $compression = util::has_property($e, "compression");
611         my $obfuscation = util::has_property($e, "obfuscation");
612         my $ndr = "_ndr_$e->{NAME}";
613
614         if (defined $obfuscation) {
615                 ParseObfuscationPullEnd($e, $ndr);
616         }
617
618         if (defined $compression) {
619                 ParseCompressionPullEnd($e, $ndr);
620         }
621
622         my $advance;
623         if (defined ($size_is)) {
624                 $advance = "$size_is";
625         } elsif ($header_size) {
626                 $advance = "$ndr->data_size";
627         } else {
628                 $advance = "$ndr->offset";
629         }
630         pidl "NDR_CHECK(ndr_pull_advance(ndr, $advance));";
631         deindent;
632         pidl "}";
633 }
634
635 #####################################################################
636 # parse scalars in a structure element
637 sub ParseElementPushScalar($$$)
638 {
639         my($e) = shift;
640         my($var_prefix) = shift;
641         my($ndr_flags) = shift;
642         my $cprefix = c_push_prefix($e);
643         my $ptr_prefix = c_ptr_prefix($e);
644         my $sub_size = util::has_property($e, "subcontext");
645         my $ndr = "ndr";
646         my $subndr = undef;
647
648         start_flags($e);
649
650         if (my $value = util::has_property($e, "value")) {
651                 pidl "$cprefix$var_prefix$e->{NAME} = $value;";
652         }
653
654         if (defined $sub_size and $e->{POINTERS} == 0) {
655                 $subndr = ParseSubcontextPushStart($e, "NDR_SCALARS");
656                 $ndr = $subndr;
657         }
658
659         if (Ndr::need_wire_pointer($e)) {
660                 ParsePtrPush($e, $ptr_prefix.$var_prefix);
661         } elsif (Ndr::is_inline_array($e)) {
662                 ParseArrayPush($e, $ndr, "r->", "NDR_SCALARS");
663         } elsif (need_alloc($e)) {
664                 # no scalar component
665         } else {
666                 if (my $switch = util::has_property($e, "switch_is")) {
667                         ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
668                 }
669
670                 pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
671         }
672
673         if (defined $sub_size and $e->{POINTERS} == 0) {
674                 ParseSubcontextPushEnd($e);
675         }
676
677         end_flags($e);
678 }
679
680 #####################################################################
681 # parse a pointer in a struct element or function
682 sub ParsePtrPush($$)
683 {
684         my $e = shift;
685         my $var_prefix = shift;
686
687         if (util::has_property($e, "ref")) {
688                 pidl "NDR_CHECK(ndr_push_ref_ptr(ndr, $var_prefix$e->{NAME}));";
689         } elsif (util::has_property($e, "relative")) {
690                 pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));";
691         } else {
692                 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_prefix$e->{NAME}));";
693         }
694 }
695
696 #####################################################################
697 # print scalars in a structure element
698 sub ParseElementPrint($$)
699 {
700         my($e) = shift;
701         my($var_prefix) = shift;
702         my $cprefix = c_push_prefix($e);
703         my $ptr_prefix = c_ptr_prefix($e);
704
705         return if (util::has_property($e, "noprint"));
706
707         if (my $value = util::has_property($e, "value")) {
708                 pidl "if (ndr->flags & LIBNDR_PRINT_SET_VALUES) {";
709                 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;";
710                 pidl "}";
711         }
712
713         my $l = $e->{POINTERS};
714         $l++ if (util::array_size($e) and $l == 0 and !Ndr::is_fixed_array($e));
715
716         foreach my $i (1..$l) {
717                 pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});";
718                 pidl "ndr->depth++;";
719                 if ($i > $l-Ndr::need_wire_pointer($e)) {
720                         pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {";
721                         indent;
722                 }
723         }
724
725         if (util::array_size($e)) {
726                 ParseArrayPrint($e, $var_prefix)
727         } else {
728                 if (my $switch = util::has_property($e, "switch_is")) {
729                         my $switch_var = ParseExpr($e, $switch, $var_prefix);
730                         check_null_pointer_void($switch_var);
731
732                         pidl "ndr_print_set_switch_value(ndr, $cprefix$var_prefix$e->{NAME}, $switch_var);";
733                 }
734
735                 pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});";
736         }
737
738         foreach my $i (1..$l) {
739                 if ($i > $l-Ndr::need_wire_pointer($e)) {
740                         deindent;
741                         pidl "}";
742                 }
743                 pidl "ndr->depth--;";
744         }
745 }
746
747 #####################################################################
748 # parse scalars in a structure element - pull size
749 sub ParseSwitchPull($$$$$)
750 {
751         my($e) = shift;
752         my $ndr = shift;
753         my($var_prefix) = shift;
754         my($ndr_flags) = shift;
755         my $switch = shift;
756         my $switch_var = ParseExpr($e, $switch, $var_prefix);
757
758         my $cprefix = c_pull_prefix($e);
759
760         my $utype = typelist::getType($e->{TYPE});
761
762         check_null_pointer($switch_var);
763
764         pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));";
765
766 }
767
768 #####################################################################
769 # push switch element
770 sub ParseSwitchPush($$$$$)
771 {
772         my($e) = shift;
773         my $ndr = shift;
774         my($var_prefix) = shift;
775         my($ndr_flags) = shift;
776         my $switch = shift;
777         my $switch_var = ParseExpr($e, $switch, $var_prefix);
778         my $cprefix = c_push_prefix($e);
779
780         check_null_pointer($switch_var);
781
782         pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));";
783
784 }
785
786 #####################################################################
787 # parse scalars in a structure element - pull size
788 sub ParseElementPullScalar($$$)
789 {
790         my($e) = shift;
791         my($var_prefix) = shift;
792         my($ndr_flags) = shift;
793         my $cprefix = c_pull_prefix($e);
794         my $ptr_prefix = c_ptr_prefix($e);
795         my $sub_size = util::has_property($e, "subcontext");
796         my $ndr = "ndr";
797         my $subndr = undef;
798
799         start_flags($e);
800
801         if (defined $sub_size && $e->{POINTERS} == 0) {
802                 $subndr = ParseSubcontextPullStart($e, $ndr_flags);
803                 $ndr = $subndr;
804                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
805         }
806
807         if (Ndr::is_inline_array($e)) {
808                 ParseArrayPull($e, $ndr, "r->", "NDR_SCALARS");
809         } elsif (Ndr::need_wire_pointer($e)) {
810                 ParsePtrPull($e, $ptr_prefix.$var_prefix);
811         } elsif (Ndr::is_surrounding_array($e)) {
812         } else {
813                 if (my $switch = util::has_property($e, "switch_is")) {
814                         ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
815                 }
816
817                 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
818         }
819
820         if (my $range = util::has_property($e, "range")) {
821                 my ($low, $high) = split(/ /, $range, 2);
822                 pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {";
823                 pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
824                 pidl "}";
825         }
826
827         if (defined $sub_size && $e->{POINTERS} == 0) {
828                 ParseSubcontextPullEnd($e);
829         }
830
831         end_flags($e);
832 }
833
834 #####################################################################
835 # parse a pointer in a struct element or function
836 sub ParsePtrPull($$)
837 {
838         my($e) = shift;
839         my($var_prefix) = shift;
840
841         if (util::has_property($e, "ref")) {
842                 pidl "NDR_CHECK(ndr_pull_ref_ptr(ndr, &_ptr_$e->{NAME}));";
843         } else {
844                 pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
845         }
846         pidl "if (_ptr_$e->{NAME}) {";
847         indent;
848         pidl "NDR_ALLOC(ndr, $var_prefix$e->{NAME});";
849         if (util::has_property($e, "relative")) {
850                 pidl "NDR_CHECK(ndr_pull_relative_ptr1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));";
851         }
852         deindent;
853         pidl "} else {";
854         pidl "\t$var_prefix$e->{NAME} = NULL;";
855         pidl "}";
856 }
857
858 #####################################################################
859 # parse buffers in a structure element
860 sub ParseElementPushBuffer($$)
861 {
862         my($e) = shift;
863         my($var_prefix) = shift;
864         my $cprefix = c_push_prefix($e);
865         my $sub_size = util::has_property($e, "subcontext");
866         my $ndr = "ndr";
867         my $subndr = undef;
868
869         return unless (need_buffers_section($e));
870
871         start_flags($e);
872
873         my $pointers = c_ptr_prefix($e);
874         for my $i (1..Ndr::need_wire_pointer($e)) {
875                 if ($i > 1) {
876                         ParsePtrPush($e,$pointers.$var_prefix);
877                 }
878                 pidl "if ($pointers$var_prefix$e->{NAME}) {";
879                 indent;
880                 $pointers.="*";
881         }
882         
883         if (util::has_property($e, "relative")) {
884                 pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
885         }
886
887         my $ndr_flags = "NDR_BUFFERS";
888         if ($e->{POINTERS} || (util::array_size($e) && !Ndr::is_inline_array($e)))
889         {
890                 $ndr_flags="NDR_SCALARS|$ndr_flags" 
891         }
892
893         if (defined $sub_size) {
894                 $subndr = ParseSubcontextPushStart($e, $ndr_flags);
895                 $ndr = $subndr;
896                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
897         }
898
899         if (util::array_size($e)) {
900                 ParseArrayPush($e, $ndr, "r->", $ndr_flags);
901         } else {
902                 if (my $switch = util::has_property($e, "switch_is")) {
903                         ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
904                 }
905
906                 pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
907         }
908
909         if (defined $sub_size) {
910                 ParseSubcontextPushEnd($e);
911         }
912
913         for my $i (1..Ndr::need_wire_pointer($e)) {
914                 deindent;
915                 pidl "}";
916         }
917
918         end_flags($e);
919 }
920
921 #####################################################################
922 # parse buffers in a structure element - pull side
923 sub ParseElementPullBuffer($$)
924 {
925         my($e) = shift;
926         my($var_prefix) = shift;
927         my $cprefix = c_pull_prefix($e);
928         my $sub_size = util::has_property($e, "subcontext");
929         my $ndr = "ndr";
930         my $subndr = undef;
931
932         return unless (need_buffers_section($e));
933
934         start_flags($e);
935
936         my $pointers = c_ptr_prefix($e);
937         for my $i (1..Ndr::need_wire_pointer($e)) {
938                 if ($i > 1) {
939                         ParsePtrPull($e,$pointers.$var_prefix);
940                 }
941                 pidl "if ($pointers$var_prefix$e->{NAME}) {";
942                 indent;
943                 $pointers.="*";
944         }
945  
946         if (util::has_property($e, "relative")) {
947                 pidl "struct ndr_pull_save _relative_save;";
948                 pidl "ndr_pull_save(ndr, &_relative_save);";
949                 pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
950         }
951
952         my $ndr_flags = "NDR_BUFFERS";
953         if ($e->{POINTERS} || (util::array_size($e) && !Ndr::is_inline_array($e)))
954         {
955                 $ndr_flags="NDR_SCALARS|$ndr_flags" 
956         }
957
958         if (defined $sub_size) {
959                 $subndr = ParseSubcontextPullStart($e, $ndr_flags);
960                 $ndr = $subndr;
961                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
962         }
963
964         if (util::array_size($e)) {
965                 ParseArrayPull($e, $ndr, "r->", $ndr_flags);
966         } else {
967                 if (my $switch = util::has_property($e, "switch_is")) {
968                         ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
969                 }
970
971                 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
972         }
973
974         if (defined $sub_size) {
975                 ParseSubcontextPullEnd($e);
976         }
977
978         if (util::has_property($e, "relative")) {
979                 pidl "ndr_pull_restore(ndr, &_relative_save);";
980         }
981
982         for my $i (1..Ndr::need_wire_pointer($e)) {
983                 deindent;
984                 pidl "}";
985         }
986
987         end_flags($e);
988 }
989
990 #####################################################################
991 # parse a struct
992 sub ParseStructPush($)
993 {
994         my($struct) = shift;
995         
996         return unless defined($struct->{ELEMENTS});
997
998         start_flags($struct);
999
1000         # see if the structure contains a conformant array. If it
1001         # does, then it must be the last element of the structure, and
1002         # we need to push the conformant length early, as it fits on
1003         # the wire before the structure (and even before the structure
1004         # alignment)
1005         my $e = $struct->{ELEMENTS}[-1];
1006         if (Ndr::is_conformant_array($e) and Ndr::is_surrounding_array($e)) {
1007                 ParseArrayPushPreceding($e, "r->", "NDR_SCALARS");
1008         }
1009
1010         if (defined $e->{TYPE} && $e->{TYPE} eq "string" 
1011             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1012                 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
1013         }
1014
1015         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1016
1017         pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1018
1019         my $align = Ndr::find_largest_alignment($struct);
1020         pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1021
1022         foreach my $e (@{$struct->{ELEMENTS}}) {
1023                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
1024         }       
1025
1026         pidl "buffers:";
1027         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1028         foreach my $e (@{$struct->{ELEMENTS}}) {
1029                 ParseElementPushBuffer($e, "r->");
1030         }
1031
1032         pidl "ndr_push_struct_end(ndr);";
1033
1034         pidl "done:";
1035
1036         end_flags($struct);
1037 }
1038
1039 #####################################################################
1040 # generate a push function for an enum
1041 sub ParseEnumPush($)
1042 {
1043         my($enum) = shift;
1044         my($type_fn) = typelist::enum_type_fn($enum);
1045
1046         start_flags($enum);
1047
1048         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1049
1050         end_flags($enum);
1051 }
1052
1053 #####################################################################
1054 # generate a pull function for an enum
1055 sub ParseEnumPull($)
1056 {
1057         my($enum) = shift;
1058         my($type_fn) = typelist::enum_type_fn($enum);
1059         my($type_v_decl) = typelist::mapScalarType(typelist::enum_type_fn($enum));
1060
1061         pidl "$type_v_decl v;";
1062         start_flags($enum);
1063         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1064         pidl "*r = v;";
1065
1066         end_flags($enum);
1067 }
1068
1069 #####################################################################
1070 # generate a print function for an enum
1071 sub ParseEnumPrint($)
1072 {
1073         my($enum) = shift;
1074
1075         pidl "const char *val = NULL;";
1076         pidl "";
1077
1078         start_flags($enum);
1079
1080         pidl "switch (r) {";
1081         indent;
1082         my $els = \@{$enum->{ELEMENTS}};
1083         foreach my $i (0 .. $#{$els}) {
1084                 my $e = ${$els}[$i];
1085                 chomp $e;
1086                 if ($e =~ /^(.*)=/) {
1087                         $e = $1;
1088                 }
1089                 pidl "case $e: val = \"$e\"; break;";
1090         }
1091
1092         deindent;
1093         pidl "}";
1094         
1095         pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
1096
1097         end_flags($enum);
1098 }
1099
1100 sub ArgsEnumPush($)
1101 {
1102         my $e = shift;
1103         return "struct ndr_push *ndr, int ndr_flags, enum $e->{NAME} r";
1104 }
1105
1106 sub ArgsEnumPrint($)
1107 {
1108         my $e = shift;
1109         return "struct ndr_print *ndr, const char *name, enum $e->{NAME} r";
1110 }
1111
1112 sub ArgsEnumPull($)
1113 {
1114         my $e = shift;
1115         return "struct ndr_pull *ndr, int ndr_flags, enum $e->{NAME} *r";
1116 }
1117
1118 $typefamily{ENUM} = {
1119         PUSH_FN_BODY => \&ParseEnumPush,
1120         PUSH_FN_ARGS => \&ArgsEnumPush,
1121         PULL_FN_BODY => \&ParseEnumPull,
1122         PULL_FN_ARGS => \&ArgsEnumPull,
1123         PRINT_FN_BODY => \&ParseEnumPrint,
1124         PRINT_FN_ARGS => \&ArgsEnumPrint,
1125 };
1126
1127 #####################################################################
1128 # generate a push function for a bitmap
1129 sub ParseBitmapPush($)
1130 {
1131         my($bitmap) = shift;
1132         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1133
1134         start_flags($bitmap);
1135
1136         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1137
1138         end_flags($bitmap);
1139 }
1140
1141 #####################################################################
1142 # generate a pull function for an bitmap
1143 sub ParseBitmapPull($)
1144 {
1145         my($bitmap) = shift;
1146         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1147         my($type_decl) = typelist::mapType($bitmap);
1148
1149         pidl "$type_decl v;";
1150         start_flags($bitmap);
1151         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1152         pidl "*r = v;";
1153
1154         end_flags($bitmap);
1155 }
1156
1157 #####################################################################
1158 # generate a print function for an bitmap
1159 sub ParseBitmapPrintElement($$)
1160 {
1161         my($e) = shift;
1162         my($bitmap) = shift;
1163         my($type_decl) = typelist::mapType($bitmap);
1164         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1165         my($name) = $bitmap->{PARENT}->{NAME};
1166         my($flag);
1167
1168         if ($e =~ /^(\w+) .*$/) {
1169                 $flag = "$1";
1170         } else {
1171                 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1172         }
1173
1174         pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
1175 }
1176
1177 #####################################################################
1178 # generate a print function for an bitmap
1179 sub ParseBitmapPrint($)
1180 {
1181         my($bitmap) = shift;
1182         my($type_decl) = typelist::mapType($bitmap);
1183         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1184
1185         start_flags($bitmap);
1186
1187         pidl "ndr_print_$type_fn(ndr, name, r);";
1188
1189         pidl "ndr->depth++;";
1190         foreach my $e (@{$bitmap->{ELEMENTS}}) {
1191                 ParseBitmapPrintElement($e, $bitmap);
1192         }
1193         pidl "ndr->depth--;";
1194
1195         end_flags($bitmap);
1196 }
1197
1198 sub ArgsBitmapPush($)
1199 {
1200         my $e = shift;
1201         my $type_decl = typelist::mapType($e->{DATA});
1202         return "struct ndr_push *ndr, int ndr_flags, $type_decl r";
1203 }
1204
1205 sub ArgsBitmapPrint($)
1206 {
1207         my $e = shift;
1208         my $type_decl = typelist::mapType($e->{DATA});
1209         return "struct ndr_print *ndr, const char *name, $type_decl r";
1210 }
1211
1212 sub ArgsBitmapPull($)
1213 {
1214         my $e = shift;
1215         my $type_decl = typelist::mapType($e->{DATA});
1216         return "struct ndr_pull *ndr, int ndr_flags, $type_decl *r";
1217 }
1218
1219 $typefamily{BITMAP} = {
1220         PUSH_FN_BODY => \&ParseBitmapPush,
1221         PUSH_FN_ARGS => \&ArgsBitmapPush,
1222         PULL_FN_BODY => \&ParseBitmapPull,
1223         PULL_FN_ARGS => \&ArgsBitmapPull,
1224         PRINT_FN_BODY => \&ParseBitmapPrint,
1225         PRINT_FN_ARGS => \&ArgsBitmapPrint,
1226 };
1227
1228 #####################################################################
1229 # generate a struct print function
1230 sub ParseStructPrint($)
1231 {
1232         my($struct) = shift;
1233         my($name) = $struct->{PARENT}->{NAME};
1234
1235         return unless defined $struct->{ELEMENTS};
1236
1237         pidl "ndr_print_struct(ndr, name, \"$name\");";
1238
1239         start_flags($struct);
1240
1241         pidl "ndr->depth++;";
1242         foreach my $e (@{$struct->{ELEMENTS}}) {
1243                 ParseElementPrint($e, "r->");
1244         }
1245         pidl "ndr->depth--;";
1246
1247         end_flags($struct);
1248 }
1249
1250 #####################################################################
1251 # parse a struct - pull side
1252 sub ParseStructPull($)
1253 {
1254         my($struct) = shift;
1255         my $conform_e;
1256
1257         return unless defined $struct->{ELEMENTS};
1258
1259         # see if the structure contains a conformant array. If it
1260         # does, then it must be the last element of the structure, and
1261         # we need to pull the conformant length early, as it fits on
1262         # the wire before the structure (and even before the structure
1263         # alignment)
1264         my $e = $struct->{ELEMENTS}[-1];
1265         if (Ndr::is_conformant_array($e) and Ndr::is_surrounding_array($e)) {
1266                 $conform_e = $e;
1267         }
1268
1269         if (defined $e->{TYPE} && $e->{TYPE} eq "string"
1270             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1271                 $conform_e = $e;
1272         }
1273
1274         # declare any internal pointers we need
1275         foreach my $e (@{$struct->{ELEMENTS}}) {
1276                 if (Ndr::need_wire_pointer($e)) {
1277                         pidl "uint32_t _ptr_$e->{NAME};";
1278                 }
1279         }
1280
1281         start_flags($struct);
1282
1283         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1284
1285         pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1286
1287         if (defined $conform_e) {
1288                 ParseArrayPullPreceding($conform_e, "r->", "NDR_SCALARS");
1289         }
1290
1291         my $align = Ndr::find_largest_alignment($struct);
1292         pidl "NDR_CHECK(ndr_pull_align(ndr, $align));";
1293
1294         foreach my $e (@{$struct->{ELEMENTS}}) {
1295                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
1296         }       
1297
1298         pidl "buffers:\n";
1299         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1300         foreach my $e (@{$struct->{ELEMENTS}}) {
1301                 ParseElementPullBuffer($e, "r->");
1302         }
1303
1304         foreach my $e (@{$struct->{ELEMENTS}}) {
1305                 CheckArraySizes($e, "r->");
1306         }
1307
1308         pidl "ndr_pull_struct_end(ndr);";
1309
1310         pidl "done:";
1311
1312         end_flags($struct);
1313 }
1314
1315 #####################################################################
1316 # calculate size of ndr struct
1317 sub ParseStructNdrSize($)
1318 {
1319         my $t = shift;
1320         my $static = fn_prefix($t);
1321         my $sizevar;
1322
1323         if (my $flags = util::has_property($t, "flag")) {
1324                 pidl "flags |= $flags;";
1325         }
1326         pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1327 }
1328
1329 sub ArgsStructPush($)
1330 {
1331         my $e = shift;
1332         return "struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r";
1333 }
1334
1335 sub ArgsStructPrint($)
1336 {
1337         my $e = shift;
1338         return "struct ndr_print *ndr, const char *name, struct $e->{NAME} *r";
1339 }
1340
1341 sub ArgsStructPull($)
1342 {
1343         my $e = shift;
1344         return "struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r";
1345 }
1346
1347 sub ArgsStructNdrSize($)
1348 {
1349         my $d = shift;
1350         return "const struct $d->{NAME} *r, int flags";
1351 }
1352
1353 $typefamily{STRUCT} = {
1354         PUSH_FN_BODY => \&ParseStructPush,
1355         PUSH_FN_ARGS => \&ArgsStructPush,
1356         PULL_FN_BODY => \&ParseStructPull,
1357         PULL_FN_ARGS => \&ArgsStructPull,
1358         PRINT_FN_BODY => \&ParseStructPrint,
1359         PRINT_FN_ARGS => \&ArgsStructPrint,
1360         SIZE_FN_BODY => \&ParseStructNdrSize,
1361         SIZE_FN_ARGS => \&ArgsStructNdrSize,
1362 };
1363
1364 #####################################################################
1365 # calculate size of ndr struct
1366 sub ParseUnionNdrSize($)
1367 {
1368         my $t = shift;
1369         my $static = fn_prefix($t);
1370         my $sizevar;
1371
1372         if (my $flags = util::has_property($t, "flag")) {
1373                 pidl "flags |= $flags;";
1374         }
1375
1376         pidl "return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1377 }
1378
1379 #####################################################################
1380 # parse a union - push side
1381 sub ParseUnionPush($)
1382 {
1383         my $e = shift;
1384         my $have_default = 0;
1385
1386         pidl "int level;";
1387
1388         start_flags($e);
1389
1390         pidl "level = ndr_push_get_switch_value(ndr, r);";
1391
1392         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1393
1394         if (!util::has_property($e, "nodiscriminant")) {
1395                 my $switch_type = util::has_property($e, "switch_type");
1396                 $switch_type = "uint32" unless  (defined ($switch_type));
1397                 pidl "NDR_CHECK(ndr_push_$switch_type(ndr, NDR_SCALARS, level));";
1398         }
1399
1400         pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1401
1402 #       my $align = union_alignment($e);
1403 #       pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1404
1405         pidl "switch (level) {";
1406         indent;
1407         foreach my $el (@{$e->{ELEMENTS}}) {
1408                 if (util::has_property($el, "default")) {
1409                         pidl "default:";
1410                         $have_default = 1;
1411                 } else {
1412                         pidl "case $el->{PROPERTIES}->{case}:";
1413
1414                 }
1415                 if ($el->{TYPE} ne "EMPTY") {
1416                         indent;
1417                         ParseElementPushScalar($el, "r->", "NDR_SCALARS");
1418                         deindent;
1419                 }
1420                 pidl "break;";
1421                 pidl "";
1422         }
1423         if (! $have_default) {
1424                 pidl "default:";
1425                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1426         }
1427         deindent;
1428         pidl "}";
1429         pidl "buffers:";
1430         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1431         pidl "switch (level) {";
1432         indent;
1433         foreach my $el (@{$e->{ELEMENTS}}) {
1434                 if (util::has_property($el, "default")) {
1435                         pidl "default:";
1436                 } else {
1437                         pidl "case $el->{PROPERTIES}->{case}:";
1438                 }
1439                 if ($el->{TYPE} ne "EMPTY") {
1440                         indent;
1441                         ParseElementPushBuffer($el, "r->");
1442                         deindent;
1443                 }
1444                 pidl "break;";
1445                 pidl "";
1446         }
1447         if (! $have_default) {
1448                 pidl "default:";
1449                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1450         }
1451         deindent;
1452         pidl "}";
1453         pidl "ndr_push_struct_end(ndr);";
1454         pidl "done:";
1455         end_flags($e);
1456 }
1457
1458 #####################################################################
1459 # print a union
1460 sub ParseUnionPrint($)
1461 {
1462         my $e = shift;
1463         my $have_default = 0;
1464         my($name) = $e->{PARENT}->{NAME};
1465
1466         pidl "int level = ndr_print_get_switch_value(ndr, r);";
1467
1468         pidl "ndr_print_union(ndr, name, level, \"$name\");";
1469         start_flags($e);
1470
1471         pidl "switch (level) {";
1472         indent;
1473         foreach my $el (@{$e->{ELEMENTS}}) {
1474                 if (util::has_property($el, "default")) {
1475                         $have_default = 1;
1476                         pidl "default:";
1477                 } else {
1478                         pidl "case $el->{PROPERTIES}->{case}:";
1479                 }
1480                 if ($el->{TYPE} ne "EMPTY") {
1481                         indent;
1482                         ParseElementPrint($el, "r->");
1483                         deindent;
1484                 }
1485                 pidl "break;";
1486                 pidl "";
1487         }
1488         if (! $have_default) {
1489                 pidl "default:";
1490                 pidl "\tndr_print_bad_level(ndr, name, level);";
1491         }
1492         deindent;
1493         pidl "}";
1494
1495         end_flags($e);
1496 }
1497
1498 #####################################################################
1499 # parse a union - pull side
1500 sub ParseUnionPull($)
1501 {
1502         my $e = shift;
1503         my $have_default = 0;
1504         my $switch_type = util::has_property($e, "switch_type");
1505         $switch_type = "uint32" unless defined($switch_type);
1506
1507         pidl "int level;";
1508         if (!util::has_property($e, "nodiscriminant")) {
1509                 if (typelist::typeIs($switch_type, "ENUM")) {
1510                         $switch_type = typelist::enum_type_fn(typelist::getType($switch_type));
1511                 }
1512                 pidl typelist::mapScalarType($switch_type) . " _level;";
1513         }
1514
1515         start_flags($e);
1516
1517         pidl "level = ndr_pull_get_switch_value(ndr, r);";
1518
1519         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1520
1521         if (!util::has_property($e, "nodiscriminant")) {
1522                 pidl "NDR_CHECK(ndr_pull_$switch_type(ndr, NDR_SCALARS, &_level));";
1523                 pidl "if (_level != level) {"; 
1524                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $e->{PARENT}->{NAME}\", _level);";
1525                 pidl "}";
1526         }
1527
1528         pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1529
1530 #       my $align = union_alignment($e);
1531 #       pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1532
1533         pidl "switch (level) {";
1534         indent;
1535         foreach my $el (@{$e->{ELEMENTS}}) {
1536                 if (util::has_property($el, "default")) {
1537                         pidl "default: {";
1538                         $have_default = 1;
1539                 } else {
1540                         pidl "case $el->{PROPERTIES}->{case}: {";
1541                 }
1542                 if ($el->{TYPE} ne "EMPTY") {
1543                         indent;
1544                         if ($el->{POINTERS}) {
1545                                 pidl "uint32_t _ptr_$el->{NAME};";
1546                         }
1547                         ParseElementPullScalar($el, "r->", "NDR_SCALARS");
1548                         deindent;
1549                 }
1550                 pidl "break; }";
1551                 pidl "";
1552         }
1553         if (! $have_default) {
1554                 pidl "default:";
1555                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1556         }
1557         deindent;
1558         pidl "}";
1559         pidl "buffers:";
1560         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1561         pidl "switch (level) {";
1562         indent;
1563         foreach my $el (@{$e->{ELEMENTS}}) {
1564                 if (util::has_property($el, "default")) {
1565                         pidl "default:";
1566                 } else {
1567                         pidl "case $el->{PROPERTIES}->{case}:";
1568                 }
1569                 if ($el->{TYPE} ne "EMPTY") {
1570                         indent;
1571                         ParseElementPullBuffer($el, "r->");
1572                         deindent;
1573                 }
1574                 pidl "break;";
1575                 pidl "";
1576         }
1577         if (! $have_default) {
1578                 pidl "default:";
1579                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1580         }
1581         deindent;
1582         pidl "}";
1583         pidl "ndr_pull_struct_end(ndr);";
1584         pidl "done:";
1585         end_flags($e);
1586 }
1587
1588 sub ArgsUnionPush($)
1589 {
1590         my $e = shift;
1591         return "struct ndr_push *ndr, int ndr_flags, union $e->{NAME} *r";
1592 }
1593
1594 sub ArgsUnionPrint($)
1595 {
1596         my $e = shift;
1597         return "struct ndr_print *ndr, const char *name, union $e->{NAME} *r";
1598 }
1599
1600 sub ArgsUnionPull($)
1601 {
1602         my $e = shift;
1603         return "struct ndr_pull *ndr, int ndr_flags, union $e->{NAME} *r";
1604 }
1605
1606 sub ArgsUnionNdrSize($)
1607 {
1608         my $d = shift;
1609         return "const union $d->{NAME} *r, uint32_t level, int flags";
1610 }
1611
1612 $typefamily{UNION} = {
1613         PUSH_FN_BODY => \&ParseUnionPush,
1614         PUSH_FN_ARGS => \&ArgsUnionPush,
1615         PULL_FN_BODY => \&ParseUnionPull,
1616         PULL_FN_ARGS => \&ArgsUnionPull,
1617         PRINT_FN_BODY => \&ParseUnionPrint,
1618         PRINT_FN_ARGS => \&ArgsUnionPrint,
1619         SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1620         SIZE_FN_BODY => \&ParseUnionNdrSize,
1621 };
1622         
1623 #####################################################################
1624 # parse a typedef - push side
1625 sub ParseTypedefPush($)
1626 {
1627         my($e) = shift;
1628         my $static = fn_prefix($e);
1629
1630         return unless needed::is_needed("push_$e->{NAME}");
1631
1632         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_ARGS}->($e);
1633         pidl $static . "NTSTATUS ndr_push_$e->{NAME}($args)";
1634
1635         pidl "{";
1636         indent;
1637         $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA});
1638         pidl "return NT_STATUS_OK;";
1639         deindent;
1640         pidl "}";
1641         pidl "";;
1642 }
1643
1644
1645 #####################################################################
1646 # parse a typedef - pull side
1647 sub ParseTypedefPull($)
1648 {
1649         my($e) = shift;
1650         my $static = fn_prefix($e);
1651
1652         return unless needed::is_needed("pull_$e->{NAME}");
1653
1654         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_ARGS}->($e);
1655
1656         pidl $static . "NTSTATUS ndr_pull_$e->{NAME}($args)";
1657
1658         pidl "{";
1659         indent;
1660         $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA});
1661         pidl "return NT_STATUS_OK;";
1662         deindent;
1663         pidl "}";
1664         pidl "";
1665 }
1666
1667 #####################################################################
1668 # parse a typedef - print side
1669 sub ParseTypedefPrint($)
1670 {
1671         my($e) = shift;
1672
1673         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_ARGS}->($e);
1674
1675         return unless !util::has_property($e, "noprint");
1676
1677         pidl "void ndr_print_$e->{NAME}($args)";
1678         pidl "{";
1679         indent;
1680         $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA});
1681         deindent;
1682         pidl "}";
1683         pidl "";
1684 }
1685
1686 #####################################################################
1687 ## calculate the size of a structure
1688 sub ParseTypedefNdrSize($)
1689 {
1690         my($t) = shift;
1691
1692         return unless needed::is_needed("ndr_size_$t->{NAME}");
1693
1694         my $tf = $typefamily{$t->{DATA}->{TYPE}};
1695         my $args = $tf->{SIZE_FN_ARGS}->($t);
1696
1697         pidl "size_t ndr_size_$t->{NAME}($args)";
1698         pidl "{";
1699         indent;
1700         $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
1701         deindent;
1702         pidl "}";
1703         pidl "";
1704 }
1705
1706 #####################################################################
1707 # parse a function - print side
1708 sub ParseFunctionPrint($)
1709 {
1710         my($fn) = shift;
1711
1712         return unless !util::has_property($fn, "noprint");
1713
1714         pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)";
1715         pidl "{";
1716         indent;
1717         pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
1718         pidl "ndr->depth++;";
1719
1720         pidl "if (flags & NDR_SET_VALUES) {";
1721         pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
1722         pidl "}";
1723
1724         pidl "if (flags & NDR_IN) {";
1725         indent;
1726         pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
1727         pidl "ndr->depth++;";
1728
1729         foreach my $e (@{$fn->{ELEMENTS}}) {
1730                 if (util::has_property($e, "in")) {
1731                         ParseElementPrint($e, "r->in.");
1732                 }
1733         }
1734         pidl "ndr->depth--;";
1735         deindent;
1736         pidl "}";
1737         
1738         pidl "if (flags & NDR_OUT) {";
1739         indent;
1740         pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
1741         pidl "ndr->depth++;";
1742         foreach my $e (@{$fn->{ELEMENTS}}) {
1743                 if (util::has_property($e, "out")) {
1744                         ParseElementPrint($e, "r->out.");
1745                 }
1746         }
1747         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1748                 my $cprefix = "&";
1749                 $cprefix = "" if (Ndr::is_scalar_type($fn->{RETURN_TYPE})) ; # FIXME: Should really use util::c_push_prefix here
1750                 pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", $cprefix"."r->out.result);";
1751         }
1752         pidl "ndr->depth--;";
1753         deindent;
1754         pidl "}";
1755         
1756         pidl "ndr->depth--;";
1757         deindent;
1758         pidl "}";
1759         pidl "";
1760 }
1761
1762 #####################################################################
1763 # parse a function element
1764 sub ParseFunctionElementPush($$)
1765
1766         my $e = shift;
1767         my $inout = shift;
1768
1769         if (util::array_size($e)) {
1770                 if (Ndr::need_wire_pointer($e)) {
1771                         ParsePtrPush($e, "r->$inout.");
1772                         pidl "if (r->$inout.$e->{NAME}) {";
1773                         indent;
1774                         ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1775                         deindent;
1776                         pidl "}";
1777                 } else {
1778                         ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1779                 }
1780         } else {
1781                 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1782                 if (Ndr::need_wire_pointer($e)) {
1783                         ParseElementPushBuffer($e, "r->$inout.");
1784                 }
1785         }
1786 }       
1787
1788 #####################################################################
1789 # parse a function
1790 sub ParseFunctionPush($)
1791
1792         my($fn) = shift;
1793         my $static = fn_prefix($fn);
1794
1795         return unless !util::has_property($fn, "nopush");
1796
1797         pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)";
1798         pidl "{";
1799         indent;
1800
1801         pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1802         pidl "";
1803
1804         foreach my $e (@{$fn->{ELEMENTS}}) {
1805                 if (util::has_property($e, "in")) {
1806                         if (util::has_property($e, "ref")) {
1807                                 check_null_pointer("*r->in.$e->{NAME}");
1808                         } 
1809                         ParseFunctionElementPush($e, "in");
1810                 }               
1811         }
1812
1813         pidl "ndr_out:";
1814         pidl "if (!(flags & NDR_OUT)) goto done;";
1815         pidl "";
1816
1817         foreach my $e (@{$fn->{ELEMENTS}}) {
1818                 if (util::has_property($e, "out")) {
1819                         if (util::has_property($e, "ref")) {
1820                                 check_null_pointer("*r->out.$e->{NAME}");
1821                         } 
1822                         ParseFunctionElementPush($e, "out");
1823                 }               
1824         }
1825
1826         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1827                 pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
1828         }
1829     
1830         pidl "done:";
1831         pidl "return NT_STATUS_OK;";
1832         deindent;
1833         pidl "}";
1834         pidl "";
1835 }
1836
1837 #####################################################################
1838 # parse a function element
1839 sub ParseFunctionElementPull($$)
1840
1841         my $e = shift;
1842         my $inout = shift;
1843
1844         if (util::array_size($e)) {
1845                 if (Ndr::need_wire_pointer($e)) {
1846                         pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
1847                         pidl "r->$inout.$e->{NAME} = NULL;";
1848                         pidl "if (_ptr_$e->{NAME}) {";
1849                         indent;
1850                 } elsif ($inout eq "out" && util::has_property($e, "ref")) {
1851                         pidl "if (r->$inout.$e->{NAME}) {";
1852                         indent;
1853                 }
1854
1855                 ParseArrayPull($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1856
1857                 if (Ndr::need_wire_pointer($e) or ($inout eq "out" and util::has_property($e, "ref"))) {
1858                         deindent;
1859                         pidl "}";
1860                 }
1861         } else {
1862                 if ($inout eq "out" && util::has_property($e, "ref")) {
1863                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
1864                         pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});";
1865                         pidl "}";
1866                 }
1867
1868                 if ($inout eq "in" && util::has_property($e, "ref")) {
1869                         pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});";
1870                 }
1871
1872                 ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1873                 if (Ndr::need_wire_pointer($e)) {
1874                         ParseElementPullBuffer($e, "r->$inout.");
1875                 }
1876         }
1877 }
1878
1879 ############################################################
1880 # allocate ref variables
1881 sub AllocateRefVars($)
1882 {
1883         my $e = shift;
1884         my $asize = util::array_size($e);
1885
1886         # note that if the variable is also an "in"
1887         # variable then we copy the initial value from
1888         # the in side
1889
1890         if (!defined $asize) {
1891                 # its a simple variable
1892                 pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});";
1893                 if (util::has_property($e, "in")) {
1894                         pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
1895                 } else {
1896                         pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
1897                 }
1898                 return;
1899         }
1900
1901         # its an array
1902         my $size = ParseExpr($e, $asize, "r->out.");
1903         check_null_pointer($size);
1904         pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
1905         if (util::has_property($e, "in")) {
1906                 pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));";
1907         } else {
1908                 pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
1909         }
1910 }
1911
1912 #####################################################################
1913 # parse a function
1914 sub ParseFunctionPull($)
1915
1916         my($fn) = shift;
1917         my $static = fn_prefix($fn);
1918
1919         return unless !util::has_property($fn, "nopull");
1920
1921         # pull function args
1922         pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)";
1923         pidl "{";
1924         indent;
1925
1926         # declare any internal pointers we need
1927         foreach my $e (@{$fn->{ELEMENTS}}) {
1928                 if (Ndr::need_wire_pointer($e)) {
1929                         pidl "uint32_t _ptr_$e->{NAME};";
1930                 }
1931         }
1932
1933         pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1934         pidl "";
1935
1936         # auto-init the out section of a structure. I originally argued that
1937         # this was a bad idea as it hides bugs, but coping correctly
1938         # with initialisation and not wiping ref vars is turning
1939         # out to be too tricky (tridge)
1940         foreach my $e (@{$fn->{ELEMENTS}}) {
1941                 if (util::has_property($e, "out")) {
1942                         pidl "ZERO_STRUCT(r->out);";
1943                         pidl "";
1944                         last;
1945                 }
1946         }
1947
1948         foreach my $e (@{$fn->{ELEMENTS}}) {
1949                 if (util::has_property($e, "in")) {
1950                         ParseFunctionElementPull($e, "in");
1951                 }
1952                 # we need to allocate any reference output variables, so that
1953                 # a dcerpc backend can be sure they are non-null
1954                 if (util::has_property($e, "out") && util::has_property($e, "ref")) {
1955                         AllocateRefVars($e);
1956                 }
1957         }
1958
1959         foreach my $e (@{$fn->{ELEMENTS}}) {
1960                 if (util::has_property($e, "in")) {
1961                         CheckArraySizes($e, "r->in.");
1962                 }
1963         }
1964
1965         pidl "ndr_out:";
1966         pidl "if (!(flags & NDR_OUT)) goto done;";
1967         pidl "";
1968
1969         foreach my $e (@{$fn->{ELEMENTS}}) {
1970                 if (util::has_property($e, "out")) {
1971                         ParseFunctionElementPull($e, "out");
1972                 }
1973         }
1974
1975         foreach my $e (@{$fn->{ELEMENTS}}) {
1976                 if (util::has_property($e, "out")) {
1977                         CheckArraySizes($e, "r->out.");
1978                 }
1979         }
1980
1981         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1982                 pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
1983         }
1984
1985         pidl "done:";
1986         pidl "";
1987         pidl "return NT_STATUS_OK;";
1988         deindent;
1989         pidl "}";
1990         pidl "";
1991 }
1992
1993 #####################################################################
1994 # produce a function call table
1995 sub FunctionTable($)
1996 {
1997         my($interface) = shift;
1998         my($data) = $interface->{INHERITED_DATA};
1999         my $count = 0;
2000         my $uname = uc $interface->{NAME};
2001
2002         foreach my $d (@{$data}) {
2003                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
2004         }
2005
2006         return if ($count == 0);
2007
2008         pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
2009         foreach my $d (@{$data}) {
2010                 if ($d->{TYPE} eq "FUNCTION") {
2011                         pidl "\t{";
2012                         pidl "\t\t\"$d->{NAME}\",";
2013                         pidl "\t\tsizeof(struct $d->{NAME}),";
2014                         pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
2015                         pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
2016                         pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}";
2017                         pidl "\t},";
2018                 }
2019         }
2020         pidl "\t{ NULL, 0, NULL, NULL, NULL }";
2021         pidl "};";
2022         pidl "";
2023
2024         # If no endpoint is set, default to the interface name as a named pipe
2025         if (! defined $interface->{PROPERTIES}->{endpoint}) {
2026                 $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\"";
2027         }
2028
2029         my @e = split / /, $interface->{PROPERTIES}->{endpoint};
2030         my $endpoint_count = $#e + 1;
2031
2032         pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
2033         foreach my $ep (@e) {
2034                 pidl "\t$ep, ";
2035         }
2036         pidl "};";
2037         pidl "";
2038
2039         pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
2040         pidl "\t.count\t= $endpoint_count,";
2041         pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
2042         pidl "};";
2043         pidl "";
2044
2045         if (! defined $interface->{PROPERTIES}->{authservice}) {
2046                 $interface->{PROPERTIES}->{authservice} = "\"host\"";
2047         }
2048
2049         my @a = split / /, $interface->{PROPERTIES}->{authservice};
2050         my $authservice_count = $#a + 1;
2051
2052         pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
2053         foreach my $ap (@a) {
2054                 pidl "\t$ap, ";
2055         }
2056         pidl "};";
2057         pidl "";
2058
2059         pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
2060         pidl "\t.count\t= $endpoint_count,";
2061         pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
2062         pidl "};";
2063         pidl "";
2064
2065         pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
2066         pidl "\t.name\t\t= \"$interface->{NAME}\",";
2067         pidl "\t.uuid\t\t= DCERPC_$uname\_UUID,";
2068         pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
2069         pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
2070         pidl "\t.num_calls\t= $count,";
2071         pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
2072         pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
2073         pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
2074         pidl "};";
2075         pidl "";
2076
2077         pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)";
2078         pidl "{";
2079         pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});";
2080         pidl "}";
2081         pidl "";
2082 }
2083
2084 #####################################################################
2085 # parse the interface definitions
2086 sub ParseInterface($)
2087 {
2088         my($interface) = shift;
2089         my($data) = $interface->{DATA};
2090
2091         # Push functions
2092         foreach my $d (@{$data}) {
2093                 if ($d->{TYPE} eq "TYPEDEF") {
2094                     ParseTypedefPush($d);
2095                     ParseTypedefPull($d);
2096                         ParseTypedefPrint($d);
2097                         ParseTypedefNdrSize($d);
2098                 }
2099         }
2100
2101         foreach my $d (@{$data}) {
2102                 if ($d->{TYPE} eq "FUNCTION") {
2103                     ParseFunctionPush($d);
2104                     ParseFunctionPull($d);
2105                         ParseFunctionPrint($d);
2106                 }
2107         }
2108
2109         FunctionTable($interface);
2110 }
2111
2112 sub RegistrationFunction($$)
2113 {
2114         my $idl = shift;
2115         my $filename = shift;
2116
2117         $filename =~ /.*\/ndr_(.*).c/;
2118         my $basename = $1;
2119         pidl "NTSTATUS dcerpc_$basename\_init(void)";
2120         pidl "{";
2121         indent;
2122         pidl "NTSTATUS status = NT_STATUS_OK;";
2123         foreach my $interface (@{$idl}) {
2124                 next if $interface->{TYPE} ne "INTERFACE";
2125
2126                 my $data = $interface->{INHERITED_DATA};
2127                 my $count = 0;
2128                 foreach my $d (@{$data}) {
2129                         if ($d->{TYPE} eq "FUNCTION") { $count++; }
2130                 }
2131
2132                 next if ($count == 0);
2133
2134                 pidl "status = dcerpc_ndr_$interface->{NAME}_init();";
2135                 pidl "if (NT_STATUS_IS_ERR(status)) {";
2136                 pidl "\treturn status;";
2137                 pidl "}";
2138                 pidl "";
2139         }
2140         pidl "return status;";
2141         deindent;
2142         pidl "}";
2143         pidl "";
2144 }
2145
2146 sub CheckPointerTypes($$)
2147 {
2148         my $s = shift;
2149         my $default = shift;
2150
2151         foreach my $e (@{$s->{ELEMENTS}}) {
2152                 if ($e->{POINTERS}) {
2153                         if (not defined(Ndr::pointer_type($e))) {
2154                                 $e->{PROPERTIES}->{$default} = 1;
2155                         }
2156
2157                         if (Ndr::pointer_type($e) eq "ptr") {
2158                                 print "Warning: ptr is not supported by pidl yet\n";
2159                         }
2160                 }
2161         }
2162 }
2163
2164 sub LoadInterface($)
2165 {
2166         my $x = shift;
2167
2168         if (not util::has_property($x, "pointer_default")) {
2169                 # MIDL defaults to "ptr" in DCE compatible mode (/osf)
2170                 # and "unique" in Microsoft Extensions mode (default)
2171                 $x->{PROPERTIES}->{pointer_default} = "unique";
2172         }
2173
2174         foreach my $d (@{$x->{DATA}}) {
2175                 if (($d->{TYPE} eq "DECLARE") or ($d->{TYPE} eq "TYPEDEF")) {
2176                         if ($d->{DATA}->{TYPE} eq "STRUCT" or $d->{DATA}->{TYPE} eq "UNION") {
2177                                 CheckPointerTypes($d->{DATA}, $x->{PROPERTIES}->{pointer_default});
2178                         }
2179
2180                         if (defined($d->{PROPERTIES}) && !defined($d->{DATA}->{PROPERTIES})) {
2181                                 $d->{DATA}->{PROPERTIES} = $d->{PROPERTIES};
2182                         }
2183                 }
2184                 if ($d->{TYPE} eq "FUNCTION") {
2185                         CheckPointerTypes($d, 
2186                                 $x->{PROPERTIES}->{pointer_default}  # MIDL defaults to "ref"
2187                         );
2188                 }
2189         }
2190 }
2191
2192 sub Load($)
2193 {
2194         my $idl = shift;
2195
2196         foreach my $x (@{$idl}) {
2197                 LoadInterface($x);
2198         }
2199 }
2200
2201 #####################################################################
2202 # parse a parsed IDL structure back into an IDL file
2203 sub Parse($$)
2204 {
2205         my($idl) = shift;
2206         my($filename) = shift;
2207         my $h_filename = $filename;
2208         $res = "";
2209
2210         Load($idl);
2211
2212         if ($h_filename =~ /(.*)\.c/) {
2213                 $h_filename = "$1.h";
2214         }
2215
2216         pidl "/* parser auto-generated by pidl */";
2217         pidl "";
2218         pidl "#include \"includes.h\"";
2219         pidl "#include \"$h_filename\"";
2220         pidl "";
2221
2222         foreach my $x (@{$idl}) {
2223                 if ($x->{TYPE} eq "INTERFACE") { 
2224                         needed::BuildNeeded($x);
2225                         ParseInterface($x);
2226                 }
2227         }
2228
2229         RegistrationFunction($idl, $filename);
2230
2231         return $res;
2232 }
2233
2234 1;