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