4461bb77af25d32e97e00aa9c70990042d745271
[samba.git] / source4 / build / pidl / parser.pm
1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001
5 # Copyright jelmer@samba.org 2004
6 # released under the GNU GPL
7
8 package IdlParser;
9
10 use strict;
11 use needed;
12
13 # the list of needed functions
14 my %structs;
15
16 sub pidl($)
17 {
18         print OUT shift;
19 }
20
21 #####################################################################
22 # parse a properties list
23 sub ParseProperties($)
24 {
25     my($props) = shift;
26     foreach my $d (@{$props}) {
27         if (ref($d) ne "HASH") {
28             pidl "[$d] ";
29         } else {
30             foreach my $k (keys %{$d}) {
31                 pidl "[$k($d->{$k})] ";
32             }
33         }
34     }
35 }
36
37 ###################################
38 # find a sibling var in a structure
39 sub find_sibling($$)
40 {
41         my($e) = shift;
42         my($name) = shift;
43         my($fn) = $e->{PARENT};
44
45         if ($name =~ /\*(.*)/) {
46                 $name = $1;
47         }
48
49         if ($fn->{TYPE} eq "FUNCTION") {
50                 for my $e2 (@{$fn->{DATA}}) {
51                         if ($e2->{NAME} eq $name) {
52                                 return $e2;
53                         }
54                 }
55         }
56
57         for my $e2 (@{$fn->{ELEMENTS}}) {
58                 if ($e2->{NAME} eq $name) {
59                         return $e2;
60                 }
61         }
62         die "invalid sibling '$name'";
63 }
64
65 ####################################################################
66 # work out the name of a size_is() variable
67 sub find_size_var($$$)
68 {
69         my($e) = shift;
70         my($size) = shift;
71         my($var_prefix) = shift;
72
73         my($fn) = $e->{PARENT};
74
75         if (util::is_constant($size)) {
76                 return $size;
77         }
78
79         if ($size =~ /ndr->|\(/) {
80                 return $size;
81         }
82
83         my $prefix = "";
84
85         if ($size =~ /\*(.*)/) {
86                 $size = $1;
87                 $prefix = "*";
88         }
89
90         if ($fn->{TYPE} ne "FUNCTION") {
91                 return $prefix . "r->$size";
92         }
93
94         my $e2 = find_sibling($e, $size);
95
96         if (util::has_property($e2, "in") && util::has_property($e2, "out")) {
97                 return $prefix . "$var_prefix$size";
98         }
99         if (util::has_property($e2, "in")) {
100                 return $prefix . "r->in.$size";
101         }
102         if (util::has_property($e2, "out")) {
103                 return $prefix . "r->out.$size";
104         }
105
106         die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
107 }
108
109
110 #####################################################################
111 # work out is a parse function should be declared static or not
112 sub fn_prefix($)
113 {
114         my $fn = shift;
115         if ($fn->{TYPE} eq "TYPEDEF") {
116                 if (util::has_property($fn->{DATA}, "public")) {
117                         return "";
118                 }
119         }
120
121         if ($fn->{TYPE} eq "FUNCTION") {
122                 if (util::has_property($fn, "public")) {
123                         return "";
124                 }
125         }
126         return "static ";
127 }
128
129
130 ###################################################################
131 # setup any special flags for an element or structure
132 sub start_flags($)
133 {
134         my $e = shift;
135         my $flags = util::has_property($e, "flag");
136         if (defined $flags) {
137                 pidl "\t{ uint32_t _flags_save_$e->{TYPE} = ndr->flags;\n";
138                 pidl "\tndr_set_flags(&ndr->flags, $flags);\n";
139         }
140 }
141
142 ###################################################################
143 # end any special flags for an element or structure
144 sub end_flags($)
145 {
146         my $e = shift;
147         my $flags = util::has_property($e, "flag");
148         if (defined $flags) {
149                 pidl "\tndr->flags = _flags_save_$e->{TYPE};\n\t}\n";
150         }
151 }
152
153
154 #####################################################################
155 # work out the correct alignment for a structure
156 sub struct_alignment
157 {
158         my $s = shift;
159
160         my $align = 1;
161         for my $e (@{$s->{ELEMENTS}}) {
162                 my $a = 1;
163
164                 if (!util::need_wire_pointer($e)
165                     && defined $structs{$e->{TYPE}}) {
166                         if ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "STRUCT") {
167                                 $a = struct_alignment($structs{$e->{TYPE}}->{DATA});
168                         } elsif ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "UNION") {
169                                 if (defined $structs{$e->{TYPE}}->{DATA}) {
170                                         $a = union_alignment($structs{$e->{TYPE}}->{DATA});
171                                 }
172                         }
173                 } else {
174                         $a = util::type_align($e);
175                 }
176
177                 if ($align < $a) {
178                         $align = $a;
179                 }
180         }
181
182         return $align;
183 }
184
185 #####################################################################
186 # work out the correct alignment for a union
187 sub union_alignment
188 {
189         my $u = shift;
190
191         my $align = 1;
192
193         foreach my $e (@{$u->{DATA}}) {
194                 my $a = 1;
195
196                 if ($e->{TYPE} eq "EMPTY") {
197                         next;
198                 }
199
200                 if (!util::need_wire_pointer($e)
201                     && defined $structs{$e->{DATA}->{TYPE}}) {
202                         my $s = $structs{$e->{DATA}->{TYPE}};
203                         if ($s->{DATA}->{TYPE} eq "STRUCT") {
204                                 $a = struct_alignment($s->{DATA});
205                         } elsif ($s->{DATA}->{TYPE} eq "UNION") {
206                                 $a = union_alignment($s->{DATA});
207                         }
208                 } else {
209                         $a = util::type_align($e->{DATA});
210                 }
211
212                 if ($align < $a) {
213                         $align = $a;
214                 }
215         }
216
217         return $align;
218 }
219
220 #####################################################################
221 # parse an array - push side
222 sub ParseArrayPush($$$)
223 {
224         my $e = shift;
225         my $var_prefix = shift;
226         my $ndr_flags = shift;
227
228         my $size = find_size_var($e, util::array_size($e), $var_prefix);
229
230         if (defined $e->{CONFORMANT_SIZE}) {
231                 # the conformant size has already been pushed
232         } elsif (!util::is_inline_array($e)) {
233                 # we need to emit the array size
234                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, $size));\n";
235         }
236
237         if (my $length = util::has_property($e, "length_is")) {
238                 $length = find_size_var($e, $length, $var_prefix);
239                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, 0));\n";
240                 pidl "\t\tNDR_CHECK(ndr_push_uint32(ndr, $length));\n";
241                 $size = $length;
242         }
243
244         if (util::is_scalar_type($e->{TYPE})) {
245                 pidl "\t\tNDR_CHECK(ndr_push_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));\n";
246         } else {
247                 pidl "\t\tNDR_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}));\n";
248         }
249 }
250
251 #####################################################################
252 # print an array
253 sub ParseArrayPrint($$)
254 {
255         my $e = shift;
256         my $var_prefix = shift;
257         my $size = find_size_var($e, util::array_size($e), $var_prefix);
258         my $length = util::has_property($e, "length_is");
259
260         if (defined $length) {
261                 $size = find_size_var($e, $length, $var_prefix);
262         }
263
264         if (util::is_scalar_type($e->{TYPE})) {
265                 pidl "\t\tndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME}, $size);\n";
266         } else {
267                 pidl "\t\tndr_print_array(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_print_fn_t)ndr_print_$e->{TYPE});\n";
268         }
269 }
270
271 #####################################################################
272 # check the size_is and length_is constraints
273 sub CheckArraySizes($$)
274 {
275         my $e = shift;
276         my $var_prefix = shift;
277
278         if (util::has_property($e, "size_is")) {
279                 my $size = find_size_var($e, util::array_size($e), $var_prefix);
280                 pidl "\tNDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));\n";
281         }
282
283         if (my $length = util::has_property($e, "length_is")) {
284                 $length = find_size_var($e, $length, $var_prefix);
285                 pidl "\tNDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));\n";
286         }
287 }
288
289
290 #####################################################################
291 # parse an array - pull side
292 sub ParseArrayPull($$$)
293 {
294         my $e = shift;
295         my $var_prefix = shift;
296         my $ndr_flags = shift;
297
298         my $size = find_size_var($e, util::array_size($e), $var_prefix);
299         my $alloc_size = $size;
300
301         # if this is a conformant array then we use that size to allocate, and make sure
302         # we allocate enough to pull the elements
303         if (defined $e->{CONFORMANT_SIZE}) {
304                 $alloc_size = $e->{CONFORMANT_SIZE};
305
306                 pidl "\tif ($size > $alloc_size) {\n";
307                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $alloc_size, $size);\n";
308                 pidl "\t}\n";
309         } elsif (!util::is_inline_array($e)) {
310                 if ($var_prefix =~ /^r->out/ && $size =~ /^\*r->in/) {
311                         my $size2 = substr($size, 1);
312                         pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { NDR_ALLOC(ndr, $size2); }\n";
313                 }
314
315                 # non fixed arrays encode the size just before the array
316                 pidl "\t\tNDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));\n";
317                 $alloc_size = "ndr_get_array_size(ndr, &$var_prefix$e->{NAME})";
318         }
319
320         if ((util::need_alloc($e) && !util::is_fixed_array($e)) ||
321             ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
322                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
323                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
324                 }
325         }
326
327         if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
328                 if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
329                         pidl "\tif (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
330                         pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
331                         pidl "\t}\n";
332                 }
333         }
334
335         if (my $length = util::has_property($e, "length_is")) {
336                 pidl "\t\tNDR_CHECK(ndr_pull_array_length(ndr, &$var_prefix$e->{NAME}));\n";
337                 $size = "ndr_get_array_length(ndr, &$var_prefix$e->{NAME})";
338         }
339
340         if (util::is_scalar_type($e->{TYPE})) {
341                 pidl "\t\tNDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));\n";
342         } else {
343                 pidl "\t\tNDR_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}));\n";
344         }
345 }
346
347
348 #####################################################################
349 # parse scalars in a structure element
350 sub ParseElementPushScalar($$$)
351 {
352         my($e) = shift;
353         my($var_prefix) = shift;
354         my($ndr_flags) = shift;
355         my $cprefix = util::c_push_prefix($e);
356         my $sub_size = util::has_property($e, "subcontext");
357
358         start_flags($e);
359
360         if (my $value = util::has_property($e, "value")) {
361                 pidl "\t$cprefix$var_prefix$e->{NAME} = $value;\n";
362         }
363
364         if (util::has_property($e, "relative")) {
365                 pidl "\tNDR_CHECK(ndr_push_relative1(ndr, $var_prefix$e->{NAME}));\n";
366         } elsif (util::is_inline_array($e)) {
367                 ParseArrayPush($e, "r->", "NDR_SCALARS");
368         } elsif (util::need_wire_pointer($e)) {
369                 pidl "\tNDR_CHECK(ndr_push_ptr(ndr, $var_prefix$e->{NAME}));\n";
370         } elsif (util::need_alloc($e)) {
371                 # no scalar component
372         } elsif (my $switch = util::has_property($e, "switch_is")) {
373                 ParseElementPushSwitch($e, $var_prefix, $ndr_flags, $switch);
374         } elsif (defined $sub_size) {
375                 if (util::is_builtin_type($e->{TYPE})) {
376                         pidl "\tNDR_CHECK(ndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE}));\n";
377                 } else {
378                         pidl "\tNDR_CHECK(ndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE}));\n";
379                 }
380         } elsif (util::is_builtin_type($e->{TYPE})) {
381                 pidl "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
382         } else {
383                 pidl "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
384         }
385
386         end_flags($e);
387 }
388
389 #####################################################################
390 # print scalars in a structure element
391 sub ParseElementPrintScalar($$)
392 {
393         my($e) = shift;
394         my($var_prefix) = shift;
395         my $cprefix = util::c_push_prefix($e);
396
397         if (util::has_property($e, "noprint")) {
398                 return;
399         }
400
401         if (my $value = util::has_property($e, "value")) {
402                 pidl "\tif (ndr->flags & LIBNDR_PRINT_SET_VALUES) {\n";
403                 pidl "\t\t$cprefix$var_prefix$e->{NAME} = $value;\n";
404                 pidl "\t}\n";
405         }
406
407         if (util::is_fixed_array($e)) {
408                 ParseElementPrintBuffer($e, $var_prefix);
409         } elsif (util::has_direct_buffers($e)) {
410                 pidl "\tndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});\n";
411                 pidl "\tndr->depth++;\n";
412                 ParseElementPrintBuffer($e, $var_prefix);
413                 pidl "\tndr->depth--;\n";
414         } elsif (my $switch = util::has_property($e, "switch_is")) {
415                 ParseElementPrintSwitch($e, $var_prefix, $switch);
416         } else {
417                 pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
418         }
419 }
420
421 #####################################################################
422 # parse scalars in a structure element - pull size
423 sub ParseElementPullSwitch($$$$)
424 {
425         my($e) = shift;
426         my($var_prefix) = shift;
427         my($ndr_flags) = shift;
428         my $switch = shift;
429         my $switch_var = find_size_var($e, $switch, $var_prefix);
430
431         my $cprefix = util::c_pull_prefix($e);
432
433         my $utype = $structs{$e->{TYPE}};
434         if (!defined $utype ||
435             !util::has_property($utype->{DATA}, "nodiscriminant")) {
436                 my $e2 = find_sibling($e, $switch);
437                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
438                 pidl "\t\t $e2->{TYPE} _level;\n";
439                 pidl "\t\tNDR_CHECK(ndr_pull_$e2->{TYPE}(ndr, &_level));\n";
440                 if ($switch_var =~ /r->in/) {
441                         pidl "\t\tif (!(ndr->flags & LIBNDR_FLAG_REF_ALLOC) && _level != $switch_var) {\n";
442                 } else {
443                         pidl "\t\tif (_level != $switch_var) {\n";
444                 }
445                 pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\", _level);\n";
446                 pidl "\t\t}\n";
447                 if ($switch_var =~ /r->/) {
448                         pidl "else { $switch_var = _level; }\n";
449                 }
450                 pidl "\t}\n";
451         }
452
453         my $sub_size = util::has_property($e, "subcontext");
454         if (defined $sub_size) {
455                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
456                 pidl "\t\tNDR_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}));\n";
457                 pidl "\t}\n";
458         } else {
459                 pidl "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));\n";
460         }
461
462
463 }
464
465 #####################################################################
466 # push switch element
467 sub ParseElementPushSwitch($$$$)
468 {
469         my($e) = shift;
470         my($var_prefix) = shift;
471         my($ndr_flags) = shift;
472         my $switch = shift;
473         my $switch_var = find_size_var($e, $switch, $var_prefix);
474         my $cprefix = util::c_push_prefix($e);
475
476         my $utype = $structs{$e->{TYPE}};
477         if (!defined $utype ||
478             !util::has_property($utype->{DATA}, "nodiscriminant")) {
479                 my $e2 = find_sibling($e, $switch);
480                 pidl "\tif (($ndr_flags) & NDR_SCALARS) {\n";
481                 pidl "\t\tNDR_CHECK(ndr_push_$e2->{TYPE}(ndr, $switch_var));\n";
482                 pidl "\t}\n";
483         }
484
485         my $sub_size = util::has_property($e, "subcontext");
486         if (defined $sub_size) {
487                 pidl "\tif(($ndr_flags) & NDR_SCALARS) {\n";
488                 pidl "\t\tNDR_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}));\n";
489                 pidl "\t}\n";
490         } else {
491                 pidl "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));\n";
492         }
493 }
494
495 #####################################################################
496 # print scalars in a structure element 
497 sub ParseElementPrintSwitch($$$)
498 {
499         my($e) = shift;
500         my($var_prefix) = shift;
501         my $switch = shift;
502         my $switch_var = find_size_var($e, $switch, $var_prefix);
503         my $cprefix = util::c_push_prefix($e);
504
505         pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});\n";
506 }
507
508
509 #####################################################################
510 # parse scalars in a structure element - pull size
511 sub ParseElementPullScalar($$$)
512 {
513         my($e) = shift;
514         my($var_prefix) = shift;
515         my($ndr_flags) = shift;
516         my $cprefix = util::c_pull_prefix($e);
517         my $sub_size = util::has_property($e, "subcontext");
518
519         start_flags($e);
520
521         if (util::is_inline_array($e)) {
522                 ParseArrayPull($e, "r->", "NDR_SCALARS");
523         } elsif (util::need_wire_pointer($e)) {
524                 pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
525                 pidl "\tif (_ptr_$e->{NAME}) {\n";
526                 pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
527                 if (util::has_property($e, "relative")) {
528                         pidl "\t\tNDR_CHECK(ndr_pull_relative1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));";
529                 }
530                 pidl "\t} else {\n";
531                 pidl "\t\t$var_prefix$e->{NAME} = NULL;\n";
532                 pidl "\t}\n";
533         } elsif (util::need_alloc($e)) {
534                 # no scalar component
535         } elsif (my $switch = util::has_property($e, "switch_is")) {
536                 ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch);
537         } elsif (defined $sub_size) {
538                 if (util::is_builtin_type($e->{TYPE})) {
539                         pidl "\tNDR_CHECK(ndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE}));\n";
540                 } else {
541                         pidl "\tNDR_CHECK(ndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE}));\n";
542                 }
543         } elsif (util::is_builtin_type($e->{TYPE})) {
544                 pidl "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
545         } else {
546                 pidl "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
547         }
548         if (my $range = util::has_property($e, "range")) {
549                 my ($low, $high) = split(/ /, $range, 2);
550                 pidl "\tif ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {\n";
551                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_RANGE, \"value out of range\");\n\t}\n";
552         }
553
554         end_flags($e);
555 }
556
557 #####################################################################
558 # parse buffers in a structure element
559 sub ParseElementPushBuffer($$$)
560 {
561         my($e) = shift;
562         my($var_prefix) = shift;
563         my($ndr_flags) = shift;
564         my $cprefix = util::c_push_prefix($e);
565         my $sub_size = util::has_property($e, "subcontext");
566
567         if (util::is_pure_scalar($e)) {
568                 return;
569         }
570
571         start_flags($e);
572
573         if (util::need_wire_pointer($e)) {
574                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
575                 if (util::has_property($e, "relative")) {
576                         pidl "\t\tNDR_CHECK(ndr_push_relative2(ndr, $var_prefix$e->{NAME}));\n";
577                 }
578         }
579             
580         if (util::is_inline_array($e)) {
581                 ParseArrayPush($e, "r->", "NDR_BUFFERS");
582         } elsif (util::array_size($e)) {
583                 ParseArrayPush($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
584         } elsif (my $switch = util::has_property($e, "switch_is")) {
585                 if ($e->{POINTERS}) {
586                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS|NDR_SCALARS", $switch);
587                 } else {
588                         ParseElementPushSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
589                 }
590         } elsif (defined $sub_size) {
591                 if ($e->{POINTERS}) {
592                         if (util::is_builtin_type($e->{TYPE})) {
593                                 pidl "\tNDR_CHECK(ndr_push_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_fn_t) ndr_push_$e->{TYPE}));\n";
594                         } else {
595                                 pidl "\tNDR_CHECK(ndr_push_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_push_flags_fn_t) ndr_push_$e->{TYPE}));\n";
596                         }
597                 }
598         } elsif (util::is_builtin_type($e->{TYPE})) {
599                 pidl "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
600         } elsif ($e->{POINTERS}) {
601                 pidl "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}));\n";
602         } else {
603                 pidl "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
604         }
605
606         if (util::need_wire_pointer($e)) {
607                 pidl "\t}\n";
608         }       
609
610         end_flags($e);
611 }
612
613 #####################################################################
614 # print buffers in a structure element
615 sub ParseElementPrintBuffer($$)
616 {
617         my($e) = shift;
618         my($var_prefix) = shift;
619         my $cprefix = util::c_push_prefix($e);
620
621         if (util::need_wire_pointer($e)) {
622                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
623         }
624             
625         if (util::array_size($e)) {
626                 ParseArrayPrint($e, $var_prefix)
627         } elsif (my $switch = util::has_property($e, "switch_is")) {
628                 ParseElementPrintSwitch($e, $var_prefix, $switch);
629         } else {
630                 pidl "\t\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});\n";
631         }
632
633         if (util::need_wire_pointer($e)) {
634                 pidl "\t}\n";
635         }       
636 }
637
638
639 #####################################################################
640 # parse buffers in a structure element - pull side
641 sub ParseElementPullBuffer($$$)
642 {
643         my($e) = shift;
644         my($var_prefix) = shift;
645         my($ndr_flags) = shift;
646         my $cprefix = util::c_pull_prefix($e);
647         my $sub_size = util::has_property($e, "subcontext");
648
649         if (util::is_pure_scalar($e)) {
650                 return;
651         }
652
653         start_flags($e);
654
655         if (util::need_wire_pointer($e)) {
656                 pidl "\tif ($var_prefix$e->{NAME}) {\n";
657                 if (util::has_property($e, "relative")) {
658                         pidl "\t\tstruct ndr_pull_save _relative_save;\n";
659                         pidl "\t\tndr_pull_save(ndr, &_relative_save);\n";
660                         pidl "\t\tNDR_CHECK(ndr_pull_relative2(ndr, $var_prefix$e->{NAME}));\n";
661                 }
662         }
663             
664         if (util::is_inline_array($e)) {
665                 ParseArrayPull($e, "r->", "NDR_BUFFERS");
666         } elsif (util::array_size($e)) {
667                 ParseArrayPull($e, "r->", "NDR_SCALARS|NDR_BUFFERS");
668         } elsif (my $switch = util::has_property($e, "switch_is")) {
669                 if ($e->{POINTERS}) {
670                         ParseElementPullSwitch($e, $var_prefix, "NDR_SCALARS|NDR_BUFFERS", $switch);
671                 } else {
672                         ParseElementPullSwitch($e, $var_prefix, "NDR_BUFFERS", $switch);
673                 }
674         } elsif (defined $sub_size) {
675                 if ($e->{POINTERS}) {
676                         if (util::is_builtin_type($e->{TYPE})) {
677                                 pidl "\tNDR_CHECK(ndr_pull_subcontext_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_fn_t) ndr_pull_$e->{TYPE}));\n";
678                         } else {
679                                 pidl "\tNDR_CHECK(ndr_pull_subcontext_flags_fn(ndr, $sub_size, $cprefix$var_prefix$e->{NAME}, (ndr_pull_flags_fn_t) ndr_pull_$e->{TYPE}));\n";
680                         }
681                 }
682         } elsif (util::is_builtin_type($e->{TYPE})) {
683                 pidl "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
684         } elsif ($e->{POINTERS}) {
685                 pidl "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, NDR_SCALARS|NDR_BUFFERS, $cprefix$var_prefix$e->{NAME}));\n";
686         } else {
687                 pidl "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
688         }
689
690         if (util::need_wire_pointer($e)) {
691                 if (util::has_property($e, "relative")) {
692                         pidl "\t\tndr_pull_restore(ndr, &_relative_save);\n";
693                 }
694                 pidl "\t}\n";
695         }       
696
697         end_flags($e);
698 }
699
700 #####################################################################
701 # parse a struct
702 sub ParseStructPush($)
703 {
704         my($struct) = shift;
705         
706         if (! defined $struct->{ELEMENTS}) {
707                 return;
708         }
709
710         start_flags($struct);
711
712         # see if the structure contains a conformant array. If it
713         # does, then it must be the last element of the structure, and
714         # we need to push the conformant length early, as it fits on
715         # the wire before the structure (and even before the structure
716         # alignment)
717         my $e = $struct->{ELEMENTS}[-1];
718         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
719                 my $size = find_size_var($e, util::array_size($e), "r->");
720                 $e->{CONFORMANT_SIZE} = $size;
721                 pidl "\tNDR_CHECK(ndr_push_uint32(ndr, $size));\n";
722         }
723
724         if (defined $e->{TYPE} && $e->{TYPE} eq "string" 
725             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
726                 pidl "\tNDR_CHECK(ndr_push_uint32(ndr, ndr_string_array_size(ndr, r->$e->{NAME})));\n";
727         }
728
729         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
730
731         pidl "\tNDR_CHECK(ndr_push_struct_start(ndr));\n";
732
733         my $align = struct_alignment($struct);
734         pidl "\tNDR_CHECK(ndr_push_align(ndr, $align));\n";
735
736         foreach my $e (@{$struct->{ELEMENTS}}) {
737                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
738         }       
739
740         pidl "buffers:\n";
741         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
742         foreach my $e (@{$struct->{ELEMENTS}}) {
743                 ParseElementPushBuffer($e, "r->", "NDR_BUFFERS");
744         }
745
746         pidl "\tndr_push_struct_end(ndr);\n";
747
748         pidl "done:\n";
749
750         end_flags($struct);
751 }
752
753 #####################################################################
754 # generate a struct print function
755 sub ParseStructPrint($)
756 {
757         my($struct) = shift;
758
759         if (! defined $struct->{ELEMENTS}) {
760                 return;
761         }
762
763         start_flags($struct);
764
765         pidl "\tndr->depth++;\n";
766         foreach my $e (@{$struct->{ELEMENTS}}) {
767                 ParseElementPrintScalar($e, "r->");
768         }
769         pidl "\tndr->depth--;\n";
770
771         end_flags($struct);
772 }
773
774 #####################################################################
775 # parse a struct - pull side
776 sub ParseStructPull($)
777 {
778         my($struct) = shift;
779         my $conform_e;
780
781         if (! defined $struct->{ELEMENTS}) {
782                 return;
783         }
784
785         # see if the structure contains a conformant array. If it
786         # does, then it must be the last element of the structure, and
787         # we need to pull the conformant length early, as it fits on
788         # the wire before the structure (and even before the structure
789         # alignment)
790         my $e = $struct->{ELEMENTS}[-1];
791         if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
792                 $conform_e = $e;
793         }
794
795         if (defined $e->{TYPE} && $e->{TYPE} eq "string"
796             &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
797                 $conform_e = $e;
798         }
799
800         if (defined $conform_e) {
801                 $conform_e = $e;
802                 pidl "\tuint32_t _conformant_size;\n";
803                 $conform_e->{CONFORMANT_SIZE} = "_conformant_size";
804         }
805
806         # declare any internal pointers we need
807         foreach my $e (@{$struct->{ELEMENTS}}) {
808                 if (util::need_wire_pointer($e)) {
809                         pidl "\tuint32_t _ptr_$e->{NAME};\n";
810                 }
811         }
812
813         start_flags($struct);
814
815         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
816
817         pidl "\tNDR_CHECK(ndr_pull_struct_start(ndr));\n";
818
819         if (defined $conform_e) {
820                 pidl "\tNDR_CHECK(ndr_pull_uint32(ndr, &$conform_e->{CONFORMANT_SIZE}));\n";
821         }
822
823         my $align = struct_alignment($struct);
824         pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
825
826         foreach my $e (@{$struct->{ELEMENTS}}) {
827                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
828         }       
829
830         pidl "buffers:\n";
831         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
832         foreach my $e (@{$struct->{ELEMENTS}}) {
833                 ParseElementPullBuffer($e, "r->", "NDR_BUFFERS");
834         }
835
836         foreach my $e (@{$struct->{ELEMENTS}}) {
837                 CheckArraySizes($e, "r->");
838         }
839
840         pidl "\tndr_pull_struct_end(ndr);\n";
841
842         pidl "done:\n";
843
844         end_flags($struct);
845 }
846
847 #####################################################################
848 # calculate size of ndr struct
849 sub ParseStructNdrSize($)
850 {
851         my $t = shift;
852         my $static = fn_prefix($t);
853         my $sizevar;
854
855         pidl $static . "size_t ndr_size_$t->{NAME}(int ret, const struct $t->{NAME} *r, int flags)\n";
856         pidl "{\n";
857
858         if (util::has_property($t->{DATA}, "flag")) {
859                 pidl "\tflags = flags | " . $t->{DATA}->{PROPERTIES}->{flag} . ";\n";   
860         }
861
862         pidl "\tif(!r) return 0;\n";
863
864         pidl "\tret = NDR_SIZE_ALIGN(ret, " . struct_alignment($t->{DATA}) . ", flags);\n";
865
866         for my $e (@{$t->{DATA}->{ELEMENTS}}) {
867                 my $switch = "";
868
869                 if (util::has_property($e, "subcontext")) {
870                         pidl "\tret += $e->{PROPERTIES}->{subcontext}; /* Subcontext length */\n";
871                 }
872
873                 if (util::has_property($e, "switch_is")) {
874                         $switch = ", r->$e->{PROPERTIES}->{switch_is}";
875                 }
876
877                 if ($e->{POINTERS} > 0) {
878                         pidl "\tret = ndr_size_ptr(ret, &r->$e->{NAME}, flags); \n";
879                 } elsif (util::is_inline_array($e)) {
880                         $sizevar = find_size_var($e, util::array_size($e), "r->");
881                         pidl "\t{\n";
882                         pidl "\t\tint i;\n";
883                         pidl "\t\tfor(i = 0; i < $sizevar; i++) {\n";
884                         pidl "\t\t\tret = ndr_size_$e->{TYPE}(ret, &r->" . $e->{NAME} . "[i], flags);\n";
885                         pidl "\t\t}\n";
886                         pidl "\t}\n";
887                 } else {
888                         pidl "\tret = ndr_size_$e->{TYPE}(ret, &r->$e->{NAME}$switch, flags); \n";
889                 }
890         }
891         
892         # Add lengths of relative members
893         for my $e (@{$t->{DATA}->{ELEMENTS}}) {
894                 next unless (util::has_property($e, "relative"));
895
896                 pidl "\tif (r->$e->{NAME}) {\n";
897                 pidl "\t\tret = ndr_size_$e->{TYPE}(ret, r->$e->{NAME}, flags); \n"; 
898                 pidl "\t}\n";
899         }
900
901         pidl "\treturn ret;\n";
902         pidl "}\n\n";
903 }
904
905 #####################################################################
906 # parse a union - push side
907 sub ParseUnionPush($)
908 {
909         my $e = shift;
910         my $have_default = 0;
911
912         start_flags($e);
913
914         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
915
916         pidl "\tNDR_CHECK(ndr_push_struct_start(ndr));\n";
917
918 #       my $align = union_alignment($e);
919 #       pidl "\tNDR_CHECK(ndr_push_align(ndr, $align));\n";
920
921         pidl "\tswitch (level) {\n";
922         foreach my $el (@{$e->{DATA}}) {
923                 if ($el->{CASE} eq "default") {
924                         pidl "\tdefault:\n";
925                         $have_default = 1;
926                 } else {
927                         pidl "\tcase $el->{CASE}:\n";
928                 }
929                 if ($el->{TYPE} eq "UNION_ELEMENT") {
930                         ParseElementPushScalar($el->{DATA}, "r->", "NDR_SCALARS");
931                 }
932                 pidl "\tbreak;\n\n";
933         }
934         if (! $have_default) {
935                 pidl "\tdefault:\n";
936                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
937         }
938         pidl "\t}\n";
939         pidl "buffers:\n";
940         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
941         pidl "\tswitch (level) {\n";
942         foreach my $el (@{$e->{DATA}}) {
943                 if ($el->{CASE} eq "default") {
944                         pidl "\tdefault:\n";
945                 } else {
946                         pidl "\tcase $el->{CASE}:\n";
947                 }
948                 if ($el->{TYPE} eq "UNION_ELEMENT") {
949                         ParseElementPushBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
950                 }
951                 pidl "\tbreak;\n\n";
952         }
953         if (! $have_default) {
954                 pidl "\tdefault:\n";
955                 pidl "\t\treturn ndr_push_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
956         }
957         pidl "\t}\n";
958         pidl "\tndr_push_struct_end(ndr);\n";
959         pidl "done:\n";
960         end_flags($e);
961 }
962
963 #####################################################################
964 # print a union
965 sub ParseUnionPrint($)
966 {
967         my $e = shift;
968         my $have_default = 0;
969
970         start_flags($e);
971
972         pidl "\tswitch (level) {\n";
973         foreach my $el (@{$e->{DATA}}) {
974                 if ($el->{CASE} eq "default") {
975                         $have_default = 1;
976                         pidl "\tdefault:\n";
977                 } else {
978                         pidl "\tcase $el->{CASE}:\n";
979                 }
980                 if ($el->{TYPE} eq "UNION_ELEMENT") {
981                         ParseElementPrintScalar($el->{DATA}, "r->");
982                 }
983                 pidl "\tbreak;\n\n";
984         }
985         if (! $have_default) {
986                 pidl "\tdefault:\n\t\tndr_print_bad_level(ndr, name, level);\n";
987         }
988         pidl "\t}\n";
989
990         end_flags($e);
991 }
992
993 #####################################################################
994 # parse a union - pull side
995 sub ParseUnionPull($)
996 {
997         my $e = shift;
998         my $have_default = 0;
999
1000         start_flags($e);
1001
1002         pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
1003
1004         pidl "\tNDR_CHECK(ndr_pull_struct_start(ndr));\n";
1005
1006 #       my $align = union_alignment($e);
1007 #       pidl "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n";
1008
1009         pidl "\tswitch (level) {\n";
1010         foreach my $el (@{$e->{DATA}}) {
1011                 if ($el->{CASE} eq "default") {
1012                         pidl "\tdefault: {\n";
1013                         $have_default = 1;
1014                 } else {
1015                         pidl "\tcase $el->{CASE}: {\n";
1016                 }
1017                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1018                         my $e2 = $el->{DATA};
1019                         if ($e2->{POINTERS}) {
1020                                 pidl "\t\tuint32_t _ptr_$e2->{NAME};\n";
1021                         }
1022                         ParseElementPullScalar($el->{DATA}, "r->", "NDR_SCALARS");
1023                 }
1024                 pidl "\tbreak; }\n\n";
1025         }
1026         if (! $have_default) {
1027                 pidl "\tdefault:\n";
1028                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1029         }
1030         pidl "\t}\n";
1031         pidl "buffers:\n";
1032         pidl "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
1033         pidl "\tswitch (level) {\n";
1034         foreach my $el (@{$e->{DATA}}) {
1035                 if ($el->{CASE} eq "default") {
1036                         pidl "\tdefault:\n";
1037                 } else {
1038                         pidl "\tcase $el->{CASE}:\n";
1039                 }
1040                 if ($el->{TYPE} eq "UNION_ELEMENT") {
1041                         ParseElementPullBuffer($el->{DATA}, "r->", "NDR_BUFFERS");
1042                 }
1043                 pidl "\tbreak;\n\n";
1044         }
1045         if (! $have_default) {
1046                 pidl "\tdefault:\n";
1047                 pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n";
1048         }
1049         pidl "\t}\n";
1050         pidl "\tndr_pull_struct_end(ndr);\n";
1051         pidl "done:\n";
1052         end_flags($e);
1053 }
1054
1055 #####################################################################
1056 # calculate size of ndr union
1057
1058 sub ParseUnionNdrSize($)
1059 {
1060         my $t = shift;
1061         my $static = fn_prefix($t);
1062
1063         pidl $static . "size_t ndr_size_$t->{NAME}(int ret, const union $t->{NAME} *data, uint16 level, int flags)\n";
1064         pidl "{\n";
1065         if (util::has_property($t->{DATA}, "flag")) {
1066                 pidl "\tflags = flags | " . $t->{DATA}->{PROPERTIES}->{flag} . ";\n";   
1067         }
1068         pidl "\tif(!data) return 0;\n\n";
1069         
1070         pidl "\tret = NDR_SIZE_ALIGN(ret, " . union_alignment($t->{DATA}) . ", flags);\n";
1071
1072         pidl "\tswitch(level) {\n";
1073
1074         for my $e (@{$t->{DATA}->{DATA}}) {
1075                 if ($e->{TYPE} eq "UNION_ELEMENT") {
1076                         
1077                         if ($e->{CASE} eq "default") {
1078                                 pidl "\t\tdefault:";
1079                         } else { 
1080                                 pidl "\t\tcase $e->{CASE}:";
1081                         }
1082                         
1083                         pidl " return ndr_size_$e->{DATA}->{TYPE}(ret, &data->$e->{DATA}->{NAME}, flags); \n";
1084
1085                 }
1086         }
1087         pidl "\t}\n";
1088         pidl "\treturn ret;\n";
1089         pidl "}\n\n";
1090 }
1091
1092 #####################################################################
1093 # parse a type
1094 sub ParseTypePush($)
1095 {
1096         my($data) = shift;
1097
1098         if (ref($data) eq "HASH") {
1099                 ($data->{TYPE} eq "STRUCT") &&
1100                     ParseStructPush($data);
1101                 ($data->{TYPE} eq "UNION") &&
1102                     ParseUnionPush($data);
1103         }
1104 }
1105
1106 #####################################################################
1107 # generate a print function for a type
1108 sub ParseTypePrint($)
1109 {
1110         my($data) = shift;
1111
1112         if (ref($data) eq "HASH") {
1113                 ($data->{TYPE} eq "STRUCT") &&
1114                     ParseStructPrint($data);
1115                 ($data->{TYPE} eq "UNION") &&
1116                     ParseUnionPrint($data);
1117         }
1118 }
1119
1120 #####################################################################
1121 # parse a type
1122 sub ParseTypePull($)
1123 {
1124         my($data) = shift;
1125
1126         if (ref($data) eq "HASH") {
1127                 ($data->{TYPE} eq "STRUCT") &&
1128                     ParseStructPull($data);
1129                 ($data->{TYPE} eq "UNION") &&
1130                     ParseUnionPull($data);
1131         }
1132 }
1133
1134 #####################################################################
1135 # parse a typedef - push side
1136 sub ParseTypedefPush($)
1137 {
1138         my($e) = shift;
1139         my $static = fn_prefix($e);
1140
1141         if (! needed::is_needed("push_$e->{NAME}")) {
1142 #               print "push_$e->{NAME} not needed\n";
1143                 return;
1144         }
1145
1146         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1147                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r)";
1148                 pidl "\n{\n";
1149                 ParseTypePush($e->{DATA});
1150                 pidl "\treturn NT_STATUS_OK;\n";
1151                 pidl "}\n\n";
1152         }
1153
1154         if ($e->{DATA}->{TYPE} eq "UNION") {
1155                 pidl $static . "NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, int level, union $e->{NAME} *r)";
1156                 pidl "\n{\n";
1157                 ParseTypePush($e->{DATA});
1158                 pidl "\treturn NT_STATUS_OK;\n";
1159                 pidl "}\n\n";
1160         }
1161 }
1162
1163
1164 #####################################################################
1165 # parse a typedef - pull side
1166 sub ParseTypedefPull($)
1167 {
1168         my($e) = shift;
1169         my $static = fn_prefix($e);
1170
1171         if (! needed::is_needed("pull_$e->{NAME}")) {
1172 #               print "pull_$e->{NAME} not needed\n";
1173                 return;
1174         }
1175
1176         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1177                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r)";
1178                 pidl "\n{\n";
1179                 ParseTypePull($e->{DATA});
1180                 pidl "\treturn NT_STATUS_OK;\n";
1181                 pidl "}\n\n";
1182         }
1183
1184         if ($e->{DATA}->{TYPE} eq "UNION") {
1185                 pidl $static . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, int level, union $e->{NAME} *r)";
1186                 pidl "\n{\n";
1187                 ParseTypePull($e->{DATA});
1188                 pidl "\treturn NT_STATUS_OK;\n";
1189                 pidl "}\n\n";
1190         }
1191 }
1192
1193
1194 #####################################################################
1195 # parse a typedef - print side
1196 sub ParseTypedefPrint($)
1197 {
1198         my($e) = shift;
1199
1200         if ($e->{DATA}->{TYPE} eq "STRUCT") {
1201                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, struct $e->{NAME} *r)";
1202                 pidl "\n{\n";
1203                 pidl "\tndr_print_struct(ndr, name, \"$e->{NAME}\");\n";
1204                 ParseTypePrint($e->{DATA});
1205                 pidl "}\n\n";
1206         }
1207
1208         if ($e->{DATA}->{TYPE} eq "UNION") {
1209                 pidl "void ndr_print_$e->{NAME}(struct ndr_print *ndr, const char *name, int level, union $e->{NAME} *r)";
1210                 pidl "\n{\n";
1211                 pidl "\tndr_print_union(ndr, name, level, \"$e->{NAME}\");\n";
1212                 ParseTypePrint($e->{DATA});
1213                 pidl "}\n\n";
1214         }
1215 }
1216
1217 #####################################################################
1218 ## calculate the size of a structure
1219 sub ParseTypedefNdrSize($)
1220 {
1221         my($t) = shift;
1222         if (! needed::is_needed("ndr_size_$t->{NAME}")) {
1223                 return;
1224         }
1225         
1226         ($t->{DATA}->{TYPE} eq "STRUCT") &&
1227                 ParseStructNdrSize($t);
1228
1229         ($t->{DATA}->{TYPE} eq "UNION") &&
1230                 ParseUnionNdrSize($t);
1231
1232 }
1233
1234 #####################################################################
1235 # parse a function - print side
1236 sub ParseFunctionPrint($)
1237 {
1238         my($fn) = shift;
1239
1240         pidl "void ndr_print_$fn->{NAME}(struct ndr_print *ndr, const char *name, int flags, struct $fn->{NAME} *r)";
1241         pidl "\n{\n";
1242         pidl "\tndr_print_struct(ndr, name, \"$fn->{NAME}\");\n";
1243         pidl "\tndr->depth++;\n";
1244
1245         pidl "\tif (flags & NDR_SET_VALUES) {\n";
1246         pidl "\t\tndr->flags |= LIBNDR_PRINT_SET_VALUES;\n";
1247         pidl "\t}\n";
1248
1249         pidl "\tif (flags & NDR_IN) {\n";
1250         pidl "\t\tndr_print_struct(ndr, \"in\", \"$fn->{NAME}\");\n";
1251         pidl "\tndr->depth++;\n";
1252         foreach my $e (@{$fn->{DATA}}) {
1253                 if (util::has_property($e, "in")) {
1254                         ParseElementPrintScalar($e, "r->in.");
1255                 }
1256         }
1257         pidl "\tndr->depth--;\n";
1258         pidl "\t}\n";
1259         
1260         pidl "\tif (flags & NDR_OUT) {\n";
1261         pidl "\t\tndr_print_struct(ndr, \"out\", \"$fn->{NAME}\");\n";
1262         pidl "\tndr->depth++;\n";
1263         foreach my $e (@{$fn->{DATA}}) {
1264                 if (util::has_property($e, "out")) {
1265                         ParseElementPrintScalar($e, "r->out.");
1266                 }
1267         }
1268         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1269                 if (util::is_scalar_type($fn->{RETURN_TYPE})) {
1270                         pidl "\tndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", r->out.result);\n";
1271                 } else {
1272                         pidl "\tndr_print_$fn->{RETURN_TYPE}(ndr, \"result\", &r->out.result);\n";
1273                 }
1274         }
1275         pidl "\tndr->depth--;\n";
1276         pidl "\t}\n";
1277         
1278         pidl "\tndr->depth--;\n";
1279         pidl "}\n\n";
1280 }
1281
1282
1283 #####################################################################
1284 # parse a function element
1285 sub ParseFunctionElementPush($$)
1286
1287         my $e = shift;
1288         my $inout = shift;
1289
1290         if (util::array_size($e)) {
1291                 if (util::need_wire_pointer($e)) {
1292                         pidl "\tNDR_CHECK(ndr_push_ptr(ndr, r->$inout.$e->{NAME}));\n";
1293                         pidl "\tif (r->$inout.$e->{NAME}) {\n";
1294                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1295                         pidl "\t}\n";
1296                 } else {
1297                         ParseArrayPush($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1298                 }
1299         } else {
1300                 ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1301                 if ($e->{POINTERS}) {
1302                         ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1303                 }
1304         }
1305 }       
1306
1307 #####################################################################
1308 # parse a function
1309 sub ParseFunctionPush($)
1310
1311         my($fn) = shift;
1312         my $static = fn_prefix($fn);
1313
1314         pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)\n{\n";
1315
1316         pidl "\n\tif (!(flags & NDR_IN)) goto ndr_out;\n\n";
1317
1318         foreach my $e (@{$fn->{DATA}}) {
1319                 if (util::has_property($e, "in")) {
1320                         ParseFunctionElementPush($e, "in");
1321                 }               
1322         }
1323
1324         pidl "\nndr_out:\n";
1325         pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
1326
1327         foreach my $e (@{$fn->{DATA}}) {
1328                 if (util::has_property($e, "out")) {
1329                         ParseFunctionElementPush($e, "out");
1330                 }               
1331         }
1332
1333         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1334                 pidl "\tNDR_CHECK(ndr_push_$fn->{RETURN_TYPE}(ndr, r->out.result));\n";
1335         }
1336     
1337         pidl "\ndone:\n";
1338         pidl "\n\treturn NT_STATUS_OK;\n}\n\n";
1339 }
1340
1341 #####################################################################
1342 # parse a function element
1343 sub ParseFunctionElementPull($$)
1344
1345         my $e = shift;
1346         my $inout = shift;
1347
1348         if (util::array_size($e)) {
1349                 if (util::need_wire_pointer($e)) {
1350                         pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
1351                         pidl "\tif (_ptr_$e->{NAME}) {\n";
1352                 } elsif ($inout eq "out" && util::has_property($e, "ref")) {
1353                         pidl "\tif (r->$inout.$e->{NAME}) {\n";
1354                 } else {
1355                         pidl "\t{\n";
1356                 }
1357                 ParseArrayPull($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1358                 pidl "\t}\n";
1359         } else {
1360                 if ($inout eq "out" && util::has_property($e, "ref")) {
1361                         pidl "\tif (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\n";
1362                         pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
1363                         pidl "\t}\n";
1364                 }
1365                 if ($inout eq "in" && util::has_property($e, "ref")) {
1366                         pidl "\tNDR_ALLOC(ndr, r->in.$e->{NAME});\n";
1367                 }
1368
1369                 ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1370                 if ($e->{POINTERS}) {
1371                         ParseElementPullBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
1372                 }
1373         }
1374 }
1375
1376
1377 ############################################################
1378 # allocate ref variables
1379 sub AllocateRefVars($)
1380 {
1381         my $e = shift;
1382         my $asize = util::array_size($e);
1383
1384         # note that if the variable is also an "in"
1385         # variable then we copy the initial value from
1386         # the in side
1387
1388         if (!defined $asize) {
1389                 # its a simple variable
1390                 pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
1391                 if (util::has_property($e, "in")) {
1392                         pidl "\t*r->out.$e->{NAME} = *r->in.$e->{NAME};\n";
1393                 } else {
1394                         pidl "\tZERO_STRUCTP(r->out.$e->{NAME});\n";
1395                 }
1396                 return;
1397         }
1398
1399         # its an array
1400         my $size = find_size_var($e, $asize, "r->out.");
1401         pidl "\tNDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);\n";
1402         if (util::has_property($e, "in")) {
1403                 pidl "\tmemcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));\n";
1404         } else {
1405                 pidl "\tmemset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));\n";
1406         }
1407 }
1408
1409
1410 #####################################################################
1411 # parse a function
1412 sub ParseFunctionPull($)
1413
1414         my($fn) = shift;
1415         my $static = fn_prefix($fn);
1416
1417         # pull function args
1418         pidl $static . "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, int flags, struct $fn->{NAME} *r)\n{\n";
1419
1420         # declare any internal pointers we need
1421         foreach my $e (@{$fn->{DATA}}) {
1422                 if (util::need_wire_pointer($e)) {
1423                         pidl "\tuint32_t _ptr_$e->{NAME};\n";
1424                 }
1425         }
1426
1427         pidl "\n\tif (!(flags & NDR_IN)) goto ndr_out;\n\n";
1428
1429         # auto-init the out section of a structure. I originally argued that
1430         # this was a bad idea as it hides bugs, but coping correctly
1431         # with initialisation and not wiping ref vars is turning
1432         # out to be too tricky (tridge)
1433         foreach my $e (@{$fn->{DATA}}) {
1434                 if (util::has_property($e, "out")) {
1435                         pidl "\tZERO_STRUCT(r->out);\n\n";
1436                         last;
1437                 }
1438         }
1439
1440         foreach my $e (@{$fn->{DATA}}) {
1441                 if (util::has_property($e, "in")) {
1442                         ParseFunctionElementPull($e, "in");
1443                 }
1444                 # we need to allocate any reference output variables, so that
1445                 # a dcerpc backend can be sure they are non-null
1446                 if (util::has_property($e, "out") && util::has_property($e, "ref")) {
1447                         AllocateRefVars($e);
1448                 }
1449         }
1450
1451         foreach my $e (@{$fn->{DATA}}) {
1452                 if (util::has_property($e, "in")) {
1453                         CheckArraySizes($e, "r->in.");
1454                 }
1455         }
1456
1457         pidl "\nndr_out:\n";
1458         pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
1459
1460         foreach my $e (@{$fn->{DATA}}) {
1461                 if (util::has_property($e, "out")) {
1462                         ParseFunctionElementPull($e, "out");
1463                 }
1464         }
1465
1466         foreach my $e (@{$fn->{DATA}}) {
1467                 if (util::has_property($e, "out")) {
1468                         CheckArraySizes($e, "r->out.");
1469                 }
1470         }
1471
1472         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
1473                 pidl "\tNDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, &r->out.result));\n";
1474         }
1475
1476         pidl "\ndone:\n";
1477         pidl "\n\treturn NT_STATUS_OK;\n}\n\n";
1478 }
1479
1480 #####################################################################
1481 # produce a function call table
1482 sub FunctionTable($)
1483 {
1484         my($interface) = shift;
1485         my($data) = $interface->{INHERITED_DATA};
1486         my $count = 0;
1487         my $uname = uc $interface->{NAME};
1488
1489         foreach my $d (@{$data}) {
1490                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
1491         }
1492
1493         return if ($count == 0);
1494
1495         pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {\n";
1496         foreach my $d (@{$data}) {
1497                 if ($d->{TYPE} eq "FUNCTION") {
1498                         pidl "\t{\n";
1499                         pidl "\t\t\"$d->{NAME}\",\n";
1500                         pidl "\t\tsizeof(struct $d->{NAME}),\n";
1501                         pidl "\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},\n";
1502                         pidl "\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},\n";
1503                         pidl "\t\t(ndr_print_function_t) ndr_print_$d->{NAME}\n";
1504                         pidl "\t},\n";
1505                 }
1506         }
1507         pidl "\t{ NULL, 0, NULL, NULL }\n};\n\n";
1508
1509         # If no endpoint is set, default to the interface name as a named pipe
1510         if (! defined $interface->{PROPERTIES}->{endpoint}) {
1511                 $interface->{PROPERTIES}->{endpoint} = "\"ncacn_np:[\\\\pipe\\\\" . $interface->{NAME} . "]\"";
1512         }
1513
1514         my @e = split / /, $interface->{PROPERTIES}->{endpoint};
1515         my $endpoint_count = $#e + 1;
1516
1517         pidl "static const char * const $interface->{NAME}\_endpoint_strings[] = {\n";
1518         foreach my $ep (@e) {
1519                 pidl "\t$ep, \n";
1520         }
1521         pidl "};\n\n";
1522
1523         pidl "static const struct dcerpc_endpoint_list $interface->{NAME}\_endpoints = {\n";
1524         pidl "\t$endpoint_count, $interface->{NAME}\_endpoint_strings\n";
1525         pidl "};\n\n";
1526
1527         pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {\n";
1528         pidl "\t\"$interface->{NAME}\",\n";
1529         pidl "\tDCERPC_$uname\_UUID,\n";
1530         pidl "\tDCERPC_$uname\_VERSION,\n";
1531         pidl "\tDCERPC_$uname\_HELPSTRING,\n";
1532         pidl "\t$count,\n";
1533         pidl "\t$interface->{NAME}\_calls,\n";
1534         pidl "\t&$interface->{NAME}\_endpoints\n";
1535         pidl "};\n\n";
1536
1537         pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)\n";
1538         pidl "{\n";
1539         pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});\n";
1540         pidl "}\n\n";
1541 }
1542
1543 #####################################################################
1544 # parse the interface definitions
1545 sub ParseInterface($)
1546 {
1547         my($interface) = shift;
1548         my($data) = $interface->{DATA};
1549
1550         foreach my $d (@{$data}) {
1551                 if ($d->{TYPE} eq "TYPEDEF") {
1552                     $structs{$d->{NAME}} = $d;
1553             }
1554         }
1555
1556         foreach my $d (@{$data}) {
1557                 ($d->{TYPE} eq "TYPEDEF") && 
1558                         ParseTypedefNdrSize($d);
1559         }
1560
1561         foreach my $d (@{$data}) {
1562                 ($d->{TYPE} eq "TYPEDEF") &&
1563                     ParseTypedefPush($d);
1564                 ($d->{TYPE} eq "FUNCTION") && 
1565                     ParseFunctionPush($d);
1566         }
1567         foreach my $d (@{$data}) {
1568                 ($d->{TYPE} eq "TYPEDEF") &&
1569                     ParseTypedefPull($d);
1570                 ($d->{TYPE} eq "FUNCTION") && 
1571                     ParseFunctionPull($d);
1572         }
1573         foreach my $d (@{$data}) {
1574                 if ($d->{TYPE} eq "TYPEDEF" &&
1575                     !util::has_property($d->{DATA}, "noprint")) {
1576                         ParseTypedefPrint($d);
1577                 }
1578                 if ($d->{TYPE} eq "FUNCTION" &&
1579                     !util::has_property($d, "noprint")) {
1580                         ParseFunctionPrint($d);
1581                 }
1582         }
1583
1584         FunctionTable($interface);
1585 }
1586
1587 sub RegistrationFunction($$)
1588 {
1589         my $idl = shift;
1590         my $filename = shift;
1591
1592         $filename =~ /.*\/ndr_(.*).c/;
1593         my $basename = $1;
1594         pidl "NTSTATUS dcerpc_$basename\_init(void)\n";
1595         pidl "{\n";
1596         pidl "\tNTSTATUS status = NT_STATUS_OK;\n";
1597         foreach my $interface (@{$idl}) {
1598                 next if $interface->{TYPE} ne "INTERFACE";
1599
1600                 my $data = $interface->{INHERITED_DATA};
1601                 my $count = 0;
1602                 foreach my $d (@{$data}) {
1603                         if ($d->{TYPE} eq "FUNCTION") { $count++; }
1604                 }
1605
1606                 next if ($count == 0);
1607
1608                 pidl "\tstatus = dcerpc_ndr_$interface->{NAME}_init();\n";
1609                 pidl "\tif (NT_STATUS_IS_ERR(status)) {\n";
1610                 pidl "\t\treturn status;\n";
1611                 pidl "\t}\n\n";
1612         }
1613         pidl "\treturn status;\n";
1614         pidl "}\n\n";
1615 }
1616
1617 #####################################################################
1618 # parse a parsed IDL structure back into an IDL file
1619 sub Parse($$)
1620 {
1621         my($idl) = shift;
1622         my($filename) = shift;
1623         my $h_filename = $filename;
1624
1625         if ($h_filename =~ /(.*)\.c/) {
1626                 $h_filename = "$1.h";
1627         }
1628
1629         open(OUT, ">$filename") || die "can't open $filename";    
1630
1631         pidl "/* parser auto-generated by pidl */\n\n";
1632         pidl "#include \"includes.h\"\n";
1633         pidl "#include \"$h_filename\"\n\n";
1634
1635         foreach my $x (@{$idl}) {
1636                 if ($x->{TYPE} eq "INTERFACE") { 
1637                         needed::BuildNeeded($x);
1638                         ParseInterface($x);
1639                 }
1640         }
1641
1642         RegistrationFunction($idl, $filename);
1643
1644         close(OUT);
1645 }
1646
1647 1;