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