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