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