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