r5319: Make some more alignment code generic, move NDR-specific stuff to
[samba.git] / source4 / build / pidl / ndr.pm
1 ###################################################
2 # Samba4 NDR parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # Copyright jelmer@samba.org 2004
6 # released under the GNU GPL
7
8 package NdrParser;
9
10 use strict;
11 use needed;
12
13 # list of known types
14 my %typedefs;
15
16 my %type_alignments = 
17     (
18      "char"           => 1,
19      "int8"           => 1,
20      "uint8"          => 1,
21      "short"          => 2,
22      "wchar_t"        => 2,
23      "int16"          => 2,
24      "uint16"         => 2,
25      "long"           => 4,
26      "int32"          => 4,
27      "uint32"         => 4,
28      "dlong"          => 4,
29      "udlong"         => 4,
30      "NTTIME"         => 4,
31      "NTTIME_1sec"    => 4,
32      "time_t"         => 4,
33      "DATA_BLOB"      => 4,
34      "error_status_t" => 4,
35      "WERROR"         => 4,
36      "boolean32"      => 4,
37      "unsigned32"     => 4,
38      "ipv4address"    => 4,
39      "hyper"          => 8,
40      "NTTIME_hyper"   => 8
41      );
42
43 sub is_scalar_type($)
44 {
45     my $type = shift;
46
47     if (defined $type_alignments{$type}) {
48             return 1;
49     }
50     if (util::is_enum($type)) {
51             return 1;
52     }
53     if (util::is_bitmap($type)) {
54             return 1;
55     }
56
57     return 0;
58 }
59
60 # determine if an element needs a reference pointer on the wire
61 # in its NDR representation
62 sub need_wire_pointer($)
63 {
64         my $e = shift;
65         if ($e->{POINTERS} && 
66             !util::has_property($e, "ref")) {
67                 return $e->{POINTERS};
68         }
69         return undef;
70 }
71
72 # determine if an element is a pure scalar. pure scalars do not
73 # have a "buffers" section in NDR
74 sub is_pure_scalar($)
75 {
76         my $e = shift;
77         if (util::has_property($e, "ref")) {
78                 return 1;
79         }
80         if (is_scalar_type($e->{TYPE}) && 
81             !$e->{POINTERS} && 
82             !util::array_size($e)) {
83                 return 1;
84         }
85         return 0;
86 }
87
88 # see if a variable needs to be allocated by the NDR subsystem on pull
89 sub need_alloc($)
90 {
91         my $e = shift;
92
93         if (util::has_property($e, "ref")) {
94                 return 0;
95         }
96
97         if ($e->{POINTERS} || util::array_size($e)) {
98                 return 1;
99         }
100
101         return 0;
102 }
103
104
105 # determine the C prefix used to refer to a variable when passing to a push
106 # function. This will be '*' for pointers to scalar types, '' for scalar
107 # types and normal pointers and '&' for pass-by-reference structures
108 sub c_push_prefix($)
109 {
110         my $e = shift;
111
112         if ($e->{TYPE} =~ "string") {
113                 return "";
114         }
115
116         if (is_scalar_type($e->{TYPE}) &&
117             $e->{POINTERS}) {
118                 return "*";
119         }
120         if (!is_scalar_type($e->{TYPE}) &&
121             !$e->{POINTERS} &&
122             !util::array_size($e)) {
123                 return "&";
124         }
125         return "";
126 }
127
128
129 # determine the C prefix used to refer to a variable when passing to a pull
130 # return '&' or ''
131 sub c_pull_prefix($)
132 {
133         my $e = shift;
134
135         if (!$e->{POINTERS} && !util::array_size($e)) {
136                 return "&";
137         }
138
139         if ($e->{TYPE} =~ "string") {
140                 return "&";
141         }
142
143         return "";
144 }
145 my $res = "";
146 sub pidl($)
147 {
148         $res .= shift;
149 }
150
151 #####################################################################
152 # parse a properties list
153 sub ParseProperties($)
154 {
155     my($props) = shift;
156     foreach my $d (@{$props}) {
157         if (ref($d) ne "HASH") {
158             pidl "[$d] ";
159         } else {
160             foreach my $k (keys %{$d}) {
161                 pidl "[$k($d->{$k})] ";
162             }
163         }
164     }
165 }
166
167 ###################################
168 # find a sibling var in a structure
169 sub find_sibling($$)
170 {
171         my($e) = shift;
172         my($name) = shift;
173         my($fn) = $e->{PARENT};
174
175         if ($name =~ /\*(.*)/) {
176                 $name = $1;
177         }
178
179         if ($fn->{TYPE} eq "FUNCTION") {
180                 for my $e2 (@{$fn->{DATA}}) {
181                         if ($e2->{NAME} eq $name) {
182                                 return $e2;
183                         }
184                 }
185         }
186
187         for my $e2 (@{$fn->{ELEMENTS}}) {
188                 if ($e2->{NAME} eq $name) {
189                         return $e2;
190                 }
191         }
192         die "invalid sibling '$name'";
193 }
194
195 ####################################################################
196 # work out the name of a size_is() variable
197 sub find_size_var($$$)
198 {
199         my($e) = shift;
200         my($size) = shift;
201         my($var_prefix) = shift;
202
203         my($fn) = $e->{PARENT};
204
205         if (util::is_constant($size)) {
206                 return $size;
207         }
208
209         if ($size =~ /ndr->|\(/) {
210                 return $size;
211         }
212
213         my $prefix = "";
214
215         if ($size =~ /\*(.*)/) {
216                 $size = $1;
217                 $prefix = "*";
218         }
219
220         if ($fn->{TYPE} ne "FUNCTION") {
221                 return $prefix . "r->$size";
222         }
223
224         my $e2 = find_sibling($e, $size);
225
226         if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
227                 return $prefix . "$var_prefix$size";
228         }
229         if (util::has_property($e2, "in")) {
230                 return $prefix . "r->in.$size";
231         }
232         if (util::has_property($e2, "out")) {
233                 return $prefix . "r->out.$size";
234         }
235
236         die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
237 }
238
239 #####################################################################
240 # check that a variable we get from find_size_var isn't a null pointer
241 sub check_null_pointer($)
242 {
243         my $size = shift;
244         if ($size =~ /^\*/) {
245                 my $size2 = substr($size, 1);
246                 pidl "\tif ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;\n";
247         }
248 }
249
250 #####################################################################
251 # check that a variable we get from find_size_var isn't a null pointer
252 # void return varient
253 sub check_null_pointer_void($)
254 {
255         my $size = shift;
256         if ($size =~ /^\*/) {
257                 my $size2 = substr($size, 1);
258                 pidl "\tif ($size2 == NULL) return;\n";
259         }
260 }
261
262
263 #####################################################################
264 # work out is a parse function should be declared static or not
265 sub fn_prefix($)
266 {
267         my $fn = shift;
268         if ($fn->{TYPE} eq "TYPEDEF") {
269                 if (util::has_property($fn, "public")) {
270                         return "";
271                 }
272         }
273
274         if ($fn->{TYPE} eq "FUNCTION") {
275                 if (util::has_property($fn, "public")) {
276                         return "";
277                 }
278         }
279         return "static ";
280 }
281
282
283 ###################################################################
284 # setup any special flags for an element or structure
285 sub start_flags($)
286 {
287         my $e = shift;
288         my $flags = util::has_property($e, "flag");
289         if (defined $flags) {
290                 pidl "\t{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;\n";
291                 pidl "\tndr_set_flags(&ndr->flags, $flags);\n";
292         }
293 }
294
295 ###################################################################
296 # end any special flags for an element or structure
297 sub end_flags($)
298 {
299         my $e = shift;
300         my $flags = util::has_property($e, "flag");
301         if (defined $flags) {
302                 pidl "\tndr->flags = _flags_save_$e->{TYPE};\n\t}\n";
303         }
304 }
305
306
307 #####################################################################
308 # work out the correct alignment for a structure
309 sub struct_alignment
310 {
311         my $s = shift;
312
313         my $align = 1;
314         for my $e (@{$s->{ELEMENTS}}) {
315                 my $a = 1;
316
317                 if (need_wire_pointer($e)) {
318                         $a = 4; 
319                 } else { 
320                         $a = align_type($e->{TYPE}); 
321                 }
322
323                 if ($align < $a) {
324                         $align = $a;
325                 }
326         }
327
328         return $align;
329 }
330
331 #####################################################################
332 # work out the correct alignment for a union
333 sub union_alignment
334 {
335         my $u = shift;
336
337         my $align = 1;
338
339         foreach my $e (@{$u->{DATA}}) {
340                 my $a = 1;
341
342                 if ($e->{TYPE} eq "EMPTY") {
343                         next;
344                 }
345
346                 if (need_wire_pointer($e->{DATA})) {
347                         $a = 4;
348                 } else {
349                         $a = align_type($e->{DATA}->{TYPE});
350                 }
351
352                 if ($align < $a) {
353                         $align = $a;
354                 }
355         }
356
357         return $align;
358 }
359
360 #####################################################################
361 # align a type
362 sub align_type
363 {
364         my $e = shift;
365
366         # Scalar type
367         if (my $ret = $type_alignments{$e}) {
368             return $ret;
369     }
370
371         if (defined $typedefs{$e}) {
372                 if ($typedefs{$e}->{DATA}->{TYPE} eq "STRUCT") {
373                         return struct_alignment($typedefs{$e}->{DATA});
374                 } elsif ($typedefs{$e}->{DATA}->{TYPE} eq "UNION") {
375                         if (defined $typedefs{$e}->{DATA}) {
376                                 return union_alignment($typedefs{$e}->{DATA});
377                         }
378                 } elsif ($typedefs{$e}->{DATA}->{TYPE} eq "ENUM") {
379                 return align_type(util::enum_type_fn(util::get_enum($e)));
380                 } elsif ($typedefs{$e}->{DATA}->{TYPE} eq "BITMAP") {
381                         return align_type(util::bitmap_type_fn(util::get_bitmap($e)));
382                 }
383         } 
384
385     # it must be an external type - all we can do is guess 
386         # print "Warning: assuming alignment of unknown type '$e' is 4\n";
387     return 4;
388 }
389
390 #####################################################################
391 # parse an array - push side
392 sub ParseArrayPush($$$)
393 {
394         my $e = shift;
395         my $var_prefix = shift;
396         my $ndr_flags = shift;
397
398         my $size = find_size_var($e, util::array_size($e), $var_prefix);
399
400         if (defined $e->{CONFORMANT_SIZE}) {
401                 # the conformant size has already been pushed
402         } elsif (!util::is_inline_array($e)) {
403                 # we need to emit the array size
404                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));\n";
405         }
406
407         if (my $length = util::has_property($e, "length_is")) {
408                 $length = find_size_var($e, $length, $var_prefix);
409                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));\n";
410                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $length));\n";
411                 $size = $length;
412         }
413
414         if (is_scalar_type($e->{TYPE})) {
415                 pidl "\t\tNDR_CHECK(ndr_push_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));\n";
416         } else {
417                 pidl "\t\tNDR_CHECK(ndr_push_array(ndr, $ndr_flags, $var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_push_flags_fn_t)ndr_push_$e->{TYPE}));\n";
418         }
419 }
420
421 #####################################################################
422 # print an array
423 sub ParseArrayPrint($$)
424 {
425         my $e = shift;
426         my $var_prefix = shift;
427         my $size = find_size_var($e, util::array_size($e), $var_prefix);
428         my $length = util::has_property($e, "length_is");
429
430         if (defined $length) {
431                 $size = find_size_var($e, $length, $var_prefix);
432         }
433
434         if (is_scalar_type($e->{TYPE})) {
435                 pidl "\t\tndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME}, $size);\n";
436         } else {
437                 pidl "\t\tndr_print_array(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_print_fn_t)ndr_print_$e->{TYPE});\n";
438         }
439 }
440
441 #####################################################################
442 # check the size_is and length_is constraints
443 sub CheckArraySizes($$)
444 {
445         my $e = shift;
446         my $var_prefix = shift;
447
448         if (!defined $e->{CONFORMANT_SIZE} && 
449             util::has_property($e, "size_is")) {
450                 my $size = find_size_var($e, util::array_size($e), $var_prefix);
451                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
452                 check_null_pointer($size);
453                 pidl "\t\tNDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));\n";
454                 pidl "\t}\n";
455         }
456
457         if (my $length = util::has_property($e, "length_is")) {
458                 $length = find_size_var($e, $length, $var_prefix);
459                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
460                 check_null_pointer($length);
461                 pidl "\t\tNDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));\n";
462                 pidl "\t}\n";
463         }
464 }
465
466
467 #####################################################################
468 # parse an array - pull side
469 sub ParseArrayPull($$$)
470 {
471         my $e = shift;
472         my $var_prefix = shift;
473         my $ndr_flags = shift;
474
475         my $size = find_size_var($e, util::array_size($e), $var_prefix);
476         my $alloc_size = $size;
477
478         # if this is a conformant array then we use that size to allocate, and make sure
479         # we allocate enough to pull the elements
480         if (defined $e->{CONFORMANT_SIZE}) {
481                 $alloc_size = $e->{CONFORMANT_SIZE};
482                 check_null_pointer($size);
483                 pidl "\tif ($size > $alloc_size) {\n";
484                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $alloc_size, $size);\n";
485                 pidl "\t}\n";
486         } elsif (!util::is_inline_array($e)) {
487                 if ($var_prefix =~ /^r->out/ && $size =~ /^\*r->in/) {
488                         my $size2 = substr($size, 1);
489                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_ALLOC(ndr, $size2); }\n";
490                 }
491
492                 # non fixed arrays encode the size just before the array
493                 pidl "\t\tNDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));\n";
494                 $alloc_size = "ndr_get_array_size(ndr, &$var_prefix$e->{NAME})";
495         }
496
497         if ((need_alloc($e) && !util::is_fixed_array($e)) ||
498             ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
499                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
500                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
501                 }
502         }
503
504         if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
505                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
506                         pidl "\tif (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
507                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
508                         pidl "\t}\n";
509                 }
510         }
511
512         if (my $length = util::has_property($e, "length_is")) {
513                 pidl "\t\tNDR_CHECK(ndr_pull_array_length(ndr, &$var_prefix$e->{NAME}));\n";
514                 $size = "ndr_get_array_length(ndr, &$var_prefix$e->{NAME})";
515         }
516
517         check_null_pointer($size);
518         if (is_scalar_type($e->{TYPE})) {
519                 pidl "\t\tNDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));\n";
520         } else {
521                 pidl "\t\tNDR_CHECK(ndr_pull_array(ndr, $ndr_flags, (void **)$var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE}));\n";
522         }
523 }
524
525
526 #####################################################################
527 # parse scalars in a structure element
528 sub ParseElementPushScalar($$$)
529 {
530         my($e) = shift;
531         my($var_prefix) = shift;
532         my($ndr_flags) = shift;
533         my $cprefix = c_push_prefix($e);
534         my $sub_size = util::has_property($e, "subcontext");
535
536         start_flags($e);
537
538         if (my $value = util::has_property($e, "value")) {
539                 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;\n";
540         }
541
542         if (util::has_property($e, "relative")) {
543                 pidl "\tNDR_CHECK(ndr_push_relative1(ndr, $var_prefix$e->{NAME}));\n";
544         } elsif (util::is_inline_array($e)) {
545                 ParseArrayPush($e, "r->", "NDR_SCALARS");
546         } elsif (need_wire_pointer($e)) {
547                 pidl "\tNDR_CHECK(ndr_push_ptr(ndr, $var_prefix$e->{NAME}));\n";
548         } elsif (need_alloc($e)) {
549                 # no scalar component
550         } elsif (my $switch = util::has_property($e, "switch_is")) {
551                 ParseElementPushSwitch($e, $var_prefix, $ndr_flags, $switch);
552         } elsif (defined $sub_size) {
553                 pidl "\tNDR_CHECK(ndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE}));\n";
554         } else {
555                 pidl "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
556         }
557
558         end_flags($e);
559 }
560
561 #####################################################################
562 # print scalars in a structure element
563 sub ParseElementPrintScalar($$)
564 {
565         my($e) = shift;
566         my($var_prefix) = shift;
567         my $cprefix = c_push_prefix($e);
568
569         if (util::has_property($e, "noprint")) {
570                 return;
571         }
572
573         if (my $value = util::has_property($e, "value")) {
574                 pidl "\tif (ndr->flags & LIBNDR_PRINT_SET_VALUES) {\n";
575                 pidl "\t\t$cprefix$var_prefix$e->{NAME} = $value;\n";
576                 pidl "\t}\n";
577         }
578
579         if (util::is_fixed_array($e)) {
580                 ParseElementPrintBuffer($e, $var_prefix);
581         } elsif (util::has_direct_buffers($e)) {
582                 pidl "\tndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});\n";
583                 pidl "\tndr->depth++;\n";
584                 ParseElementPrintBuffer($e, $var_prefix);
585                 pidl "\tndr->depth--;\n";
586         } elsif (my $switch = util::has_property($e, "switch_is")) {
587                 ParseElementPrintSwitch($e, $var_prefix, $switch);
588         } else {
589                 pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
590         }
591 }
592
593 #####################################################################
594 # parse scalars in a structure element - pull size
595 sub ParseElementPullSwitch($$$$)
596 {
597         my($e) = shift;
598         my($var_prefix) = shift;
599         my($ndr_flags) = shift;
600         my $switch = shift;
601         my $switch_var = find_size_var($e, $switch, $var_prefix);
602
603         my $cprefix = c_pull_prefix($e);
604
605         my $utype = $typedefs{$e->{TYPE}};
606
607         check_null_pointer($switch_var);
608
609         if (!defined $utype ||
610             !util::has_property($utype, "nodiscriminant")) {
611                 my $e2 = find_sibling($e, $switch);
612                 my $type_decl = util::map_type($e2->{TYPE});
613                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
614                 if (util::is_enum($e2->{TYPE})) {
615                         $type_decl = util::enum_type_decl($e2);
616                 } elsif (util::is_bitmap($e2->{TYPE})) {
617                         $type_decl = util::bitmap_type_decl($e2);
618                 }
619                 pidl "\t\t$type_decl _level;\n";
620                 pidl "\t\tNDR_CHECK(ndr_pull_$e2->{TYPE}(ndr, NDR_SCALARS, &_level));\n";
621                 if ($switch_var =~ /r->in/) {
622                         pidl "\t\tif (!(ndr->flags & LIBNDR_FLAG_REF_ALLOC) && _level != $switch_var) {\n";
623                 } else {
624                         pidl "\t\tif (_level != $switch_var) {\n";
625                 }
626                 pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\", _level);\n";
627                 pidl "\t\t}\n";
628                 if ($switch_var =~ /r->/) {
629                         pidl "else { $switch_var = _level; }\n";
630                 }
631                 pidl "\t}\n";
632         }
633
634         my $sub_size = util::has_property($e, "subcontext");
635         if (defined $sub_size) {
636                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
637                 pidl "\t\tNDR_CHECK(ndr_pull_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_pull_union_fn_t) ndr_pull_$e->{TYPE}));\n";
638                 pidl "\t}\n";
639         } else {
640                 pidl "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));\n";
641         }
642
643
644 }
645
646 #####################################################################
647 # push switch element
648 sub ParseElementPushSwitch($$$$)
649 {
650         my($e) = shift;
651         my($var_prefix) = shift;
652         my($ndr_flags) = shift;
653         my $switch = shift;
654         my $switch_var = find_size_var($e, $switch, $var_prefix);
655         my $cprefix = c_push_prefix($e);
656
657         check_null_pointer($switch_var);
658
659         my $utype = $typedefs{$e->{TYPE}};
660         if (!defined $utype ||
661             !util::has_property($utype, "nodiscriminant")) {
662                 my $e2 = find_sibling($e, $switch);
663                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
664                 pidl "\t\tNDR_CHECK(ndr_push_$e2->{TYPE}(ndr, NDR_SCALARS, $switch_var));\n";
665                 pidl "\t}\n";
666         }
667
668         my $sub_size = util::has_property($e, "subcontext");
669         if (defined $sub_size) {
670                 pidl "\tif(($ndr_flags) & NDR_SCALARS) {\n";
671                 pidl "\t\tNDR_CHECK(ndr_push_subcontext_union_fn(ndr, $sub_size, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_push_union_fn_t) ndr_push_$e->{TYPE}));\n";
672                 pidl "\t}\n";
673         } else {
674                 pidl "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));\n";
675         }
676 }
677
678 #####################################################################
679 # print scalars in a structure element 
680 sub ParseElementPrintSwitch($$$)
681 {
682         my($e) = shift;
683         my($var_prefix) = shift;
684         my $switch = shift;
685         my $switch_var = find_size_var($e, $switch, $var_prefix);
686         my $cprefix = c_push_prefix($e);
687
688         check_null_pointer_void($switch_var);
689
690         pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});\n";
691 }
692
693
694 #####################################################################
695 # parse scalars in a structure element - pull size
696 sub ParseElementPullScalar($$$)
697 {
698         my($e) = shift;
699         my($var_prefix) = shift;
700         my($ndr_flags) = shift;
701         my $cprefix = c_pull_prefix($e);
702         my $sub_size = util::has_property($e, "subcontext");
703
704         start_flags($e);
705
706         if (util::is_inline_array($e)) {
707                 ParseArrayPull($e, "r->", "NDR_SCALARS");
708         } elsif (need_wire_pointer($e)) {
709                 pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
710                 pidl "\tif (_ptr_$e->{NAME}) {\n";
711                 pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
712                 if (util::has_property($e, "relative")) {
713                         pidl "\t\tNDR_CHECK(ndr_pull_relative1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));\n";
714                 }
715                 pidl "\t} else {\n";
716                 pidl "\t\t$var_prefix$e->{NAME} = NULL;\n";
717                 pidl "\t}\n";
718         } elsif (need_alloc($e)) {
719                 # no scalar component
720         } elsif (my $switch = util::has_property($e, "switch_is")) {
721                 ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch);
722         } elsif (defined $sub_size) {
723                 pidl "\tNDR_CHECK(ndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE}));\n";
724         } else {
725                 pidl "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
726         }
727         if (my $range = util::has_property($e, "range")) {
728                 my ($low, $high) = split(/ /, $range, 2);
729                 pidl "\tif ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {\n";
730                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_RANGE, \"value out of range\");\n\t}\n";
731         }
732
733         end_flags($e);
734 }
735
736 #####################################################################
737 # parse buffers in a structure element
738 sub ParseElementPushBuffer($$$)
739 {
740         my($e) = shift;
741         my($var_prefix) = shift;
742         my($ndr_flags) = shift;
743         my $cprefix = c_push_prefix($e);
744         my $sub_size = util::has_property($e, "subcontext");
745
746         if (is_pure_scalar($e)) {
747                 return;
748         }
749
750         start_flags($e);
751
752         if (need_wire_pointer($e)) {
753                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
754                 if (util::has_property($e, "relative")) {
755                         pidl "\t\tNDR_CHECK(ndr_push_relative2(ndr, $var_prefix$e->{NAME}));\n";
756                 }
757         }
758             
759         if (util::is_inline_array($e)) {
760                 ParseArrayPush($e, "r->", "NDR_BUFFERS");
761         } elsif (util::array_size($e)) {
762                 ParseArrayPush($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
763         } elsif (my $switch = util::has_property($e, "switch_is")) {
764                 if ($e->{POINTERS}) {
765                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS|NDR_SCALARS", $switch);
766                 } else {
767                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
768                 }
769         } elsif (defined $sub_size) {
770                 if ($e->{POINTERS}) {
771                         pidl "\tNDR_CHECK(ndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE}));\n";
772                 }
773         } elsif ($e->{POINTERS}) {
774                 pidl "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}));\n";
775         } else {
776                 pidl "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
777         }
778
779         if (need_wire_pointer($e)) {
780                 pidl "\t}\n";
781         }       
782
783         end_flags($e);
784 }
785
786 #####################################################################
787 # print buffers in a structure element
788 sub ParseElementPrintBuffer($$)
789 {
790         my($e) = shift;
791         my($var_prefix) = shift;
792         my $cprefix = c_push_prefix($e);
793
794         if (need_wire_pointer($e)) {
795                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
796         }
797             
798         if (util::array_size($e)) {
799                 ParseArrayPrint($e, $var_prefix)
800         } elsif (my $switch = util::has_property($e, "switch_is")) {
801                 ParseElementPrintSwitch($e, $var_prefix, $switch);
802         } else {
803                 pidl "\t\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
804         }
805
806         if (need_wire_pointer($e)) {
807                 pidl "\t}\n";
808         }       
809 }
810
811
812 #####################################################################
813 # parse buffers in a structure element - pull side
814 sub ParseElementPullBuffer($$$)
815 {
816         my($e) = shift;
817         my($var_prefix) = shift;
818         my($ndr_flags) = shift;
819         my $cprefix = c_pull_prefix($e);
820         my $sub_size = util::has_property($e, "subcontext");
821
822         if (is_pure_scalar($e)) {
823                 return;
824         }
825
826         start_flags($e);
827
828         if (need_wire_pointer($e)) {
829                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
830                 if (util::has_property($e, "relative")) {
831                         pidl "\t\tstruct ndr_pull_save _relative_save;\n";
832                         pidl "\t\tndr_pull_save(ndr, &_relative_save);\n";
833                         pidl "\t\tNDR_CHECK(ndr_pull_relative2(ndr, $var_prefix$e->{NAME}));\n";
834                 }
835         }
836             
837         if (util::is_inline_array($e)) {
838                 ParseArrayPull($e, "r->", "NDR_BUFFERS");
839         } elsif (util::array_size($e)) {
840                 ParseArrayPull($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
841         } elsif (my $switch = util::has_property($e, "switch_is")) {
842                 if ($e->{POINTERS}) {
843                         ParseElementPullSwitch($e, $var_prefix, "NDR_SCALARS|NDR_BUFFERS", $switch);
844                 } else {
845                         ParseElementPullSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
846                 }
847         } elsif (defined $sub_size) {
848                 if ($e->{POINTERS}) {
849                         pidl "\tNDR_CHECK(ndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE}));\n";
850                 }
851         } elsif ($e->{POINTERS}) {
852                 pidl "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}));\n";
853         } else {
854                 pidl "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
855         }
856
857         if (need_wire_pointer($e)) {
858                 if (util::has_property($e, "relative")) {
859                         pidl "\t\tndr_pull_restore(ndr, &_relative_save);\n";
860                 }
861                 pidl "\t}\n";
862         }       
863
864         end_flags($e);
865 }
866
867 #####################################################################
868 # parse a struct
869 sub ParseStructPush($)
870 {
871         my($struct) = shift;
872         
873         if (! defined $struct->{ELEMENTS}) {
874                 return;
875         }
876
877         start_flags($struct);
878
879         # see if the structure contains a conformant array. If it
880         # does, then it must be the last element of the structure, and
881         # we need to push the conformant length early, as it fits on
882         # the wire before the structure (and even before the structure
883         # alignment)
884         my $e = $struct->{ELEMENTS}[-1];
885         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
886                 my $size = find_size_var($e, util::array_size($e), "r->");
887                 $e->{CONFORMANT_SIZE} = $size;
888                 check_null_pointer($size);
889                 pidl "\tNDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, $size));\n";
890         }
891
892         if (defined $e->{TYPE} && $e->{TYPE} eq "string" 
893             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
894                 pidl "\tNDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, r->$e->{NAME})));\n";
895         }
896
897         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
898
899         pidl "\tNDR_CHECK(ndr_push_struct_start(ndr));\n";
900
901         my $align = struct_alignment($struct);
902         pidl "\tNDR_CHECK(ndr_push_align(ndr, $align));\n";
903
904         foreach my $e (@{$struct->{ELEMENTS}}) {
905                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
906         }       
907
908         pidl "buffers:\n";
909         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
910         foreach my $e (@{$struct->{ELEMENTS}}) {
911                 ParseElementPushBuffer($e, "r->", "NDR_BUFFERS");
912         }
913
914         pidl "\tndr_push_struct_end(ndr);\n";
915
916         pidl "done:\n";
917
918         end_flags($struct);
919 }
920
921
922 #####################################################################
923 # generate a push function for an enum
924 sub ParseEnumPush($)
925 {
926         my($enum) = shift;
927         my($type_fn) = util::enum_type_fn($enum);
928
929         start_flags($enum);
930
931         pidl "\tNDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));\n";
932
933         end_flags($enum);
934 }
935
936 #####################################################################
937 # generate a pull function for an enum
938 sub ParseEnumPull($)
939 {
940         my($enum) = shift;
941         my($type_fn) = util::enum_type_fn($enum);
942         my($type_v_decl) = util::map_type(util::enum_type_fn($enum));
943
944         pidl "\t$type_v_decl v;\n";
945         start_flags($enum);
946         pidl "\tNDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));\n";
947         pidl "\t*r = v;\n";
948
949         end_flags($enum);
950 }
951
952 #####################################################################
953 # generate a print function for an enum
954 sub ParseEnumPrint($)
955 {
956         my($enum) = shift;
957
958         pidl "\tconst char *val = NULL;\n\n";
959
960         start_flags($enum);
961
962         pidl "\tswitch (r) {\n";
963         my $els = \@{$enum->{ELEMENTS}};
964         foreach my $i (0 .. $#{$els}) {
965                 my $e = ${$els}[$i];
966                 chomp $e;
967                 if ($e =~ /^(.*)=/) {
968                         $e = $1;
969                 }
970                 pidl "\t\tcase $e: val = \"$e\"; break;\n";
971         }
972
973         pidl "\t}\n\n\tndr_print_enum(ndr, name, \"$enum->{TYPE}\", val, r);\n";
974
975         end_flags($enum);
976 }
977
978
979 #####################################################################
980 # generate a push function for a bitmap
981 sub ParseBitmapPush($)
982 {
983         my($bitmap) = shift;
984         my($type_fn) = util::bitmap_type_fn($bitmap);
985
986         start_flags($bitmap);
987
988         pidl "\tNDR_CHECK(ndr_push_$type_fn(ndr, NDR_SCALARS, r));\n";
989
990         end_flags($bitmap);
991 }
992
993 #####################################################################
994 # generate a pull function for an bitmap
995 sub ParseBitmapPull($)
996 {
997         my($bitmap) = shift;
998         my($type_fn) = util::bitmap_type_fn($bitmap);
999         my($type_decl) = util::bitmap_type_decl($bitmap);
1000
1001         pidl "\t$type_decl v;\n";
1002         start_flags($bitmap);
1003         pidl "\tNDR_CHECK(ndr_pull_$type_fn(ndr, NDR_SCALARS, &v));\n";
1004         pidl "\t*r = v;\n";
1005
1006         end_flags($bitmap);
1007 }
1008
1009 #####################################################################
1010 # generate a print function for an bitmap
1011 sub ParseBintmapPrintElement($$)
1012 {
1013         my($e) = shift;
1014         my($bitmap) = shift;
1015         my($type_decl) = util::bitmap_type_decl($bitmap);
1016         my($type_fn) = util::bitmap_type_fn($bitmap);
1017         my($name) = $bitmap->{PARENT}->{NAME};
1018         my($flag);
1019
1020         if ($e =~ /^(\w+) .*$/) {
1021                 $flag = "$1";
1022         } else {
1023                 die "Bitmap: \"$name\" invalid Flag: \"$e\"";
1024         }
1025
1026         pidl "\tndr_print_bitmap_flag(ndr, sizeof($type_decl), \"$flag\", $flag, r);\n";
1027 }
1028
1029 #####################################################################
1030 # generate a print function for an bitmap
1031 sub ParseBitmapPrint($)
1032 {
1033         my($bitmap) = shift;
1034         my($type_decl) = util::bitmap_type_decl($bitmap);
1035         my($type_fn) = util::bitmap_type_fn($bitmap);
1036
1037         start_flags($bitmap);
1038
1039         pidl "\tndr_print_$type_fn(ndr, name, r);\n";
1040
1041         pidl "\tndr->depth++;\n";
1042         foreach my $e (@{$bitmap->{ELEMENTS}}) {
1043                 ParseBintmapPrintElement($e, $bitmap);
1044         }
1045         pidl "\tndr->depth--;\n";
1046
1047         end_flags($bitmap);
1048 }
1049
1050 #####################################################################
1051 # generate a struct print function
1052 sub ParseStructPrint($)
1053 {
1054         my($struct) = shift;
1055
1056         if (! defined $struct->{ELEMENTS}) {
1057                 return;
1058         }
1059
1060         start_flags($struct);
1061
1062         pidl "\tndr->depth++;\n";
1063         foreach my $e (@{$struct->{ELEMENTS}}) {
1064                 ParseElementPrintScalar($e, "r->");
1065         }
1066         pidl "\tndr->depth--;\n";
1067
1068         end_flags($struct);
1069 }
1070
1071 #####################################################################
1072 # parse a struct - pull side
1073 sub ParseStructPull($)
1074 {
1075         my($struct) = shift;
1076         my $conform_e;
1077
1078         if (! defined $struct->{ELEMENTS}) {
1079                 return;
1080         }
1081
1082         # see if the structure contains a conformant array. If it
1083         # does, then it must be the last element of the structure, and
1084         # we need to pull the conformant length early, as it fits on
1085         # the wire before the structure (and even before the structure
1086         # alignment)
1087         my $e = $struct->{ELEMENTS}[-1];
1088         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
1089                 $conform_e = $e;
1090         }
1091
1092         if (defined $e->{TYPE} && $e->{TYPE} eq "string"
1093             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
1094                 $conform_e = $e;
1095         }
1096
1097         if (defined $conform_e) {
1098                 $conform_e = $e;
1099                 pidl "\tuint32_t _conformant_size;\n";
1100                 $conform_e->{CONFORMANT_SIZE} = "_conformant_size";
1101         }
1102
1103         # declare any internal pointers we need
1104         foreach my $e (@{$struct->{ELEMENTS}}) {
1105                 if (need_wire_pointer($e)) {
1106                         pidl "\tuint32_t _ptr_$e->{NAME};\n";
1107                 }
1108         }
1109
1110         start_flags($struct);
1111
1112         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
1113
1114         pidl "\tNDR_CHECK(ndr_pull_struct_start(ndr));\n";
1115
1116         if (defined $conform_e) {
1117                 pidl "\tNDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &$conform_e->{CONFORMANT_SIZE}));\n";
1118         }
1119
1120         my $align = struct_alignment($struct);
1121         pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1122
1123         foreach my $e (@{$struct->{ELEMENTS}}) {
1124                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
1125         }       
1126
1127         pidl "buffers:\n";
1128         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
1129         foreach my $e (@{$struct->{ELEMENTS}}) {
1130                 ParseElementPullBuffer($e, "r->", "NDR_BUFFERS");
1131         }
1132
1133         foreach my $e (@{$struct->{ELEMENTS}}) {
1134                 CheckArraySizes($e, "r->");
1135         }
1136
1137         pidl "\tndr_pull_struct_end(ndr);\n";
1138
1139         pidl "done:\n";
1140
1141         end_flags($struct);
1142 }
1143
1144 #####################################################################
1145 # calculate size of ndr struct
1146 sub ParseStructNdrSize($)
1147 {
1148         my $t = shift;
1149         my $static = fn_prefix($t);
1150         my $sizevar;
1151
1152         pidl "size_t ndr_size_$t->{NAME}(const struct $t->{NAME} *r, int flags)\n";
1153         pidl "{\n";
1154         if (my $flags = util::has_property($t, "flag")) {
1155                 pidl "\tflags |= $flags;\n";
1156         }
1157         pidl "\treturn ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_$t->{NAME});\n";
1158         pidl "}\n\n";
1159 }
1160
1161 #####################################################################
1162 # calculate size of ndr struct
1163 sub ParseUnionNdrSize($)
1164 {
1165         my $t = shift;
1166         my $static = fn_prefix($t);
1167         my $sizevar;
1168
1169         pidl "size_t ndr_size_$t->{NAME}(const union $t->{NAME} *r, int level, int flags)\n";
1170         pidl "{\n";
1171         if (my $flags = util::has_property($t, "flag")) {
1172                 pidl "\tflags |= $flags;\n";
1173         }
1174         pidl "\treturn ndr_size_union(r, flags, level, (ndr_push_union_fn_t)ndr_push_$t->{NAME});\n";
1175         pidl "}\n\n";
1176 }
1177
1178 #####################################################################
1179 # parse a union - push side
1180 sub ParseUnionPush($)
1181 {
1182         my $e = shift;
1183         my $have_default = 0;
1184
1185         start_flags($e);
1186
1187         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
1188
1189         pidl "\tNDR_CHECK(ndr_push_struct_start(ndr));\n";
1190
1191 #       my $align = union_alignment($e);
1192 #       pidl "\tNDR_CHECK(ndr_push_align(ndr, $align));\n";
1193
1194         pidl "\tswitch (level) {\n";
1195         foreach my $el (@{$e->{DATA}}) {
1196                 if ($el->{CASE} eq "default") {
1197                         pidl "\tdefault:\n";
1198                         $have_default = 1;
1199                 } else {
1200                         pidl "\tcase $el->{CASE}:\n";
1201                 }
1202                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1203                         ParseElementPushScalar($el->{DATA}, "r->", "NDR_SCALARS");
1204                 }
1205                 pidl "\tbreak;\n\n";
1206         }
1207         if (! $have_default) {
1208                 pidl "\tdefault:\n";
1209                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1210         }
1211         pidl "\t}\n";
1212         pidl "buffers:\n";
1213         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
1214         pidl "\tswitch (level) {\n";
1215         foreach my $el (@{$e->{DATA}}) {
1216                 if ($el->{CASE} eq "default") {
1217                         pidl "\tdefault:\n";
1218                 } else {
1219                         pidl "\tcase $el->{CASE}:\n";
1220                 }
1221                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1222                         ParseElementPushBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
1223                 }
1224                 pidl "\tbreak;\n\n";
1225         }
1226         if (! $have_default) {
1227                 pidl "\tdefault:\n";
1228                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1229         }
1230         pidl "\t}\n";
1231         pidl "\tndr_push_struct_end(ndr);\n";
1232         pidl "done:\n";
1233         end_flags($e);
1234 }
1235
1236 #####################################################################
1237 # print a union
1238 sub ParseUnionPrint($)
1239 {
1240         my $e = shift;
1241         my $have_default = 0;
1242
1243         start_flags($e);
1244
1245         pidl "\tswitch (level) {\n";
1246         foreach my $el (@{$e->{DATA}}) {
1247                 if ($el->{CASE} eq "default") {
1248                         $have_default = 1;
1249                         pidl "\tdefault:\n";
1250                 } else {
1251                         pidl "\tcase $el->{CASE}:\n";
1252                 }
1253                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1254                         ParseElementPrintScalar($el->{DATA}, "r->");
1255                 }
1256                 pidl "\tbreak;\n\n";
1257         }
1258         if (! $have_default) {
1259                 pidl "\tdefault:\n\t\tndr_print_bad_level(ndr, name, level);\n";
1260         }
1261         pidl "\t}\n";
1262
1263         end_flags($e);
1264 }
1265
1266 #####################################################################
1267 # parse a union - pull side
1268 sub ParseUnionPull($)
1269 {
1270         my $e = shift;
1271         my $have_default = 0;
1272
1273         start_flags($e);
1274
1275         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
1276
1277         pidl "\tNDR_CHECK(ndr_pull_struct_start(ndr));\n";
1278
1279 #       my $align = union_alignment($e);
1280 #       pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1281
1282         pidl "\tswitch (level) {\n";
1283         foreach my $el (@{$e->{DATA}}) {
1284                 if ($el->{CASE} eq "default") {
1285                         pidl "\tdefault: {\n";
1286                         $have_default = 1;
1287                 } else {
1288                         pidl "\tcase $el->{CASE}: {\n";
1289                 }
1290                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1291                         my $e2 = $el->{DATA};
1292                         if ($e2->{POINTERS}) {
1293                                 pidl "\t\tuint32_t _ptr_$e2->{NAME};\n";
1294                         }
1295                         ParseElementPullScalar($el->{DATA}, "r->", "NDR_SCALARS");
1296                 }
1297                 pidl "\tbreak; }\n\n";
1298         }
1299         if (! $have_default) {
1300                 pidl "\tdefault:\n";
1301                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1302         }
1303         pidl "\t}\n";
1304         pidl "buffers:\n";
1305         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
1306         pidl "\tswitch (level) {\n";
1307         foreach my $el (@{$e->{DATA}}) {
1308                 if ($el->{CASE} eq "default") {
1309                         pidl "\tdefault:\n";
1310                 } else {
1311                         pidl "\tcase $el->{CASE}:\n";
1312                 }
1313                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1314                         ParseElementPullBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
1315                 }
1316                 pidl "\tbreak;\n\n";
1317         }
1318         if (! $have_default) {
1319                 pidl "\tdefault:\n";
1320                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1321         }
1322         pidl "\t}\n";
1323         pidl "\tndr_pull_struct_end(ndr);\n";
1324         pidl "done:\n";
1325         end_flags($e);
1326 }
1327
1328
1329 #####################################################################
1330 # parse a type
1331 sub ParseTypePush($)
1332 {
1333         my($data) = shift;
1334
1335         if (ref($data) eq "HASH") {
1336                 ($data->{TYPE} eq "STRUCT") &&
1337                     ParseStructPush($data);
1338                 ($data->{TYPE} eq "UNION") &&
1339                     ParseUnionPush($data);
1340                 ($data->{TYPE} eq "ENUM") &&
1341                     ParseEnumPush($data);
1342                 ($data->{TYPE} eq "BITMAP") &&
1343                     ParseBitmapPush($data);
1344         }
1345 }
1346
1347 #####################################################################
1348 # generate a print function for a type
1349 sub ParseTypePrint($)
1350 {
1351         my($data) = shift;
1352
1353         if (ref($data) eq "HASH") {
1354                 ($data->{TYPE} eq "STRUCT") &&
1355                     ParseStructPrint($data);
1356                 ($data->{TYPE} eq "UNION") &&
1357                     ParseUnionPrint($data);
1358                 ($data->{TYPE} eq "ENUM") &&
1359                     ParseEnumPrint($data);
1360                 ($data->{TYPE} eq "BITMAP") &&
1361                     ParseBitmapPrint($data);
1362         }
1363 }
1364
1365 #####################################################################
1366 # parse a type
1367 sub ParseTypePull($)
1368 {
1369         my($data) = shift;
1370
1371         if (ref($data) eq "HASH") {
1372                 ($data->{TYPE} eq "STRUCT") &&
1373                     ParseStructPull($data);
1374                 ($data->{TYPE} eq "UNION") &&
1375                     ParseUnionPull($data);
1376                 ($data->{TYPE} eq "ENUM") &&
1377                     ParseEnumPull($data);
1378                 ($data->{TYPE} eq "BITMAP") &&
1379                     ParseBitmapPull($data);
1380         }
1381 }
1382
1383 #####################################################################
1384 # parse a typedef - push side
1385 sub ParseTypedefPush($)
1386 {
1387         my($e) = shift;
1388         my $static = fn_prefix($e);
1389
1390         if (! needed::is_needed("push_$e->{NAME}")) {
1391 #               print "push_$e->{NAME} not needed\n";
1392                 return;
1393         }
1394
1395         if (defined($e->{PROPERTIES}) && !defined($e->{DATA}->{PROPERTIES})) {
1396                 $e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
1397         }
1398
1399         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1400                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r)";
1401                 pidl "\n{\n";
1402                 ParseTypePush($e->{DATA});
1403                 pidl "\treturn NT_STATUS_OK;\n";
1404                 pidl "}\n\n";
1405         }
1406
1407         if ($e->{DATA}->{TYPE} eq "UNION") {
1408                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, int level, union $e->{NAME} *r)";
1409                 pidl "\n{\n";
1410                 ParseTypePush($e->{DATA});
1411                 pidl "\treturn NT_STATUS_OK;\n";
1412                 pidl "}\n\n";
1413         }
1414
1415         if ($e->{DATA}->{TYPE} eq "ENUM") {
1416                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, enum $e->{NAME} r)";
1417                 pidl "\n{\n";
1418                 ParseTypePush($e->{DATA});
1419                 pidl "\treturn NT_STATUS_OK;\n";
1420                 pidl "}\n\n";
1421         }
1422
1423         if ($e->{DATA}->{TYPE} eq "BITMAP") {
1424                 my $type_decl = util::bitmap_type_decl($e->{DATA});
1425                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, $type_decl r)";
1426                 pidl "\n{\n";
1427                 ParseTypePush($e->{DATA});
1428                 pidl "\treturn NT_STATUS_OK;\n";
1429                 pidl "}\n\n";
1430         }
1431 }
1432
1433
1434 #####################################################################
1435 # parse a typedef - pull side
1436 sub ParseTypedefPull($)
1437 {
1438         my($e) = shift;
1439         my $static = fn_prefix($e);
1440
1441         if (defined($e->{PROPERTIES}) && !defined($e->{DATA}->{PROPERTIES})) {
1442                 $e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
1443         }
1444
1445         if (! needed::is_needed("pull_$e->{NAME}")) {
1446 #               print "pull_$e->{NAME} not needed\n";
1447                 return;
1448         }
1449
1450         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1451                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r)";
1452                 pidl "\n{\n";
1453                 ParseTypePull($e->{DATA});
1454                 pidl "\treturn NT_STATUS_OK;\n";
1455                 pidl "}\n\n";
1456         }
1457
1458         if ($e->{DATA}->{TYPE} eq "UNION") {
1459                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, int level, union $e->{NAME} *r)";
1460                 pidl "\n{\n";
1461                 ParseTypePull($e->{DATA});
1462                 pidl "\treturn NT_STATUS_OK;\n";
1463                 pidl "}\n\n";
1464         }
1465
1466         if ($e->{DATA}->{TYPE} eq "ENUM") {
1467                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, enum $e->{NAME} *r)";
1468                 pidl "\n{\n";
1469                 ParseTypePull($e->{DATA});
1470                 pidl "\treturn NT_STATUS_OK;\n";
1471                 pidl "}\n\n";
1472         }
1473
1474         if ($e->{DATA}->{TYPE} eq "BITMAP") {
1475                 my $type_decl = util::bitmap_type_decl($e->{DATA});
1476                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, $type_decl *r)";
1477                 pidl "\n{\n";
1478                 ParseTypePull($e->{DATA});
1479                 pidl "\treturn NT_STATUS_OK;\n";
1480                 pidl "}\n\n";
1481         }
1482 }
1483
1484
1485 #####################################################################
1486 # parse a typedef - print side
1487 sub ParseTypedefPrint($)
1488 {
1489         my($e) = shift;
1490
1491         if (defined($e->{PROPERTIES}) && !defined($e->{DATA}->{PROPERTIES})) {
1492                 $e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
1493         }
1494
1495         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1496                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, struct $e->{NAME} *r)";
1497                 pidl "\n{\n";
1498                 pidl "\tndr_print_struct(ndr, name, \"$e->{NAME}\");\n";
1499                 ParseTypePrint($e->{DATA});
1500                 pidl "}\n\n";
1501         }
1502
1503         if ($e->{DATA}->{TYPE} eq "UNION") {
1504                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, int level, union $e->{NAME} *r)";
1505                 pidl "\n{\n";
1506                 pidl "\tndr_print_union(ndr, name, level, \"$e->{NAME}\");\n";
1507                 ParseTypePrint($e->{DATA});
1508                 pidl "}\n\n";
1509         }
1510
1511         if ($e->{DATA}->{TYPE} eq "ENUM") {
1512                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, enum $e->{NAME} r)";
1513                 pidl "\n{\n";
1514                 ParseTypePrint($e->{DATA});
1515                 pidl "}\n\n";
1516         }
1517
1518         if ($e->{DATA}->{TYPE} eq "BITMAP") {
1519                 my $type_decl = util::bitmap_type_decl($e->{DATA});
1520                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, $type_decl r)";
1521                 pidl "\n{\n";
1522                 ParseTypePrint($e->{DATA});
1523                 pidl "}\n\n";
1524         }
1525 }
1526
1527 #####################################################################
1528 ## calculate the size of a structure
1529 sub ParseTypedefNdrSize($)
1530 {
1531         my($t) = shift;
1532         if (! needed::is_needed("ndr_size_$t->{NAME}")) {
1533                 return;
1534         }
1535         
1536         ($t->{DATA}->{TYPE} eq "STRUCT") &&
1537                 ParseStructNdrSize($t);
1538
1539         ($t->{DATA}->{TYPE} eq "UNION") &&
1540                 ParseUnionNdrSize($t);
1541 }
1542
1543 #####################################################################
1544 # parse a function - print side
1545 sub ParseFunctionPrint($)
1546 {
1547         my($fn) = shift;
1548
1549         pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)";
1550         pidl "\n{\n";
1551         pidl "\tndr_print_struct(ndr, name, \"$fn->{NAME}\");\n";
1552         pidl "\tndr->depth++;\n";
1553
1554         pidl "\tif (flags & NDR_SET_VALUES) {\n";
1555         pidl "\t\tndr->flags |= LIBNDR_PRINT_SET_VALUES;\n";
1556         pidl "\t}\n";
1557
1558         pidl "\tif (flags & NDR_IN) {\n";
1559         pidl "\t\tndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");\n";
1560         pidl "\tndr->depth++;\n";
1561         foreach my $e (@{$fn->{DATA}}) {
1562                 if (util::has_property($e, "in")) {
1563                         ParseElementPrintScalar($e, "r->in.");
1564                 }
1565         }
1566         pidl "\tndr->depth--;\n";
1567         pidl "\t}\n";
1568         
1569         pidl "\tif (flags & NDR_OUT) {\n";
1570         pidl "\t\tndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");\n";
1571         pidl "\tndr->depth++;\n";
1572         foreach my $e (@{$fn->{DATA}}) {
1573                 if (util::has_property($e, "out")) {
1574                         ParseElementPrintScalar($e, "r->out.");
1575                 }
1576         }
1577         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1578                 my $cprefix = "&";
1579                 $cprefix = "" if (is_scalar_type($fn->{RETURN_TYPE})) ; # FIXME: Should really use util::c_push_prefix here
1580                 pidl "\tndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", $cprefix"."r->out.result);\n";
1581         }
1582         pidl "\tndr->depth--;\n";
1583         pidl "\t}\n";
1584         
1585         pidl "\tndr->depth--;\n";
1586         pidl "}\n\n";
1587 }
1588
1589
1590 #####################################################################
1591 # parse a function element
1592 sub ParseFunctionElementPush($$)
1593
1594         my $e = shift;
1595         my $inout = shift;
1596
1597         if (util::array_size($e)) {
1598                 if (need_wire_pointer($e)) {
1599                         pidl "\tNDR_CHECK(ndr_push_ptr(ndr, r->$inout.$e->{NAME}));\n";
1600                         pidl "\tif (r->$inout.$e->{NAME}) {\n";
1601                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1602                         pidl "\t}\n";
1603                 } else {
1604                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1605                 }
1606         } else {
1607                 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1608
1609                 if ($e->{POINTERS}) {
1610                         ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1611                 }
1612         }
1613 }       
1614
1615 #####################################################################
1616 # parse a function
1617 sub ParseFunctionPush($)
1618
1619         my($fn) = shift;
1620         my $static = fn_prefix($fn);
1621
1622         pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)\n{\n";
1623
1624         pidl "\n\tif (!(flags & NDR_IN)) goto ndr_out;\n\n";
1625
1626         foreach my $e (@{$fn->{DATA}}) {
1627                 if (util::has_property($e, "in")) {
1628                         ParseFunctionElementPush($e, "in");
1629                 }               
1630         }
1631
1632         pidl "\nndr_out:\n";
1633         pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
1634
1635         foreach my $e (@{$fn->{DATA}}) {
1636                 if (util::has_property($e, "out")) {
1637                         ParseFunctionElementPush($e, "out");
1638                 }               
1639         }
1640
1641         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1642                 pidl "\tNDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, r->out.result));\n";
1643         }
1644     
1645         pidl "\ndone:\n";
1646         pidl "\n\treturn NT_STATUS_OK;\n}\n\n";
1647 }
1648
1649 #####################################################################
1650 # parse a function element
1651 sub ParseFunctionElementPull($$)
1652
1653         my $e = shift;
1654         my $inout = shift;
1655
1656         if (util::array_size($e)) {
1657                 if (need_wire_pointer($e)) {
1658                         pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
1659                         pidl "\tr->$inout.$e->{NAME} = NULL;\n";
1660                         pidl "\tif (_ptr_$e->{NAME}) {\n";
1661                 } elsif ($inout eq "out" && util::has_property($e, "ref")) {
1662                         pidl "\tif (r->$inout.$e->{NAME}) {\n";
1663                 } else {
1664                         pidl "\t{\n";
1665                 }
1666                 ParseArrayPull($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1667                 pidl "\t}\n";
1668         } else {
1669                 if ($inout eq "out" && util::has_property($e, "ref")) {
1670                         pidl "\tif (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\n";
1671                         pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
1672                         pidl "\t}\n";
1673                 }
1674                 if ($inout eq "in" && util::has_property($e, "ref")) {
1675                         pidl "\tNDR_ALLOC(ndr, r->in.$e->{NAME});\n";
1676                 }
1677
1678                 ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1679                 if ($e->{POINTERS}) {
1680                         ParseElementPullBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1681                 }
1682         }
1683 }
1684
1685
1686 ############################################################
1687 # allocate ref variables
1688 sub AllocateRefVars($)
1689 {
1690         my $e = shift;
1691         my $asize = util::array_size($e);
1692
1693         # note that if the variable is also an "in"
1694         # variable then we copy the initial value from
1695         # the in side
1696
1697         if (!defined $asize) {
1698                 # its a simple variable
1699                 pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
1700                 if (util::has_property($e, "in")) {
1701                         pidl "\t*r->out.$e->{NAME} = *r->in.$e->{NAME};\n";
1702                 } else {
1703                         pidl "\tZERO_STRUCTP(r->out.$e->{NAME});\n";
1704                 }
1705                 return;
1706         }
1707
1708         # its an array
1709         my $size = find_size_var($e, $asize, "r->out.");
1710         check_null_pointer($size);
1711         pidl "\tNDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);\n";
1712         if (util::has_property($e, "in")) {
1713                 pidl "\tmemcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));\n";
1714         } else {
1715                 pidl "\tmemset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));\n";
1716         }
1717 }
1718
1719
1720 #####################################################################
1721 # parse a function
1722 sub ParseFunctionPull($)
1723
1724         my($fn) = shift;
1725         my $static = fn_prefix($fn);
1726
1727         # pull function args
1728         pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)\n{\n";
1729
1730         # declare any internal pointers we need
1731         foreach my $e (@{$fn->{DATA}}) {
1732                 if (need_wire_pointer($e)) {
1733                         pidl "\tuint32_t _ptr_$e->{NAME};\n";
1734                 }
1735         }
1736
1737         pidl "\n\tif (!(flags & NDR_IN)) goto ndr_out;\n\n";
1738
1739         # auto-init the out section of a structure. I originally argued that
1740         # this was a bad idea as it hides bugs, but coping correctly
1741         # with initialisation and not wiping ref vars is turning
1742         # out to be too tricky (tridge)
1743         foreach my $e (@{$fn->{DATA}}) {
1744                 if (util::has_property($e, "out")) {
1745                         pidl "\tZERO_STRUCT(r->out);\n\n";
1746                         last;
1747                 }
1748         }
1749
1750         foreach my $e (@{$fn->{DATA}}) {
1751                 if (util::has_property($e, "in")) {
1752                         ParseFunctionElementPull($e, "in");
1753                 }
1754                 # we need to allocate any reference output variables, so that
1755                 # a dcerpc backend can be sure they are non-null
1756                 if (util::has_property($e, "out") && util::has_property($e, "ref")) {
1757                         AllocateRefVars($e);
1758                 }
1759         }
1760
1761         foreach my $e (@{$fn->{DATA}}) {
1762                 if (util::has_property($e, "in")) {
1763                         CheckArraySizes($e, "r->in.");
1764                 }
1765         }
1766
1767         pidl "\nndr_out:\n";
1768         pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
1769
1770         foreach my $e (@{$fn->{DATA}}) {
1771                 if (util::has_property($e, "out")) {
1772                         ParseFunctionElementPull($e, "out");
1773                 }
1774         }
1775
1776         foreach my $e (@{$fn->{DATA}}) {
1777                 if (util::has_property($e, "out")) {
1778                         CheckArraySizes($e, "r->out.");
1779                 }
1780         }
1781
1782         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1783                 pidl "\tNDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, NDR_SCALARS, &r->out.result));\n";
1784         }
1785
1786         pidl "\ndone:\n";
1787         pidl "\n\treturn NT_STATUS_OK;\n}\n\n";
1788 }
1789
1790 #####################################################################
1791 # produce a function call table
1792 sub FunctionTable($)
1793 {
1794         my($interface) = shift;
1795         my($data) = $interface->{INHERITED_DATA};
1796         my $count = 0;
1797         my $uname = uc $interface->{NAME};
1798
1799         foreach my $d (@{$data}) {
1800                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
1801         }
1802
1803         return if ($count == 0);
1804
1805         pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {\n";
1806         foreach my $d (@{$data}) {
1807                 if ($d->{TYPE} eq "FUNCTION") {
1808                         pidl "\t{\n";
1809                         pidl "\t\t\"$d->{NAME}\",\n";
1810                         pidl "\t\tsizeof(struct $d->{NAME}),\n";
1811                         pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},\n";
1812                         pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},\n";
1813                         pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}\n";
1814                         pidl "\t},\n";
1815                 }
1816         }
1817         pidl "\t{ NULL, 0, NULL, NULL, NULL }\n};\n\n";
1818
1819         # If no endpoint is set, default to the interface name as a named pipe
1820         if (! defined $interface->{PROPERTIES}->{endpoint}) {
1821                 $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\"";
1822         }
1823
1824         my @e = split / /, $interface->{PROPERTIES}->{endpoint};
1825         my $endpoint_count = $#e + 1;
1826
1827         pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {\n";
1828         foreach my $ep (@e) {
1829                 pidl "\t$ep, \n";
1830         }
1831         pidl "};\n\n";
1832
1833         pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {\n";
1834         pidl "\t$endpoint_count, $interface->{NAME}\_endpoint_strings\n";
1835         pidl "};\n\n";
1836
1837         pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {\n";
1838         pidl "\t\"$interface->{NAME}\",\n";
1839         pidl "\tDCERPC_$uname\_UUID,\n";
1840         pidl "\tDCERPC_$uname\_VERSION,\n";
1841         pidl "\tDCERPC_$uname\_HELPSTRING,\n";
1842         pidl "\t$count,\n";
1843         pidl "\t$interface->{NAME}\_calls,\n";
1844         pidl "\t&$interface->{NAME}\_endpoints\n";
1845         pidl "};\n\n";
1846
1847         pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)\n";
1848         pidl "{\n";
1849         pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});\n";
1850         pidl "}\n\n";
1851 }
1852
1853 #####################################################################
1854 # parse the interface definitions
1855 sub ParseInterface($)
1856 {
1857         my($interface) = shift;
1858         my($data) = $interface->{DATA};
1859
1860         foreach my $d (@{$data}) {
1861                 if ($d->{TYPE} eq "DECLARE") {
1862                     $typedefs{$d->{NAME}} = $d;
1863                 }
1864                 if ($d->{TYPE} eq "TYPEDEF") {
1865                     $typedefs{$d->{NAME}} = $d;
1866                 }
1867         }
1868
1869         foreach my $d (@{$data}) {
1870                 ($d->{TYPE} eq "TYPEDEF") &&
1871                     ParseTypedefPush($d);
1872                 ($d->{TYPE} eq "FUNCTION") && 
1873                     ParseFunctionPush($d);
1874         }
1875         foreach my $d (@{$data}) {
1876                 ($d->{TYPE} eq "TYPEDEF") &&
1877                     ParseTypedefPull($d);
1878                 ($d->{TYPE} eq "FUNCTION") && 
1879                     ParseFunctionPull($d);
1880         }
1881         foreach my $d (@{$data}) {
1882                 if ($d->{TYPE} eq "TYPEDEF" &&
1883                     !util::has_property($d, "noprint")) {
1884                         ParseTypedefPrint($d);
1885                 }
1886                 if ($d->{TYPE} eq "FUNCTION" &&
1887                     !util::has_property($d, "noprint")) {
1888                         ParseFunctionPrint($d);
1889                 }
1890         }
1891
1892         foreach my $d (@{$data}) {
1893                 ($d->{TYPE} eq "TYPEDEF") && 
1894                         ParseTypedefNdrSize($d);
1895         }
1896
1897         FunctionTable($interface);
1898 }
1899
1900 sub RegistrationFunction($$)
1901 {
1902         my $idl = shift;
1903         my $filename = shift;
1904
1905         $filename =~ /.*\/ndr_(.*).c/;
1906         my $basename = $1;
1907         pidl "NTSTATUS dcerpc_$basename\_init(void)\n";
1908         pidl "{\n";
1909         pidl "\tNTSTATUS status = NT_STATUS_OK;\n";
1910         foreach my $interface (@{$idl}) {
1911                 next if $interface->{TYPE} ne "INTERFACE";
1912
1913                 my $data = $interface->{INHERITED_DATA};
1914                 my $count = 0;
1915                 foreach my $d (@{$data}) {
1916                         if ($d->{TYPE} eq "FUNCTION") { $count++; }
1917                 }
1918
1919                 next if ($count == 0);
1920
1921                 pidl "\tstatus = dcerpc_ndr_$interface->{NAME}_init();\n";
1922                 pidl "\tif (NT_STATUS_IS_ERR(status)) {\n";
1923                 pidl "\t\treturn status;\n";
1924                 pidl "\t}\n\n";
1925         }
1926         pidl "\treturn status;\n";
1927         pidl "}\n\n";
1928 }
1929
1930 #####################################################################
1931 # parse a parsed IDL structure back into an IDL file
1932 sub Parse($$)
1933 {
1934         my($idl) = shift;
1935         my($filename) = shift;
1936         my $h_filename = $filename;
1937         $res = "";
1938
1939         if ($h_filename =~ /(.*)\.c/) {
1940                 $h_filename = "$1.h";
1941         }
1942
1943         pidl "/* parser auto-generated by pidl */\n\n";
1944         pidl "#include \"includes.h\"\n";
1945         pidl "#include \"$h_filename\"\n\n";
1946
1947         foreach my $x (@{$idl}) {
1948                 if ($x->{TYPE} eq "INTERFACE") { 
1949                         needed::BuildNeeded($x);
1950                         ParseInterface($x);
1951                 }
1952         }
1953
1954         RegistrationFunction($idl, $filename);
1955
1956         return $res;
1957 }
1958
1959 1;
1960
1961 #Each type can:
1962 #
1963 #- Generate push fn
1964 #- Generate pull fn
1965 #- Generate print fn
1966 #- Generate push array fn
1967 #- Generate pull array fn
1968 #- Generate print fn
1969 #- align size
1970 #- "push prefix"