- handle void functions
[samba.git] / source / build / pidl / parser.pm
1 ###################################################
2 # Ethereal parser generator for IDL structures
3 # Copyright tpot@samba.org 2001
4 # Copyright tridge@samba.org 2000
5 # released under the GNU GPL
6
7 package IdlParser;
8
9 use Data::Dumper;
10
11 my($res);
12
13 #####################################################################
14 # parse a properties list
15 sub ParseProperties($)
16 {
17     my($props) = shift;
18     foreach my $d (@{$props}) {
19         if (ref($d) ne "HASH") {
20             $res .= "[$d] ";
21         } else {
22             foreach my $k (keys %{$d}) {
23                 $res .= "[$k($d->{$k})] ";
24             }
25         }
26     }
27 }
28
29 ####################################################################
30 # work out the name of a size_is() variable
31 sub find_size_var($)
32 {
33         my($e) = shift;
34         my($fn) = $e->{PARENT};
35         my($size) = util::has_property($e, "size_is");
36         
37         if ($fn->{TYPE} ne "FUNCTION") {
38                 return "r->$size";
39         }
40
41         for my $e2 (@{$fn->{DATA}}) {
42                 if ($e2->{NAME} eq $size) {
43                         if (util::has_property($e2, "in")) {
44                                 return "r->in.$size";
45                         }
46                         if (util::has_property($e2, "out")) {
47                                 return "r->out.$size";
48                         }
49                 }
50         }
51         die "invalid variable in size_is($size) for element $e->{NAME} in $fn->{NAME}\n";
52 }
53
54
55 #####################################################################
56 # parse an array - push side
57 sub ParseArrayPush($$)
58 {
59         my $e = shift;
60         my $var_prefix = shift;
61         my $size = find_size_var($e);
62
63         if (util::is_scalar_type($e->{TYPE})) {
64                 $res .= "\t\tNDR_CHECK(ndr_push_array_$e->{TYPE}(ndr, $var_prefix$e->{NAME}, $size));\n";
65         } else {
66                 $res .= "\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";
67         }
68 }
69
70 #####################################################################
71 # parse an array - pull side
72 sub ParseArrayPull($$)
73 {
74         my $e = shift;
75         my $var_prefix = shift;
76         my $size = find_size_var($e);
77
78         if (!util::has_property($e, "ref")) {
79                 $res .= "\t\tNDR_ALLOC_N_SIZE(ndr, $var_prefix$e->{NAME}, $size, sizeof($var_prefix$e->{NAME}\[0]));\n";
80         }
81         if (util::is_scalar_type($e->{TYPE})) {
82                 $res .= "\t\tNDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $var_prefix$e->{NAME}, $size));\n";
83         } else {
84                 $res .= "\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";
85         }
86 }
87
88
89 #####################################################################
90 # parse scalars in a structure element
91 sub ParseElementPushScalar($$$)
92 {
93         my($e) = shift;
94         my($var_prefix) = shift;
95         my($ndr_flags) = shift;
96
97         if (defined $e->{VALUE}) {
98                 $res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $e->{VALUE}));\n";
99         } elsif ($e->{POINTERS} && 
100                  !util::has_property($e, "ref")) {
101                 $res .= "\tNDR_CHECK(ndr_push_ptr(ndr, $var_prefix$e->{NAME}));\n";
102         } elsif (util::is_builtin_type($e->{TYPE})) {
103                 if (util::is_scalar_type($e->{TYPE}) &&
104                     util::has_property($e, "ref")) {
105                         $res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, *$var_prefix$e->{NAME}));\n";
106                 } else {
107                         $res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
108                 }
109         } else {
110                 if (util::is_scalar_type($e->{TYPE}) ||
111                     $e->{POINTERS}) {
112                         $res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
113                 } else {
114                         $res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
115                 }
116         }
117 }
118
119 #####################################################################
120 # parse scalars in a structure element - pull size
121 sub ParseElementPullScalar($$$)
122 {
123         my($e) = shift;
124         my($var_prefix) = shift;
125         my($ndr_flags) = shift;
126
127         if (defined $e->{VALUE}) {
128                 $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $e->{VALUE}));\n";
129         } elsif ($e->{POINTERS} && 
130                  !util::has_property($e, "ref")) {
131                 $res .= "\tNDR_CHECK(ndr_pull_uint32(ndr, &_ptr_$e->{NAME}));\n";
132                 $res .= "\tif (_ptr_$e->{NAME}) {\n";
133                 $res .= "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
134                 $res .= "\t} else {\n";
135                 $res .= "\t\t$var_prefix$e->{NAME} = NULL;\n";
136                 $res .= "\t}\n";
137         } elsif (!util::is_scalar_type($e->{TYPE}) &&
138                  util::has_property($e, "ref")) {
139                 if (util::is_builtin_type($e->{TYPE})) {
140                         $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
141                 } else {
142                         $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
143                 }
144         } else {
145                 if (util::is_builtin_type($e->{TYPE})) {
146                         if (!util::has_property($e, "ref")) {
147                                 $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, &$var_prefix$e->{NAME}));\n";
148                         } else {
149                                 $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
150                         }
151                 } else {
152                         $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
153                 }
154         }
155 }
156
157 #####################################################################
158 # parse buffers in a structure element
159 sub ParseElementPushBuffer($$)
160 {
161         my($e) = shift;
162         my($var_prefix) = shift;
163
164         if (util::has_property($e, "ref")) {
165                 return;
166         }
167
168         if (util::is_scalar_type($e->{TYPE}) && !$e->{POINTERS}) {
169                 return;
170         }
171
172         if ($e->{POINTERS}) {
173                 $res .= "\tif ($var_prefix$e->{NAME}) {\n";
174         }
175             
176         if (util::has_property($e, "size_is")) {
177                 ParseArrayPush($e, "r->");
178         } else {
179                 if (util::is_scalar_type($e->{TYPE})) {
180                         $res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, *$var_prefix$e->{NAME}));\n";
181                 } elsif (!$e->{POINTERS}) {
182                         $res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, ndr_flags, &$var_prefix$e->{NAME}));\n";
183                 } elsif (util::is_builtin_type($e->{TYPE})) {
184                         $res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
185                 } else {
186                         $res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, ndr_flags, $var_prefix$e->{NAME}));\n";
187                 }
188         }
189
190         if ($e->{POINTERS}) {
191                 $res .= "\t}\n";
192         }       
193 }
194
195
196 #####################################################################
197 # parse buffers in a structure element - pull side
198 sub ParseElementPullBuffer($$$)
199 {
200         my($e) = shift;
201         my($var_prefix) = shift;
202         my($ndr_flags) = shift;
203
204         if (util::has_property($e, "ref")) {
205                 return;
206         }
207
208         if (util::is_scalar_type($e->{TYPE}) && !$e->{POINTERS}) {
209                 return;
210         }
211
212         if ($e->{POINTERS}) {
213                 $res .= "\tif ($var_prefix$e->{NAME}) {\n";
214         }
215             
216         if (util::has_property($e, "size_is")) {
217                 ParseArrayPull($e, "r->");
218         } else {
219                 if (!$e->{POINTERS} ||
220                     $e->{TYPE} =~ "unistr.*") {
221                         if (util::is_builtin_type($e->{TYPE})) {
222                                 $res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, &$var_prefix$e->{NAME}));\n";
223                         } else {
224                                 $res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
225                         }
226                 } elsif (util::is_builtin_type($e->{TYPE})) {
227                         $res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
228                 } else {
229                         $res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
230                 }
231         }
232
233         if ($e->{POINTERS}) {
234                 $res .= "\t}\n";
235         }       
236 }
237
238 #####################################################################
239 # parse a struct
240 sub ParseStructPush($)
241 {
242         my($struct) = shift;
243         my($struct_len);
244
245         if (! defined $struct->{ELEMENTS}) {
246                 return;
247         }
248
249         # see if we have a structure length
250         foreach my $e (@{$struct->{ELEMENTS}}) {
251                 $e->{PARENT} = $struct;
252                 if (util::has_property($e, "struct_len")) {
253                         $struct_len = $e;
254                         $e->{VALUE} = "0";
255                 }
256         }       
257
258         if (defined $struct_len) {
259                 $res .= "\tstruct ndr_push_save _save1, _save2, _save3;\n";
260                 $res .= "\tndr_push_save(ndr, &_save1);\n";
261         }
262
263         $res .= "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
264
265         foreach my $e (@{$struct->{ELEMENTS}}) {
266                 if (defined($struct_len) && $e == $struct_len) {
267                         $res .= "\tNDR_CHECK(ndr_push_align_$e->{TYPE}(ndr));\n";
268                         $res .= "\tndr_push_save(ndr, &_save2);\n";
269                 }
270                 ParseElementPushScalar($e, "r->", "NDR_SCALARS");
271         }       
272
273         $res .= "buffers:\n";
274         $res .= "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
275         foreach my $e (@{$struct->{ELEMENTS}}) {
276                 ParseElementPushBuffer($e, "r->");
277         }
278
279         if (defined $struct_len) {
280                 $res .= "\tndr_push_save(ndr, &_save3);\n";
281                 $res .= "\tndr_push_restore(ndr, &_save2);\n";
282                 $struct_len->{VALUE} = "_save3.offset - _save1.offset";
283                 ParseElementPushScalar($struct_len, "r->", "NDR_SCALARS");
284                 $res .= "\tndr_push_restore(ndr, &_save3);\n";
285         }
286
287         $res .= "done:\n";
288 }
289
290 #####################################################################
291 # parse a struct - pull side
292 sub ParseStructPull($)
293 {
294         my($struct) = shift;
295         my($struct_len);
296
297         if (! defined $struct->{ELEMENTS}) {
298                 return;
299         }
300
301         # declare any internal pointers we need
302         foreach my $e (@{$struct->{ELEMENTS}}) {
303                 $e->{PARENT} = $struct;
304                 if ($e->{POINTERS} && 
305                     !util::has_property($e, "ref")) {
306                         $res .= "\tuint32 _ptr_$e->{NAME};\n";
307                 }
308         }
309
310
311         # see if we have a structure length. If we do then we need to advance
312         # the ndr_pull offset to that length past the front of the structure
313         # when we have finished with the structure
314         # we also need to make sure that we limit the size of our parsing
315         # of this structure to the given size
316         foreach my $e (@{$struct->{ELEMENTS}}) {
317                 if (util::has_property($e, "struct_len")) {
318                         $struct_len = $e;
319                         $e->{VALUE} = "&_size";
320                 }
321         }       
322
323         if (defined $struct_len) {
324                 $res .= "\tuint32 _size;\n";
325                 $res .= "\tstruct ndr_pull_save _save;\n";
326                 $res .= "\tndr_pull_save(ndr, &_save);\n";
327         }
328
329         $res .= "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
330         foreach my $e (@{$struct->{ELEMENTS}}) {
331                 ParseElementPullScalar($e, "r->", "NDR_SCALARS");
332                 if (defined($struct_len) && $e == $struct_len) {
333                         $res .= "\tNDR_CHECK(ndr_pull_limit_size(ndr, _size, 4));\n";
334                 }
335         }       
336
337         $res .= "buffers:\n";
338         $res .= "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n";
339         foreach my $e (@{$struct->{ELEMENTS}}) {
340                 ParseElementPullBuffer($e, "r->", "ndr_flags");
341         }
342
343         if (defined $struct_len) {
344                 $res .= "\tndr_pull_restore(ndr, &_save);\n";
345                 $res .= "\tNDR_CHECK(ndr_pull_advance(ndr, _size));\n";
346         }
347
348         $res .= "done:\n";
349 }
350
351
352 #####################################################################
353 # parse a union element
354 sub ParseUnionElementPush($)
355 {
356         die "unions not done";
357 }
358
359 #####################################################################
360 # parse a union - push side
361 sub ParseUnionPush($)
362 {
363         die "unions not done";  
364 }
365
366 #####################################################################
367 # parse a union - pull side
368 sub ParseUnionPull($)
369 {
370         die "unions not done";  
371 }
372
373 #####################################################################
374 # parse a type
375 sub ParseTypePush($)
376 {
377         my($data) = shift;
378
379         if (ref($data) eq "HASH") {
380                 ($data->{TYPE} eq "STRUCT") &&
381                     ParseStructPush($data);
382                 ($data->{TYPE} eq "UNION") &&
383             ParseUnionPush($data);
384         }
385 }
386
387 #####################################################################
388 # parse a type
389 sub ParseTypePull($)
390 {
391         my($data) = shift;
392
393         if (ref($data) eq "HASH") {
394                 ($data->{TYPE} eq "STRUCT") &&
395                     ParseStructPull($data);
396                 ($data->{TYPE} eq "UNION") &&
397                     ParseUnionPull($data);
398         }
399 }
400
401 #####################################################################
402 # parse a typedef - push side
403 sub ParseTypedefPush($)
404 {
405         my($e) = shift;
406
407         $res .= "static NTSTATUS ndr_push_$e->{NAME}(struct ndr_push *ndr, int ndr_flags, struct $e->{NAME} *r)";
408         $res .= "\n{\n";
409         ParseTypePush($e->{DATA});
410         $res .= "\treturn NT_STATUS_OK;\n";
411         $res .= "}\n\n";
412 }
413
414
415 #####################################################################
416 # parse a typedef - pull side
417 sub ParseTypedefPull($)
418 {
419         my($e) = shift;
420
421         $res .= "static NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, struct $e->{NAME} *r)";
422         $res .= "\n{\n";
423         ParseTypePull($e->{DATA});
424         $res .= "\treturn NT_STATUS_OK;\n";
425         $res .= "}\n\n";
426 }
427
428
429
430
431 #####################################################################
432 # parse a function
433 sub ParseFunctionPush($)
434
435         my($function) = shift;
436
437         # Input function
438         $res .= "NTSTATUS ndr_push_$function->{NAME}(struct ndr_push *ndr, struct $function->{NAME} *r)\n{\n";
439
440         foreach my $e (@{$function->{DATA}}) {
441                 if (util::has_property($e, "in")) {
442                         $e->{PARENT} = $function;
443                         if (util::has_property($e, "size_is")) {
444                                 $res .= "\tif (r->in.$e->{NAME}) {\n";
445                                 if (!util::is_scalar_type($e->{TYPE})) {
446                                         $res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
447                                 }
448                                 ParseArrayPush($e, "r->in.");
449                                 $res .= "\t}\n";
450                         } else {
451                                 ParseElementPushScalar($e, "r->in.", "NDR_SCALARS|NDR_BUFFERS");
452                                 ParseElementPushBuffer($e, "r->in.");
453                         }
454                 }
455         }
456     
457         $res .= "\n\treturn NT_STATUS_OK;\n}\n\n";
458 }
459
460 #####################################################################
461 # parse a function
462 sub ParseFunctionPull($)
463
464         my($fn) = shift;
465
466         # pull function args
467         $res .= "NTSTATUS ndr_pull_$fn->{NAME}(struct ndr_pull *ndr, struct $fn->{NAME} *r)\n{\n";
468
469         # declare any internal pointers we need
470         foreach my $e (@{$fn->{DATA}}) {
471                 if (util::has_property($e, "out") &&
472                     $e->{POINTERS} && 
473                     !util::is_scalar_type($e->{TYPE}) &&
474                     !util::has_property($e, "ref")) {
475                         $res .= "\tuint32 _ptr_$e->{NAME};\n";
476                 }
477         }
478
479         foreach my $e (@{$fn->{DATA}}) {
480                 if (util::has_property($e, "out")) {
481                         $e->{PARENT} = $fn;
482                         if (util::has_property($e, "size_is")) {
483                                 $res .= "\tif (r->out.$e->{NAME}) {\n";
484                                 if (!util::is_scalar_type($e->{TYPE})) {
485                                         $res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
486                                 }
487                                 ParseArrayPull($e, "r->out.");
488                                 $res .= "\t}\n";
489                         } else {
490                                 if ($e->{POINTERS} &&
491                                     !util::has_property($e, "ref")) {
492                                         $res .= "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
493                                 }
494                                 ParseElementPullScalar($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
495                                 ParseElementPullBuffer($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
496                         }
497                 }
498         }
499
500         if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
501                 $res .= "\tNDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, &r->out.result));\n";
502         }
503
504     
505         $res .= "\n\treturn NT_STATUS_OK;\n}\n\n";
506 }
507
508 #####################################################################
509 # parse a typedef
510 sub ParseTypedef($)
511 {
512         my($e) = shift;
513         ParseTypedefPush($e);
514         ParseTypedefPull($e);
515 }
516
517 #####################################################################
518 # parse a function
519 sub ParseFunction($)
520 {
521         my $i = shift;
522         ParseFunctionPush($i);
523         ParseFunctionPull($i);
524 }
525
526 #####################################################################
527 # parse the interface definitions
528 sub ParseInterface($)
529 {
530         my($interface) = shift;
531         my($data) = $interface->{DATA};
532         foreach my $d (@{$data}) {
533                 ($d->{TYPE} eq "TYPEDEF") &&
534                     ParseTypedef($d);
535                 ($d->{TYPE} eq "FUNCTION") && 
536                     ParseFunction($d);
537         }
538 }
539
540
541 #####################################################################
542 # parse a parsed IDL structure back into an IDL file
543 sub Parse($)
544 {
545         my($idl) = shift;
546         $res = "/* parser auto-generated by pidl */\n\n";
547         $res .= "#include \"includes.h\"\n\n";
548         foreach my $x (@{$idl}) {
549                 ($x->{TYPE} eq "INTERFACE") && 
550                     ParseInterface($x);
551         }
552         return $res;
553 }
554
555 1;