fce7f26f9398e09da117a42e495118fb309dc751
[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         } else {
670                 if (my $switch = util::has_property($e, "switch_is")) {
671                         ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
672                 }
673
674                 pidl "NDR_CHECK(ndr_push_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
675         }
676
677         if (defined $sub_size and $e->{POINTERS} == 0) {
678                 ParseSubcontextPushEnd($e);
679         }
680
681         end_flags($e);
682 }
683
684 #####################################################################
685 # parse a pointer in a struct element or function
686 sub ParsePtrPush($$)
687 {
688         my $e = shift;
689         my $var_prefix = shift;
690
691         if (util::has_property($e, "relative")) {
692                 pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));";
693         } else {
694                 pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, $var_prefix$e->{NAME}));";
695         }
696 }
697
698 #####################################################################
699 # print scalars in a structure element
700 sub ParseElementPrint($$)
701 {
702         my($e) = shift;
703         my($var_prefix) = shift;
704         my $cprefix = c_push_prefix($e);
705         my $ptr_prefix = c_ptr_prefix($e);
706
707         return if (util::has_property($e, "noprint"));
708
709         if (my $value = util::has_property($e, "value")) {
710                 pidl "if (ndr->flags & LIBNDR_PRINT_SET_VALUES) {";
711                 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;";
712                 pidl "}";
713         }
714
715         my $l = $e->{POINTERS};
716         $l++ if (util::array_size($e) and $l == 0 and !is_fixed_array($e));
717
718         foreach my $i (1..$l) {
719                 pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});";
720                 pidl "ndr->depth++;";
721                 if ($i > $l-need_wire_pointer($e)) {
722                         pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {";
723                         indent;
724                 }
725         }
726
727         if (util::array_size($e)) {
728                 ParseArrayPrint($e, $var_prefix)
729         } elsif (my $switch = util::has_property($e, "switch_is")) {
730                 my $switch_var = ParseExpr($e, $switch, $var_prefix);
731                 check_null_pointer_void($switch_var);
732
733                 pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});";
734         } else {
735                 pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});";
736         }
737
738         foreach my $i (1..$l) {
739                 if ($i > $l-need_wire_pointer($e)) {
740                         deindent;
741                         pidl "}";
742                 }
743                 pidl "ndr->depth--;";
744         }
745 }
746
747 #####################################################################
748 # parse scalars in a structure element - pull size
749 sub ParseSwitchPull($$$$$)
750 {
751         my($e) = shift;
752         my $ndr = shift;
753         my($var_prefix) = shift;
754         my($ndr_flags) = shift;
755         my $switch = shift;
756         my $switch_var = ParseExpr($e, $switch, $var_prefix);
757
758         my $cprefix = c_pull_prefix($e);
759
760         my $utype = typelist::getType($e->{TYPE});
761
762         check_null_pointer($switch_var);
763
764         pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));";
765
766 }
767
768 #####################################################################
769 # push switch element
770 sub ParseSwitchPush($$$$$)
771 {
772         my($e) = shift;
773         my $ndr = shift;
774         my($var_prefix) = shift;
775         my($ndr_flags) = shift;
776         my $switch = shift;
777         my $switch_var = ParseExpr($e, $switch, $var_prefix);
778         my $cprefix = c_push_prefix($e);
779
780         check_null_pointer($switch_var);
781
782         pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $cprefix$var_prefix$e->{NAME}, $switch_var));";
783
784 }
785
786 #####################################################################
787 # parse scalars in a structure element - pull size
788 sub ParseElementPullScalar($$$)
789 {
790         my($e) = shift;
791         my($var_prefix) = shift;
792         my($ndr_flags) = shift;
793         my $cprefix = c_pull_prefix($e);
794         my $ptr_prefix = c_ptr_prefix($e);
795         my $sub_size = util::has_property($e, "subcontext");
796         my $ndr = "ndr";
797
798         start_flags($e);
799
800         if (defined $sub_size && $e->{POINTERS} == 0) {
801                 $ndr = ParseSubcontextPullStart($e);
802                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
803         }
804
805         if (is_inline_array($e)) {
806                 ParseArrayPull($e, $ndr, "r->", "NDR_SCALARS");
807         } elsif (need_wire_pointer($e)) {
808                 ParsePtrPull($e, $ptr_prefix.$var_prefix);
809         } elsif (is_surrounding_array($e)) {
810         } else {
811                 if (my $switch = util::has_property($e, "switch_is")) {
812                         ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
813                 }
814
815                 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
816         }
817
818         if (my $range = util::has_property($e, "range")) {
819                 my ($low, $high) = split(/ /, $range, 2);
820                 pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {";
821                 pidl "\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");";
822                 pidl "}";
823         }
824
825         if (defined $sub_size && $e->{POINTERS} == 0) {
826                 ParseSubcontextPullEnd($e);
827         }
828
829         end_flags($e);
830 }
831
832 #####################################################################
833 # parse a pointer in a struct element or function
834 sub ParsePtrPull($$)
835 {
836         my($e) = shift;
837         my($var_prefix) = shift;
838
839         pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
840         pidl "if (_ptr_$e->{NAME}) {";
841         indent;
842         pidl "NDR_ALLOC(ndr, $var_prefix$e->{NAME});";
843         if (util::has_property($e, "relative")) {
844                 pidl "NDR_CHECK(ndr_pull_relative_ptr1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));";
845         }
846         deindent;
847         pidl "} else {";
848         pidl "\t$var_prefix$e->{NAME} = NULL;";
849         pidl "}";
850 }
851
852 #####################################################################
853 # parse buffers in a structure element
854 sub ParseElementPushBuffer($$)
855 {
856         my($e) = shift;
857         my($var_prefix) = shift;
858         my $cprefix = c_push_prefix($e);
859         my $sub_size = util::has_property($e, "subcontext");
860         my $ndr = "ndr";
861
862         return unless (need_buffers_section($e));
863
864         start_flags($e);
865
866         my $pointers = c_ptr_prefix($e);
867         for my $i (1..need_wire_pointer($e)) {
868                 if ($i > 1) {
869                         ParsePtrPush($e,$pointers.$var_prefix);
870                 }
871                 pidl "if ($pointers$var_prefix$e->{NAME}) {";
872                 indent;
873                 $pointers.="*";
874         }
875         
876         if (util::has_property($e, "relative")) {
877                 pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
878         }
879
880         my $ndr_flags = "NDR_BUFFERS";
881         if ($e->{POINTERS} || (util::array_size($e) && !is_inline_array($e)))
882         {
883                 $ndr_flags="NDR_SCALARS|$ndr_flags" 
884         }
885
886         if (defined $sub_size) {
887                 $ndr = ParseSubcontextPushStart($e);
888                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
889         }
890             
891         if (util::array_size($e)) {
892                 ParseArrayPush($e, $ndr, "r->", $ndr_flags);
893         } else {
894                 if (my $switch = util::has_property($e, "switch_is")) {
895                         ParseSwitchPush($e, $ndr, $var_prefix, $ndr_flags, $switch);
896                 }
897
898                 pidl "NDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
899         }
900
901         if (defined $sub_size) {
902                 ParseSubcontextPushEnd($e);
903         }
904
905         for my $i (1..need_wire_pointer($e)) {
906                 deindent;
907                 pidl "}";
908         }
909
910         end_flags($e);
911 }
912
913 #####################################################################
914 # parse buffers in a structure element - pull side
915 sub ParseElementPullBuffer($$)
916 {
917         my($e) = shift;
918         my($var_prefix) = shift;
919         my $cprefix = c_pull_prefix($e);
920         my $sub_size = util::has_property($e, "subcontext");
921         my $ndr = "ndr";
922
923         return unless (need_buffers_section($e));
924
925         start_flags($e);
926
927         my $pointers = c_ptr_prefix($e);
928         for my $i (1..need_wire_pointer($e)) {
929                 if ($i > 1) {
930                         ParsePtrPull($e,$pointers.$var_prefix);
931                 }
932                 pidl "if ($pointers$var_prefix$e->{NAME}) {";
933                 indent;
934                 $pointers.="*";
935         }
936  
937         if (util::has_property($e, "relative")) {
938                 pidl "struct ndr_pull_save _relative_save;";
939                 pidl "ndr_pull_save(ndr, &_relative_save);";
940                 pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
941         }
942
943         my $ndr_flags = "NDR_BUFFERS";
944         if ($e->{POINTERS} || (util::array_size($e) && !is_inline_array($e)))
945         {
946                 $ndr_flags="NDR_SCALARS|$ndr_flags" 
947         }
948
949         if (defined $sub_size) {
950                 $ndr = ParseSubcontextPullStart($e);
951                 $ndr_flags = "NDR_SCALARS|NDR_BUFFERS";
952         }
953
954         if (util::array_size($e)) {
955                 ParseArrayPull($e, $ndr, "r->", $ndr_flags);
956         } else {
957                 if (my $switch = util::has_property($e, "switch_is")) {
958                         ParseSwitchPull($e, $ndr, $var_prefix, $ndr_flags, $switch);
959                 }
960
961                 pidl "NDR_CHECK(ndr_pull_$e->{TYPE}($ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
962         }
963
964         if (defined $sub_size) {
965                 ParseSubcontextPullEnd($e);
966         }
967
968         if (util::has_property($e, "relative")) {
969                 pidl "ndr_pull_restore(ndr, &_relative_save);";
970         }
971
972         for my $i (1..need_wire_pointer($e)) {
973                 deindent;
974                 pidl "}";
975         }
976
977         end_flags($e);
978 }
979
980 #####################################################################
981 # parse a struct
982 sub ParseStructPush($)
983 {
984         my($struct) = shift;
985         
986         return unless defined($struct->{ELEMENTS});
987
988         start_flags($struct);
989
990         # see if the structure contains a conformant array. If it
991         # does, then it must be the last element of the structure, and
992         # we need to push the conformant length early, as it fits on
993         # the wire before the structure (and even before the structure
994         # alignment)
995         my $e = $struct->{ELEMENTS}[-1];
996         if (is_conformant_array($e) and is_surrounding_array($e)) {
997                 ParseArrayPushPreceding($e, "r->", "NDR_SCALARS");
998         }
999
1000         if (defined $e->{TYPE} && $e->{TYPE} eq "string" 
1001             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1002                 pidl "NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));";
1003         }
1004
1005         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1006
1007         pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1008
1009         my $align = find_largest_alignment($struct);
1010         pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1011
1012         foreach my $e (@{$struct->{ELEMENTS}}) {
1013                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
1014         }       
1015
1016         pidl "buffers:";
1017         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1018         foreach my $e (@{$struct->{ELEMENTS}}) {
1019                 ParseElementPushBuffer($e, "r->");
1020         }
1021
1022         pidl "ndr_push_struct_end(ndr);";
1023
1024         pidl "done:";
1025
1026         end_flags($struct);
1027 }
1028
1029 #####################################################################
1030 # generate a push function for an enum
1031 sub ParseEnumPush($)
1032 {
1033         my($enum) = shift;
1034         my($type_fn) = typelist::enum_type_fn($enum);
1035
1036         start_flags($enum);
1037
1038         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1039
1040         end_flags($enum);
1041 }
1042
1043 #####################################################################
1044 # generate a pull function for an enum
1045 sub ParseEnumPull($)
1046 {
1047         my($enum) = shift;
1048         my($type_fn) = typelist::enum_type_fn($enum);
1049         my($type_v_decl) = typelist::mapScalarType(typelist::enum_type_fn($enum));
1050
1051         pidl "$type_v_decl v;";
1052         start_flags($enum);
1053         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1054         pidl "*r = v;";
1055
1056         end_flags($enum);
1057 }
1058
1059 #####################################################################
1060 # generate a print function for an enum
1061 sub ParseEnumPrint($)
1062 {
1063         my($enum) = shift;
1064
1065         pidl "const char *val = NULL;";
1066         pidl "";
1067
1068         start_flags($enum);
1069
1070         pidl "switch (r) {";
1071         indent;
1072         my $els = \@{$enum->{ELEMENTS}};
1073         foreach my $i (0 .. $#{$els}) {
1074                 my $e = ${$els}[$i];
1075                 chomp $e;
1076                 if ($e =~ /^(.*)=/) {
1077                         $e = $1;
1078                 }
1079                 pidl "case $e: val = \"$e\"; break;";
1080         }
1081
1082         deindent;
1083         pidl "}";
1084         
1085         pidl "ndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);";
1086
1087         end_flags($enum);
1088 }
1089
1090 sub ArgsEnumPush($)
1091 {
1092         my $e = shift;
1093         return "struct ndr_push *ndr, int ndr_flags, enum $e->{NAME} r";
1094 }
1095
1096 sub ArgsEnumPrint($)
1097 {
1098         my $e = shift;
1099         return "struct ndr_print *ndr, const char *name, enum $e->{NAME} r";
1100 }
1101
1102 sub ArgsEnumPull($)
1103 {
1104         my $e = shift;
1105         return "struct ndr_pull *ndr, int ndr_flags, enum $e->{NAME} *r";
1106 }
1107
1108 $typefamily{ENUM} = {
1109         PUSH_FN_BODY => \&ParseEnumPush,
1110         PUSH_FN_ARGS => \&ArgsEnumPush,
1111         PULL_FN_BODY => \&ParseEnumPull,
1112         PULL_FN_ARGS => \&ArgsEnumPull,
1113         PRINT_FN_BODY => \&ParseEnumPrint,
1114         PRINT_FN_ARGS => \&ArgsEnumPrint,
1115         ALIGN => sub { return align_type(typelist::enum_type_fn(shift)); }
1116 };
1117
1118 #####################################################################
1119 # generate a push function for a bitmap
1120 sub ParseBitmapPush($)
1121 {
1122         my($bitmap) = shift;
1123         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1124
1125         start_flags($bitmap);
1126
1127         pidl "NDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));";
1128
1129         end_flags($bitmap);
1130 }
1131
1132 #####################################################################
1133 # generate a pull function for an bitmap
1134 sub ParseBitmapPull($)
1135 {
1136         my($bitmap) = shift;
1137         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1138         my($type_decl) = typelist::mapType($bitmap);
1139
1140         pidl "$type_decl v;";
1141         start_flags($bitmap);
1142         pidl "NDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));";
1143         pidl "*r = v;";
1144
1145         end_flags($bitmap);
1146 }
1147
1148 #####################################################################
1149 # generate a print function for an bitmap
1150 sub ParseBitmapPrintElement($$)
1151 {
1152         my($e) = shift;
1153         my($bitmap) = shift;
1154         my($type_decl) = typelist::mapType($bitmap);
1155         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1156         my($name) = $bitmap->{PARENT}->{NAME};
1157         my($flag);
1158
1159         if ($e =~ /^(\w+) .*$/) {
1160                 $flag = "$1";
1161         } else {
1162                 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1163         }
1164
1165         pidl "ndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);";
1166 }
1167
1168 #####################################################################
1169 # generate a print function for an bitmap
1170 sub ParseBitmapPrint($)
1171 {
1172         my($bitmap) = shift;
1173         my($type_decl) = typelist::mapType($bitmap);
1174         my($type_fn) = typelist::bitmap_type_fn($bitmap);
1175
1176         start_flags($bitmap);
1177
1178         pidl "ndr_print_$type_fn(ndr, name, r);";
1179
1180         pidl "ndr->depth++;";
1181         foreach my $e (@{$bitmap->{ELEMENTS}}) {
1182                 ParseBitmapPrintElement($e, $bitmap);
1183         }
1184         pidl "ndr->depth--;";
1185
1186         end_flags($bitmap);
1187 }
1188
1189 sub ArgsBitmapPush($)
1190 {
1191         my $e = shift;
1192         my $type_decl = typelist::mapType($e->{DATA});
1193         return "struct ndr_push *ndr, int ndr_flags, $type_decl r";
1194 }
1195
1196 sub ArgsBitmapPrint($)
1197 {
1198         my $e = shift;
1199         my $type_decl = typelist::mapType($e->{DATA});
1200         return "struct ndr_print *ndr, const char *name, $type_decl r";
1201 }
1202
1203 sub ArgsBitmapPull($)
1204 {
1205         my $e = shift;
1206         my $type_decl = typelist::mapType($e->{DATA});
1207         return "struct ndr_pull *ndr, int ndr_flags, $type_decl *r";
1208 }
1209
1210 $typefamily{BITMAP} = {
1211         PUSH_FN_BODY => \&ParseBitmapPush,
1212         PUSH_FN_ARGS => \&ArgsBitmapPush,
1213         PULL_FN_BODY => \&ParseBitmapPull,
1214         PULL_FN_ARGS => \&ArgsBitmapPull,
1215         PRINT_FN_BODY => \&ParseBitmapPrint,
1216         PRINT_FN_ARGS => \&ArgsBitmapPrint,
1217         ALIGN => sub { return align_type(typelist::bitmap_type_fn(shift)); }
1218 };
1219
1220 #####################################################################
1221 # generate a struct print function
1222 sub ParseStructPrint($)
1223 {
1224         my($struct) = shift;
1225         my($name) = $struct->{PARENT}->{NAME};
1226
1227         return unless defined $struct->{ELEMENTS};
1228
1229         pidl "ndr_print_struct(ndr, name, \"$name\");";
1230
1231         start_flags($struct);
1232
1233         pidl "ndr->depth++;";
1234         foreach my $e (@{$struct->{ELEMENTS}}) {
1235                 ParseElementPrint($e, "r->");
1236         }
1237         pidl "ndr->depth--;";
1238
1239         end_flags($struct);
1240 }
1241
1242 #####################################################################
1243 # parse a struct - pull side
1244 sub ParseStructPull($)
1245 {
1246         my($struct) = shift;
1247         my $conform_e;
1248
1249         return unless defined $struct->{ELEMENTS};
1250
1251         # see if the structure contains a conformant array. If it
1252         # does, then it must be the last element of the structure, and
1253         # we need to pull the conformant length early, as it fits on
1254         # the wire before the structure (and even before the structure
1255         # alignment)
1256         my $e = $struct->{ELEMENTS}[-1];
1257         if (is_conformant_array($e) and is_surrounding_array($e)) {
1258                 $conform_e = $e;
1259         }
1260
1261         if (defined $e->{TYPE} && $e->{TYPE} eq "string"
1262             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1263                 $conform_e = $e;
1264         }
1265
1266         # declare any internal pointers we need
1267         foreach my $e (@{$struct->{ELEMENTS}}) {
1268                 if (need_wire_pointer($e)) {
1269                         pidl "uint32_t _ptr_$e->{NAME};";
1270                 }
1271         }
1272
1273         start_flags($struct);
1274
1275         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1276
1277         pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1278
1279         if (defined $conform_e) {
1280                 ParseArrayPullPreceding($conform_e, "r->", "NDR_SCALARS");
1281         }
1282
1283         my $align = find_largest_alignment($struct);
1284         pidl "NDR_CHECK(ndr_pull_align(ndr, $align));";
1285
1286         foreach my $e (@{$struct->{ELEMENTS}}) {
1287                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
1288         }       
1289
1290         pidl "buffers:\n";
1291         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1292         foreach my $e (@{$struct->{ELEMENTS}}) {
1293                 ParseElementPullBuffer($e, "r->");
1294         }
1295
1296         foreach my $e (@{$struct->{ELEMENTS}}) {
1297                 CheckArraySizes($e, "r->");
1298         }
1299
1300         pidl "ndr_pull_struct_end(ndr);";
1301
1302         pidl "done:";
1303
1304         end_flags($struct);
1305 }
1306
1307 #####################################################################
1308 # calculate size of ndr struct
1309 sub ParseStructNdrSize($)
1310 {
1311         my $t = shift;
1312         my $static = fn_prefix($t);
1313         my $sizevar;
1314
1315         if (my $flags = util::has_property($t, "flag")) {
1316                 pidl "flags |= $flags;";
1317         }
1318         pidl "return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});";
1319 }
1320
1321 sub ArgsStructPush($)
1322 {
1323         my $e = shift;
1324         return "struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r";
1325 }
1326
1327 sub ArgsStructPrint($)
1328 {
1329         my $e = shift;
1330         return "struct ndr_print *ndr, const char *name, struct $e->{NAME} *r";
1331 }
1332
1333 sub ArgsStructPull($)
1334 {
1335         my $e = shift;
1336         return "struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r";
1337 }
1338
1339 sub ArgsStructNdrSize($)
1340 {
1341         my $d = shift;
1342         return "const struct $d->{NAME} *r, int flags";
1343 }
1344
1345 $typefamily{STRUCT} = {
1346         PUSH_FN_BODY => \&ParseStructPush,
1347         PUSH_FN_ARGS => \&ArgsStructPush,
1348         PULL_FN_BODY => \&ParseStructPull,
1349         PULL_FN_ARGS => \&ArgsStructPull,
1350         PRINT_FN_BODY => \&ParseStructPrint,
1351         PRINT_FN_ARGS => \&ArgsStructPrint,
1352         SIZE_FN_BODY => \&ParseStructNdrSize,
1353         SIZE_FN_ARGS => \&ArgsStructNdrSize,
1354         ALIGN => \&find_largest_alignment
1355 };
1356
1357 #####################################################################
1358 # calculate size of ndr struct
1359 sub ParseUnionNdrSize($)
1360 {
1361         my $t = shift;
1362         my $static = fn_prefix($t);
1363         my $sizevar;
1364
1365         if (my $flags = util::has_property($t, "flag")) {
1366                 pidl "flags |= $flags;";
1367         }
1368         pidl "return ndr_size_union(r, flags, level, (ndr_push_union_fn_t)ndr_push_$t->{NAME});";
1369 }
1370
1371 #####################################################################
1372 # parse a union - push side
1373 sub ParseUnionPush($)
1374 {
1375         my $e = shift;
1376         my $have_default = 0;
1377
1378         pidl "int level;";
1379
1380         start_flags($e);
1381
1382         pidl "level = ndr_push_get_switch_value(ndr, r);";
1383
1384         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1385
1386         if (!util::has_property($e, "nodiscriminant")) {
1387                 my $switch_type = util::has_property($e, "switch_type");
1388                 $switch_type = "uint32" unless  (defined ($switch_type));
1389                 pidl "NDR_CHECK(ndr_push_$switch_type(ndr, NDR_SCALARS, level));";
1390         }
1391
1392         pidl "NDR_CHECK(ndr_push_struct_start(ndr));";
1393
1394 #       my $align = union_alignment($e);
1395 #       pidl "NDR_CHECK(ndr_push_align(ndr, $align));";
1396
1397         pidl "switch (level) {";
1398         indent;
1399         foreach my $el (@{$e->{ELEMENTS}}) {
1400                 if (util::has_property($el, "default")) {
1401                         pidl "default:";
1402                         $have_default = 1;
1403                 } else {
1404                         pidl "case $el->{PROPERTIES}->{case}:";
1405
1406                 }
1407                 if ($el->{TYPE} ne "EMPTY") {
1408                         indent;
1409                         ParseElementPushScalar($el, "r->", "NDR_SCALARS");
1410                         deindent;
1411                 }
1412                 pidl "break;";
1413                 pidl "";
1414         }
1415         if (! $have_default) {
1416                 pidl "default:";
1417                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1418         }
1419         deindent;
1420         pidl "}";
1421         pidl "buffers:";
1422         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1423         pidl "switch (level) {";
1424         indent;
1425         foreach my $el (@{$e->{ELEMENTS}}) {
1426                 if (util::has_property($el, "default")) {
1427                         pidl "default:";
1428                 } else {
1429                         pidl "case $el->{PROPERTIES}->{case}:";
1430                 }
1431                 if ($el->{TYPE} ne "EMPTY") {
1432                         indent;
1433                         ParseElementPushBuffer($el, "r->");
1434                         deindent;
1435                 }
1436                 pidl "break;";
1437                 pidl "";
1438         }
1439         if (! $have_default) {
1440                 pidl "default:";
1441                 pidl "\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1442         }
1443         deindent;
1444         pidl "}";
1445         pidl "ndr_push_struct_end(ndr);";
1446         pidl "done:";
1447         end_flags($e);
1448 }
1449
1450 #####################################################################
1451 # print a union
1452 sub ParseUnionPrint($)
1453 {
1454         my $e = shift;
1455         my $have_default = 0;
1456         my($name) = $e->{PARENT}->{NAME};
1457
1458         pidl "ndr_print_union(ndr, name, level, \"$name\");";
1459         start_flags($e);
1460
1461         pidl "switch (level) {";
1462         indent;
1463         foreach my $el (@{$e->{ELEMENTS}}) {
1464                 if (util::has_property($el, "default")) {
1465                         $have_default = 1;
1466                         pidl "default:";
1467                 } else {
1468                         pidl "case $el->{PROPERTIES}->{case}:";
1469                 }
1470                 if ($el->{TYPE} ne "EMPTY") {
1471                         indent;
1472                         ParseElementPrint($el, "r->");
1473                         deindent;
1474                 }
1475                 pidl "break;";
1476                 pidl "";
1477         }
1478         if (! $have_default) {
1479                 pidl "default:";
1480                 pidl "\tndr_print_bad_level(ndr, name, level);";
1481         }
1482         deindent;
1483         pidl "}";
1484
1485         end_flags($e);
1486 }
1487
1488 #####################################################################
1489 # parse a union - pull side
1490 sub ParseUnionPull($)
1491 {
1492         my $e = shift;
1493         my $have_default = 0;
1494         my $switch_type = util::has_property($e, "switch_type");
1495         $switch_type = "uint32" unless defined($switch_type);
1496
1497         pidl "int level;";
1498         if (!util::has_property($e, "nodiscriminant")) {
1499                 if (typelist::typeIs($switch_type, "ENUM")) {
1500                         $switch_type = typelist::enum_type_fn(typelist::getType($switch_type));
1501                 }
1502                 pidl typelist::mapScalarType($switch_type) . " _level;";
1503         }
1504
1505         start_flags($e);
1506
1507         pidl "level = ndr_pull_get_switch_value(ndr, r);";
1508
1509         pidl "if (!(ndr_flags & NDR_SCALARS)) goto buffers;";
1510
1511         if (!util::has_property($e, "nodiscriminant")) {
1512                 pidl "NDR_CHECK(ndr_pull_$switch_type(ndr, NDR_SCALARS, &_level));";
1513                 pidl "if (_level != level) {"; 
1514                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $e->{PARENT}->{NAME}\", _level);";
1515                 pidl "}";
1516         }
1517
1518         pidl "NDR_CHECK(ndr_pull_struct_start(ndr));";
1519
1520 #       my $align = union_alignment($e);
1521 #       pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1522
1523         pidl "switch (level) {";
1524         indent;
1525         foreach my $el (@{$e->{ELEMENTS}}) {
1526                 if (util::has_property($el, "default")) {
1527                         pidl "default: {";
1528                         $have_default = 1;
1529                 } else {
1530                         pidl "case $el->{PROPERTIES}->{case}: {";
1531                 }
1532                 if ($el->{TYPE} ne "EMPTY") {
1533                         indent;
1534                         if ($el->{POINTERS}) {
1535                                 pidl "uint32_t _ptr_$el->{NAME};";
1536                         }
1537                         ParseElementPullScalar($el, "r->", "NDR_SCALARS");
1538                         deindent;
1539                 }
1540                 pidl "break; }";
1541                 pidl "";
1542         }
1543         if (! $have_default) {
1544                 pidl "default:";
1545                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1546         }
1547         deindent;
1548         pidl "}";
1549         pidl "buffers:";
1550         pidl "if (!(ndr_flags & NDR_BUFFERS)) goto done;";
1551         pidl "switch (level) {";
1552         indent;
1553         foreach my $el (@{$e->{ELEMENTS}}) {
1554                 if (util::has_property($el, "default")) {
1555                         pidl "default:";
1556                 } else {
1557                         pidl "case $el->{PROPERTIES}->{case}:";
1558                 }
1559                 if ($el->{TYPE} ne "EMPTY") {
1560                         indent;
1561                         ParseElementPullBuffer($el, "r->");
1562                         deindent;
1563                 }
1564                 pidl "break;";
1565                 pidl "";
1566         }
1567         if (! $have_default) {
1568                 pidl "default:";
1569                 pidl "\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);";
1570         }
1571         deindent;
1572         pidl "}";
1573         pidl "ndr_pull_struct_end(ndr);";
1574         pidl "done:";
1575         end_flags($e);
1576 }
1577
1578 sub ArgsUnionPush($)
1579 {
1580         my $e = shift;
1581         return "struct ndr_push *ndr, int ndr_flags, union $e->{NAME} *r";
1582 }
1583
1584 sub ArgsUnionPrint($)
1585 {
1586         my $e = shift;
1587         return "struct ndr_print *ndr, const char *name, int level, union $e->{NAME} *r";
1588 }
1589
1590 sub ArgsUnionPull($)
1591 {
1592         my $e = shift;
1593         return "struct ndr_pull *ndr, int ndr_flags, union $e->{NAME} *r";
1594 }
1595
1596 sub ArgsUnionNdrSize($)
1597 {
1598         my $d = shift;
1599         return "const union $d->{NAME} *r, uint32_t level, int flags";
1600 }
1601
1602 $typefamily{UNION} = {
1603         PUSH_FN_BODY => \&ParseUnionPush,
1604         PUSH_FN_ARGS => \&ArgsUnionPush,
1605         PULL_FN_BODY => \&ParseUnionPull,
1606         PULL_FN_ARGS => \&ArgsUnionPull,
1607         PRINT_FN_BODY => \&ParseUnionPrint,
1608         PRINT_FN_ARGS => \&ArgsUnionPrint,
1609         SIZE_FN_ARGS => \&ArgsUnionNdrSize,
1610         SIZE_FN_BODY => \&ParseUnionNdrSize,
1611         ALIGN => \&find_largest_alignment
1612 };
1613         
1614 #####################################################################
1615 # parse a typedef - push side
1616 sub ParseTypedefPush($)
1617 {
1618         my($e) = shift;
1619         my $static = fn_prefix($e);
1620
1621         return unless needed::is_needed("push_$e->{NAME}");
1622
1623         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_ARGS}->($e);
1624         pidl $static . "NTSTATUS ndr_push_$e->{NAME}($args)";
1625
1626         pidl "{";
1627         indent;
1628         $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($e->{DATA});
1629         pidl "return NT_STATUS_OK;";
1630         deindent;
1631         pidl "}";
1632         pidl "";;
1633 }
1634
1635
1636 #####################################################################
1637 # parse a typedef - pull side
1638 sub ParseTypedefPull($)
1639 {
1640         my($e) = shift;
1641         my $static = fn_prefix($e);
1642
1643         return unless needed::is_needed("pull_$e->{NAME}");
1644
1645         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_ARGS}->($e);
1646
1647         pidl $static . "NTSTATUS ndr_pull_$e->{NAME}($args)";
1648
1649         pidl "{";
1650         indent;
1651         $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($e->{DATA});
1652         pidl "return NT_STATUS_OK;";
1653         deindent;
1654         pidl "}";
1655         pidl "";
1656 }
1657
1658 #####################################################################
1659 # parse a typedef - print side
1660 sub ParseTypedefPrint($)
1661 {
1662         my($e) = shift;
1663
1664         my $args = $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_ARGS}->($e);
1665
1666         return unless !util::has_property($e, "noprint");
1667
1668         pidl "void ndr_print_$e->{NAME}($args)";
1669         pidl "{";
1670         indent;
1671         $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($e->{DATA});
1672         deindent;
1673         pidl "}";
1674 }
1675
1676 #####################################################################
1677 ## calculate the size of a structure
1678 sub ParseTypedefNdrSize($)
1679 {
1680         my($t) = shift;
1681
1682         return unless needed::is_needed("ndr_size_$t->{NAME}");
1683
1684         my $tf = $typefamily{$t->{DATA}->{TYPE}};
1685         my $args = $tf->{SIZE_FN_ARGS}->($t);
1686
1687         pidl "size_t ndr_size_$t->{NAME}($args)";
1688         pidl "{";
1689         indent;
1690         $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($t);
1691         deindent;
1692         pidl "}";
1693         pidl "";
1694 }
1695
1696 #####################################################################
1697 # parse a function - print side
1698 sub ParseFunctionPrint($)
1699 {
1700         my($fn) = shift;
1701
1702         return unless !util::has_property($fn, "noprint");
1703
1704         pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)";
1705         pidl "{";
1706         indent;
1707         pidl "ndr_print_struct(ndr, name, \"$fn->{NAME}\");";
1708         pidl "ndr->depth++;";
1709
1710         pidl "if (flags & NDR_SET_VALUES) {";
1711         pidl "\tndr->flags |= LIBNDR_PRINT_SET_VALUES;";
1712         pidl "}";
1713
1714         pidl "if (flags & NDR_IN) {";
1715         indent;
1716         pidl "ndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");";
1717         pidl "ndr->depth++;";
1718
1719         foreach my $e (@{$fn->{ELEMENTS}}) {
1720                 if (util::has_property($e, "in")) {
1721                         ParseElementPrint($e, "r->in.");
1722                 }
1723         }
1724         pidl "ndr->depth--;";
1725         deindent;
1726         pidl "}";
1727         
1728         pidl "if (flags & NDR_OUT) {";
1729         indent;
1730         pidl "ndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");";
1731         pidl "ndr->depth++;";
1732         foreach my $e (@{$fn->{ELEMENTS}}) {
1733                 if (util::has_property($e, "out")) {
1734                         ParseElementPrint($e, "r->out.");
1735                 }
1736         }
1737         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1738                 my $cprefix = "&";
1739                 $cprefix = "" if (is_scalar_type($fn->{RETURN_TYPE})) ; # FIXME: Should really use util::c_push_prefix here
1740                 pidl "ndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", $cprefix"."r->out.result);";
1741         }
1742         pidl "ndr->depth--;";
1743         deindent;
1744         pidl "}";
1745         
1746         pidl "ndr->depth--;";
1747         deindent;
1748         pidl "}";
1749         pidl "";
1750 }
1751
1752 #####################################################################
1753 # parse a function element
1754 sub ParseFunctionElementPush($$)
1755
1756         my $e = shift;
1757         my $inout = shift;
1758
1759         if (util::array_size($e)) {
1760                 if (need_wire_pointer($e)) {
1761                         pidl "NDR_CHECK(ndr_push_unique_ptr(ndr, r->$inout.$e->{NAME}));";
1762                         pidl "if (r->$inout.$e->{NAME}) {";
1763                         indent;
1764                         ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1765                         deindent;
1766                         pidl "}";
1767                 } else {
1768                         ParseArrayPush($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1769                 }
1770         } else {
1771                 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1772                 if (need_wire_pointer($e)) {
1773                         ParseElementPushBuffer($e, "r->$inout.");
1774                 }
1775         }
1776 }       
1777
1778 #####################################################################
1779 # parse a function
1780 sub ParseFunctionPush($)
1781
1782         my($fn) = shift;
1783         my $static = fn_prefix($fn);
1784
1785         return unless !util::has_property($fn, "nopush");
1786
1787         pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)";
1788         pidl "{";
1789         indent;
1790
1791         pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1792         pidl "";
1793
1794         foreach my $e (@{$fn->{ELEMENTS}}) {
1795                 if (util::has_property($e, "in")) {
1796                         if (util::has_property($e, "ref")) {
1797                                 check_null_pointer("*r->in.$e->{NAME}");
1798                         } 
1799                         ParseFunctionElementPush($e, "in");
1800                 }               
1801         }
1802
1803         pidl "ndr_out:";
1804         pidl "if (!(flags & NDR_OUT)) goto done;";
1805         pidl "";
1806
1807         foreach my $e (@{$fn->{ELEMENTS}}) {
1808                 if (util::has_property($e, "out")) {
1809                         if (util::has_property($e, "ref")) {
1810                                 check_null_pointer("*r->out.$e->{NAME}");
1811                         } 
1812                         ParseFunctionElementPush($e, "out");
1813                 }               
1814         }
1815
1816         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1817                 pidl "NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));";
1818         }
1819     
1820         pidl "done:";
1821         pidl "return NT_STATUS_OK;";
1822         deindent;
1823         pidl "}";
1824         pidl "";
1825 }
1826
1827 #####################################################################
1828 # parse a function element
1829 sub ParseFunctionElementPull($$)
1830
1831         my $e = shift;
1832         my $inout = shift;
1833
1834         if (util::array_size($e)) {
1835                 if (need_wire_pointer($e)) {
1836                         pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
1837                         pidl "r->$inout.$e->{NAME} = NULL;";
1838                         pidl "if (_ptr_$e->{NAME}) {";
1839                         indent;
1840                 } elsif ($inout eq "out" && util::has_property($e, "ref")) {
1841                         pidl "if (r->$inout.$e->{NAME}) {";
1842                         indent;
1843                 }
1844
1845                 ParseArrayPull($e, "ndr", "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1846
1847                 if (need_wire_pointer($e) or ($inout eq "out" and util::has_property($e, "ref"))) {
1848                         deindent;
1849                         pidl "}";
1850                 }
1851         } else {
1852                 if ($inout eq "out" && util::has_property($e, "ref")) {
1853                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
1854                         pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});";
1855                         pidl "}";
1856                 }
1857
1858                 if ($inout eq "in" && util::has_property($e, "ref")) {
1859                         pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});";
1860                 }
1861
1862                 ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1863                 if (need_wire_pointer($e)) {
1864                         ParseElementPullBuffer($e, "r->$inout.");
1865                 }
1866         }
1867 }
1868
1869 ############################################################
1870 # allocate ref variables
1871 sub AllocateRefVars($)
1872 {
1873         my $e = shift;
1874         my $asize = util::array_size($e);
1875
1876         # note that if the variable is also an "in"
1877         # variable then we copy the initial value from
1878         # the in side
1879
1880         if (!defined $asize) {
1881                 # its a simple variable
1882                 pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});";
1883                 if (util::has_property($e, "in")) {
1884                         pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};";
1885                 } else {
1886                         pidl "ZERO_STRUCTP(r->out.$e->{NAME});";
1887                 }
1888                 return;
1889         }
1890
1891         # its an array
1892         my $size = ParseExpr($e, $asize, "r->out.");
1893         check_null_pointer($size);
1894         pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
1895         if (util::has_property($e, "in")) {
1896                 pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));";
1897         } else {
1898                 pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));";
1899         }
1900 }
1901
1902 #####################################################################
1903 # parse a function
1904 sub ParseFunctionPull($)
1905
1906         my($fn) = shift;
1907         my $static = fn_prefix($fn);
1908
1909         return unless !util::has_property($fn, "nopull");
1910
1911         # pull function args
1912         pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)";
1913         pidl "{";
1914         indent;
1915
1916         # declare any internal pointers we need
1917         foreach my $e (@{$fn->{ELEMENTS}}) {
1918                 if (need_wire_pointer($e)) {
1919                         pidl "uint32_t _ptr_$e->{NAME};";
1920                 }
1921         }
1922
1923         pidl "if (!(flags & NDR_IN)) goto ndr_out;";
1924         pidl "";
1925
1926         # auto-init the out section of a structure. I originally argued that
1927         # this was a bad idea as it hides bugs, but coping correctly
1928         # with initialisation and not wiping ref vars is turning
1929         # out to be too tricky (tridge)
1930         foreach my $e (@{$fn->{ELEMENTS}}) {
1931                 if (util::has_property($e, "out")) {
1932                         pidl "ZERO_STRUCT(r->out);";
1933                         pidl "";
1934                         last;
1935                 }
1936         }
1937
1938         foreach my $e (@{$fn->{ELEMENTS}}) {
1939                 if (util::has_property($e, "in")) {
1940                         ParseFunctionElementPull($e, "in");
1941                 }
1942                 # we need to allocate any reference output variables, so that
1943                 # a dcerpc backend can be sure they are non-null
1944                 if (util::has_property($e, "out") && util::has_property($e, "ref")) {
1945                         AllocateRefVars($e);
1946                 }
1947         }
1948
1949         foreach my $e (@{$fn->{ELEMENTS}}) {
1950                 if (util::has_property($e, "in")) {
1951                         CheckArraySizes($e, "r->in.");
1952                 }
1953         }
1954
1955         pidl "ndr_out:";
1956         pidl "if (!(flags & NDR_OUT)) goto done;";
1957         pidl "";
1958
1959         foreach my $e (@{$fn->{ELEMENTS}}) {
1960                 if (util::has_property($e, "out")) {
1961                         ParseFunctionElementPull($e, "out");
1962                 }
1963         }
1964
1965         foreach my $e (@{$fn->{ELEMENTS}}) {
1966                 if (util::has_property($e, "out")) {
1967                         CheckArraySizes($e, "r->out.");
1968                 }
1969         }
1970
1971         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1972                 pidl "NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));";
1973         }
1974
1975         pidl "done:";
1976         pidl "";
1977         pidl "return NT_STATUS_OK;";
1978         deindent;
1979         pidl "}";
1980         pidl "";
1981 }
1982
1983 #####################################################################
1984 # produce a function call table
1985 sub FunctionTable($)
1986 {
1987         my($interface) = shift;
1988         my($data) = $interface->{INHERITED_DATA};
1989         my $count = 0;
1990         my $uname = uc $interface->{NAME};
1991
1992         foreach my $d (@{$data}) {
1993                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
1994         }
1995
1996         return if ($count == 0);
1997
1998         pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {";
1999         foreach my $d (@{$data}) {
2000                 if ($d->{TYPE} eq "FUNCTION") {
2001                         pidl "\t{";
2002                         pidl "\t\t\"$d->{NAME}\",";
2003                         pidl "\t\tsizeof(struct $d->{NAME}),";
2004                         pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},";
2005                         pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},";
2006                         pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}";
2007                         pidl "\t},";
2008                 }
2009         }
2010         pidl "\t{ NULL, 0, NULL, NULL, NULL }";
2011         pidl "};";
2012         pidl "";
2013
2014         # If no endpoint is set, default to the interface name as a named pipe
2015         if (! defined $interface->{PROPERTIES}->{endpoint}) {
2016                 $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\"";
2017         }
2018
2019         my @e = split / /, $interface->{PROPERTIES}->{endpoint};
2020         my $endpoint_count = $#e + 1;
2021
2022         pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {";
2023         foreach my $ep (@e) {
2024                 pidl "\t$ep, ";
2025         }
2026         pidl "};";
2027         pidl "";
2028
2029         pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {";
2030         pidl "\t.count\t= $endpoint_count,";
2031         pidl "\t.names\t= $interface->{NAME}\_endpoint_strings";
2032         pidl "};";
2033         pidl "";
2034
2035         if (! defined $interface->{PROPERTIES}->{authservice}) {
2036                 $interface->{PROPERTIES}->{authservice} = "\"host\"";
2037         }
2038
2039         my @a = split / /, $interface->{PROPERTIES}->{authservice};
2040         my $authservice_count = $#a + 1;
2041
2042         pidl "static const char * const $interface->{NAME}\_authservice_strings[] = {";
2043         foreach my $ap (@a) {
2044                 pidl "\t$ap, ";
2045         }
2046         pidl "};";
2047         pidl "";
2048
2049         pidl "static const struct dcerpc_authservice_list $interface->{NAME}\_authservices = {";
2050         pidl "\t.count\t= $endpoint_count,";
2051         pidl "\t.names\t= $interface->{NAME}\_authservice_strings";
2052         pidl "};";
2053         pidl "";
2054
2055         pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {";
2056         pidl "\t.name\t\t= \"$interface->{NAME}\",";
2057         pidl "\t.uuid\t\t= DCERPC_$uname\_UUID,";
2058         pidl "\t.if_version\t= DCERPC_$uname\_VERSION,";
2059         pidl "\t.helpstring\t= DCERPC_$uname\_HELPSTRING,";
2060         pidl "\t.num_calls\t= $count,";
2061         pidl "\t.calls\t\t= $interface->{NAME}\_calls,";
2062         pidl "\t.endpoints\t= &$interface->{NAME}\_endpoints,";
2063         pidl "\t.authservices\t= &$interface->{NAME}\_authservices";
2064         pidl "};";
2065         pidl "";
2066
2067         pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)";
2068         pidl "{";
2069         pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});";
2070         pidl "}";
2071         pidl "";
2072 }
2073
2074 #####################################################################
2075 # parse the interface definitions
2076 sub ParseInterface($)
2077 {
2078         my($interface) = shift;
2079         my($data) = $interface->{DATA};
2080
2081         # Push functions
2082         foreach my $d (@{$data}) {
2083                 ($d->{TYPE} eq "TYPEDEF") &&
2084                     ParseTypedefPush($d);
2085                 ($d->{TYPE} eq "FUNCTION") && 
2086                     ParseFunctionPush($d);
2087         }
2088
2089         # Pull functions
2090         foreach my $d (@{$data}) {
2091                 ($d->{TYPE} eq "TYPEDEF") &&
2092                     ParseTypedefPull($d);
2093                 ($d->{TYPE} eq "FUNCTION") && 
2094                     ParseFunctionPull($d);
2095         }
2096         
2097         # Print functions
2098         foreach my $d (@{$data}) {
2099                 ($d->{TYPE} eq "TYPEDEF") &&
2100                         ParseTypedefPrint($d);
2101                 ($d->{TYPE} eq "FUNCTION") &&
2102                         ParseFunctionPrint($d);
2103         }
2104
2105         # Size functions
2106         foreach my $d (@{$data}) {
2107                 ($d->{TYPE} eq "TYPEDEF") && 
2108                         ParseTypedefNdrSize($d);
2109         }
2110
2111         FunctionTable($interface);
2112 }
2113
2114 sub RegistrationFunction($$)
2115 {
2116         my $idl = shift;
2117         my $filename = shift;
2118
2119         $filename =~ /.*\/ndr_(.*).c/;
2120         my $basename = $1;
2121         pidl "NTSTATUS dcerpc_$basename\_init(void)";
2122         pidl "{";
2123         indent;
2124         pidl "NTSTATUS status = NT_STATUS_OK;";
2125         foreach my $interface (@{$idl}) {
2126                 next if $interface->{TYPE} ne "INTERFACE";
2127
2128                 my $data = $interface->{INHERITED_DATA};
2129                 my $count = 0;
2130                 foreach my $d (@{$data}) {
2131                         if ($d->{TYPE} eq "FUNCTION") { $count++; }
2132                 }
2133
2134                 next if ($count == 0);
2135
2136                 pidl "status = dcerpc_ndr_$interface->{NAME}_init();";
2137                 pidl "if (NT_STATUS_IS_ERR(status)) {";
2138                 pidl "\treturn status;";
2139                 pidl "}";
2140                 pidl "";
2141         }
2142         pidl "return status;";
2143         deindent;
2144         pidl "}";
2145         pidl "";
2146 }
2147
2148 sub CheckPointerTypes($$)
2149 {
2150         my $s = shift;
2151         my $default = shift;
2152
2153         foreach my $e (@{$s->{ELEMENTS}}) {
2154                 if ($e->{POINTERS}) {
2155                         if (not defined(pointer_type($e))) {
2156                                 $e->{PROPERTIES}->{$default} = 1;
2157                         }
2158
2159                         if (pointer_type($e) eq "ptr") {
2160                                 print "Warning: ptr is not supported by pidl yet\n";
2161                         }
2162                 }
2163         }
2164 }
2165
2166 sub LoadInterface($)
2167 {
2168         my $x = shift;
2169
2170         if (not util::has_property($x, "pointer_default")) {
2171                 # MIDL defaults to "ptr" in DCE compatible mode (/osf)
2172                 # and "unique" in Microsoft Extensions mode (default)
2173                 $x->{PROPERTIES}->{pointer_default} = "unique";
2174         }
2175
2176         foreach my $d (@{$x->{DATA}}) {
2177                 if (($d->{TYPE} eq "DECLARE") or ($d->{TYPE} eq "TYPEDEF")) {
2178                         if ($d->{DATA}->{TYPE} eq "STRUCT" or $d->{DATA}->{TYPE} eq "UNION") {
2179                                 CheckPointerTypes($d->{DATA}, $x->{PROPERTIES}->{pointer_default});
2180                         }
2181
2182                         if (defined($d->{PROPERTIES}) && !defined($d->{DATA}->{PROPERTIES})) {
2183                                 $d->{DATA}->{PROPERTIES} = $d->{PROPERTIES};
2184                         }
2185                 }
2186                 if ($d->{TYPE} eq "FUNCTION") {
2187                         CheckPointerTypes($d, 
2188                                 $x->{PROPERTIES}->{pointer_default}  # MIDL defaults to "ref"
2189                         );
2190                 }
2191         }
2192 }
2193
2194 sub Load($)
2195 {
2196         my $idl = shift;
2197
2198         foreach my $x (@{$idl}) {
2199                 LoadInterface($x);
2200         }
2201 }
2202
2203 #####################################################################
2204 # parse a parsed IDL structure back into an IDL file
2205 sub Parse($$)
2206 {
2207         my($idl) = shift;
2208         my($filename) = shift;
2209         my $h_filename = $filename;
2210         $res = "";
2211
2212         Load($idl);
2213
2214         if ($h_filename =~ /(.*)\.c/) {
2215                 $h_filename = "$1.h";
2216         }
2217
2218         pidl "/* parser auto-generated by pidl */";
2219         pidl "";
2220         pidl "#include \"includes.h\"";
2221         pidl "#include \"$h_filename\"";
2222         pidl "";
2223
2224         foreach my $x (@{$idl}) {
2225                 if ($x->{TYPE} eq "INTERFACE") { 
2226                         needed::BuildNeeded($x);
2227                         ParseInterface($x);
2228                 }
2229         }
2230
2231         RegistrationFunction($idl, $filename);
2232
2233         return $res;
2234 }
2235
2236 1;