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