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