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