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