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