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