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