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