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