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