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