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