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