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