r5034: - added a type mapping function in pidl, so the type names in our IDL
[samba.git] / source4 / build / pidl / header.pm
1 ###################################################
2 # create C header files for an IDL structure
3 # Copyright tridge@samba.org 2000
4 # released under the GNU GPL
5
6 package IdlHeader;
7
8 use strict;
9 use needed;
10
11 my($res);
12 my($tab_depth);
13
14 sub tabs()
15 {
16         for (my($i)=0; $i < $tab_depth; $i++) {
17                 $res .= "\t";
18         }
19 }
20
21 #####################################################################
22 # parse a properties list
23 sub HeaderProperties($)
24 {
25     my($props) = shift;
26
27     return;
28
29     foreach my $d (@{$props}) {
30         if (ref($d) ne "HASH") {
31             $res .= "/* [$d] */ ";
32         } else {
33             foreach my $k (keys %{$d}) {
34                 $res .= "/* [$k($d->{$k})] */ ";
35             }
36         }
37     }
38 }
39
40 #####################################################################
41 # parse a structure element
42 sub HeaderElement($)
43 {
44     my($element) = shift;
45
46     (defined $element->{PROPERTIES}) && HeaderProperties($element->{PROPERTIES});
47     $res .= tabs();
48     HeaderType($element, $element->{TYPE}, "");
49     $res .= " ";
50     if ($element->{POINTERS} && 
51         $element->{TYPE} ne "string") {
52             my($n) = $element->{POINTERS};
53             for (my($i)=$n; $i > 0; $i--) {
54                     $res .= "*";
55             }
56     }
57     if (defined $element->{ARRAY_LEN} && 
58         !util::is_constant($element->{ARRAY_LEN}) &&
59         !$element->{POINTERS}) {
60             # conformant arrays are ugly! I choose to implement them with
61             # pointers instead of the [1] method
62             $res .= "*";
63     }
64     $res .= "$element->{NAME}";
65     if (defined $element->{ARRAY_LEN} && util::is_constant($element->{ARRAY_LEN})) {
66             $res .= "[$element->{ARRAY_LEN}]";
67     }
68     $res .= ";\n";
69 }
70
71 #####################################################################
72 # parse a struct
73 sub HeaderStruct($$)
74 {
75     my($struct) = shift;
76     my($name) = shift;
77     $res .= "\nstruct $name {\n";
78     $tab_depth++;
79     my $el_count=0;
80     if (defined $struct->{ELEMENTS}) {
81         foreach my $e (@{$struct->{ELEMENTS}}) {
82             HeaderElement($e);
83             $el_count++;
84         }
85     }
86     if ($el_count == 0) {
87             # some compilers can't handle empty structures
88             $res .= "\tchar _empty_;\n";
89     }
90     $tab_depth--;
91     $res .= "}";
92 }
93
94 #####################################################################
95 # parse a enum
96 sub HeaderEnum($$)
97 {
98     my($enum) = shift;
99     my($name) = shift;
100
101     util::register_enum($enum, $name);
102
103     $res .= "\nenum $name {\n";
104     $tab_depth++;
105     my $els = \@{$enum->{ELEMENTS}};
106     foreach my $i (0 .. $#{$els}-1) {
107             my $e = ${$els}[$i];
108             tabs();
109             chomp $e;
110             $res .= "$e,\n";
111     }
112
113     my $e = ${$els}[$#{$els}];
114     tabs();
115     chomp $e;
116     if ($e !~ /^(.*?)\s*$/) {
117             die "Bad enum $name\n";
118     }
119     $res .= "$1\n";
120     $tab_depth--;
121     $res .= "}";
122 }
123
124 #####################################################################
125 # parse a bitmap
126 sub HeaderBitmap($$)
127 {
128     my($bitmap) = shift;
129     my($name) = shift;
130
131     util::register_bitmap($bitmap, $name);
132
133     $res .= "\n/* bitmap $name */\n";
134
135     my $els = \@{$bitmap->{ELEMENTS}};
136     foreach my $i (0 .. $#{$els}) {
137             my $e = ${$els}[$i];
138             chomp $e;
139             $res .= "#define $e\n";
140     }
141
142     $res .= "\n";
143 }
144
145 #####################################################################
146 # parse a union
147 sub HeaderUnion($$)
148 {
149         my($union) = shift;
150         my($name) = shift;
151         my %done = ();
152
153         (defined $union->{PROPERTIES}) && HeaderProperties($union->{PROPERTIES});
154         $res .= "\nunion $name {\n";
155         $tab_depth++;
156         foreach my $e (@{$union->{DATA}}) {
157                 if ($e->{TYPE} eq "UNION_ELEMENT") {
158                         if (! defined $done{$e->{DATA}->{NAME}}) {
159                                 HeaderElement($e->{DATA});
160                         }
161                         $done{$e->{DATA}->{NAME}} = 1;
162                 }
163         }
164         $tab_depth--;
165         $res .= "}";
166 }
167
168 #####################################################################
169 # parse a type
170 sub HeaderType($$$)
171 {
172         my $e = shift;
173         my($data) = shift;
174         my($name) = shift;
175         if (ref($data) eq "HASH") {
176                 ($data->{TYPE} eq "ENUM") &&
177                     HeaderEnum($data, $name);
178                 ($data->{TYPE} eq "BITMAP") &&
179                     HeaderBitmap($data, $name);
180                 ($data->{TYPE} eq "STRUCT") &&
181                     HeaderStruct($data, $name);
182                 ($data->{TYPE} eq "UNION") &&
183                     HeaderUnion($data, $name);
184                 return;
185         }
186         if ($data =~ "string") {
187                 $res .= "const char *";
188         } elsif (util::is_enum($e->{TYPE})) {
189                 $res .= "enum $data";
190         } elsif (util::is_bitmap($e->{TYPE})) {
191                 my $bitmap = util::get_bitmap($e->{TYPE});
192                 $res .= util::bitmap_type_decl($bitmap);
193         } elsif (util::is_scalar_type($data)) {
194                 $res .= util::map_type($data);
195         } elsif (util::has_property($e, "switch_is")) {
196                 $res .= "union $data";
197         } else {
198                 $res .= "struct $data";
199         }
200 }
201
202 #####################################################################
203 # parse a declare
204 sub HeaderDeclare($)
205 {
206         my($declare) = shift;
207
208         if ($declare->{DATA}->{TYPE} eq "ENUM") {
209                 util::register_enum($declare, $declare->{NAME});
210         } elsif ($declare->{DATA}->{TYPE} eq "BITMAP") {
211                 util::register_bitmap($declare, $declare->{NAME});
212         }
213 }
214
215 #####################################################################
216 # parse a typedef
217 sub HeaderTypedef($)
218 {
219     my($typedef) = shift;
220     HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
221     $res .= ";\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
222 }
223
224 #####################################################################
225 # prototype a typedef
226 sub HeaderTypedefProto($)
227 {
228     my($d) = shift;
229
230     if (needed::is_needed("ndr_size_$d->{NAME}")) {
231             if ($d->{DATA}{TYPE} eq "STRUCT") {
232                     $res .= "size_t ndr_size_$d->{NAME}(const struct $d->{NAME} *r, int flags);\n";
233             }
234             if ($d->{DATA}{TYPE} eq "UNION") {
235                     $res .= "size_t ndr_size_$d->{NAME}(const union $d->{NAME} *r, uint32_t level, int flags);\n";
236             }
237     }
238
239     if (!util::has_property($d, "public")) {
240             return;
241     }
242
243     if ($d->{DATA}{TYPE} eq "STRUCT") {
244             $res .= "NTSTATUS ndr_push_$d->{NAME}(struct ndr_push *ndr, int ndr_flags, struct $d->{NAME} *r);\n";
245             $res .= "NTSTATUS ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, struct $d->{NAME} *r);\n";
246             if (!util::has_property($d, "noprint")) {
247                     $res .= "void ndr_print_$d->{NAME}(struct ndr_print *ndr, const char *name, struct $d->{NAME} *r);\n";
248             }
249
250     }
251     if ($d->{DATA}{TYPE} eq "UNION") {
252             $res .= "NTSTATUS ndr_push_$d->{NAME}(struct ndr_push *ndr, int ndr_flags, int level, union $d->{NAME} *r);\n";
253             $res .= "NTSTATUS ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, int level, union $d->{NAME} *r);\n";
254             if (!util::has_property($d, "noprint")) {
255                     $res .= "void ndr_print_$d->{NAME}(struct ndr_print *ndr, const char *name, int level, union $d->{NAME} *r);\n";
256             }
257     }
258
259     if ($d->{DATA}{TYPE} eq "ENUM") {
260             $res .= "NTSTATUS ndr_push_$d->{NAME}(struct ndr_push *ndr, enum $d->{NAME} r);\n";
261             $res .= "NTSTATUS ndr_pull_$d->{NAME}(struct ndr_pull *ndr, enum $d->{NAME} *r);\n";
262             if (!util::has_property($d, "noprint")) {
263                     $res .= "void ndr_print_$d->{NAME}(struct ndr_print *ndr, const char *name, enum $d->{NAME} r);\n";
264             }
265     }
266
267     if ($d->{DATA}{TYPE} eq "BITMAP") {
268             my $type_decl = util::bitmap_type_decl($d->{DATA});
269             $res .= "NTSTATUS ndr_push_$d->{NAME}(struct ndr_push *ndr, $type_decl r);\n";
270             $res .= "NTSTATUS ndr_pull_$d->{NAME}(struct ndr_pull *ndr, $type_decl *r);\n";
271             if (!util::has_property($d, "noprint")) {
272                     $res .= "void ndr_print_$d->{NAME}(struct ndr_print *ndr, const char *name, $type_decl r);\n";
273             }
274     }
275 }
276
277 #####################################################################
278 # parse a const
279 sub HeaderConst($)
280 {
281     my($const) = shift;
282     if (!defined($const->{ARRAY_LEN})) {
283         $res .= "#define $const->{NAME}\t( $const->{VALUE} )\n";
284     } else {
285         $res .= "#define $const->{NAME}\t $const->{VALUE}\n";
286     }
287 }
288
289 #####################################################################
290 # parse a function
291 sub HeaderFunctionInOut($$)
292 {
293     my($fn) = shift;
294     my($prop) = shift;
295
296     foreach my $e (@{$fn->{DATA}}) {
297             if (util::has_property($e, $prop)) {
298                     HeaderElement($e);
299             }
300     }
301 }
302
303 #####################################################################
304 # determine if we need an "in" or "out" section
305 sub HeaderFunctionInOut_needed($$)
306 {
307     my($fn) = shift;
308     my($prop) = shift;
309
310     if ($prop eq "out" && $fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
311             return 1;
312     }
313
314     foreach my $e (@{$fn->{DATA}}) {
315             if (util::has_property($e, $prop)) {
316                     return 1;
317             }
318     }
319
320     return undef;
321 }
322
323
324 #####################################################################
325 # parse a function
326 sub HeaderFunction($)
327 {
328     my($fn) = shift;
329
330     $res .= "\nstruct $fn->{NAME} {\n";
331     $tab_depth++;
332     my $needed = 0;
333
334     if (HeaderFunctionInOut_needed($fn, "in")) {
335             tabs();
336             $res .= "struct {\n";
337             $tab_depth++;
338             HeaderFunctionInOut($fn, "in");
339             $tab_depth--;
340             tabs();
341             $res .= "} in;\n\n";
342             $needed++;
343     }
344
345     if (HeaderFunctionInOut_needed($fn, "out")) {
346             tabs();
347             $res .= "struct {\n";
348             $tab_depth++;
349             HeaderFunctionInOut($fn, "out");
350             if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
351                     tabs();
352                     $res .= util::map_type($fn->{RETURN_TYPE}) . " result;\n";
353             }
354             $tab_depth--;
355             tabs();
356             $res .= "} out;\n\n";
357             $needed++;
358     }
359
360     if (! $needed) {
361             # sigh - some compilers don't like empty structures
362             tabs();
363             $res .= "int _dummy_element;\n";
364     }
365
366     $tab_depth--;
367     $res .= "};\n\n";
368 }
369
370 #####################################################################
371 # output prototypes for a IDL function
372 sub HeaderFnProto($$)
373 {
374         my $interface = shift;
375     my $fn = shift;
376     my $name = $fn->{NAME};
377         
378     $res .= "void ndr_print_$name(struct ndr_print *ndr, const char *name, int flags, struct $name *r);\n";
379
380         if (util::has_property($interface, "object")) {
381                 $res .= "NTSTATUS dcom_$interface->{NAME}_$name (struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r);\n";
382         } else {
383             $res .= "NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
384         $res .= "struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
385         }
386     $res .= "\n";
387 }
388
389
390 #####################################################################
391 # generate vtable structure for DCOM interface
392 sub HeaderVTable($)
393 {
394         my $interface = shift;
395         $res .= "struct dcom_$interface->{NAME}_vtable {\n";
396         if (defined($interface->{BASE})) {
397                 $res .= "\tstruct dcom_$interface->{BASE}\_vtable base;\n";
398         }
399
400         my $data = $interface->{DATA};
401         foreach my $d (@{$data}) {
402                 $res .= "\tNTSTATUS (*$d->{NAME}) (struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $d->{NAME} *r);\n" if ($d->{TYPE} eq "FUNCTION");
403         }
404         $res .= "};\n\n";
405 }
406
407
408 #####################################################################
409 # parse the interface definitions
410 sub HeaderInterface($)
411 {
412     my($interface) = shift;
413     my($data) = $interface->{DATA};
414
415     my $count = 0;
416
417     $res .= "#ifndef _HEADER_NDR_$interface->{NAME}\n";
418     $res .= "#define _HEADER_NDR_$interface->{NAME}\n\n";
419
420     if (defined $interface->{PROPERTIES}->{depends}) {
421             my @d = split / /, $interface->{PROPERTIES}->{depends};
422             foreach my $i (@d) {
423                     $res .= "#include \"librpc/gen_ndr/ndr_$i\.h\"\n";
424             }
425     }
426
427     if (defined $interface->{PROPERTIES}->{uuid}) {
428             my $name = uc $interface->{NAME};
429             $res .= "#define DCERPC_$name\_UUID " . 
430                 util::make_str($interface->{PROPERTIES}->{uuid}) . "\n";
431
432                 if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
433             $res .= "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}\n";
434
435             $res .= "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n";
436
437                 if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
438                 $res .= "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}\n";
439
440             $res .= "\nextern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
441             $res .= "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);\n\n";
442     }
443
444     foreach my $d (@{$data}) {
445             if ($d->{TYPE} eq "FUNCTION") {
446                     my $u_name = uc $d->{NAME};
447                         $res .= "#define DCERPC_$u_name (";
448                 
449                         if (defined($interface->{BASE})) {
450                                 $res .= "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
451                         }
452                         
453                     $res .= sprintf("0x%02x", $count) . ")\n";
454                     $count++;
455             }
456     }
457
458         $res .= "\n#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT (";
459         
460         if (defined($interface->{BASE})) {
461                 $res .= "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
462         }
463         
464         $res .= "$count)\n\n";
465
466     foreach my $d (@{$data}) {
467         ($d->{TYPE} eq "CONST") &&
468             HeaderConst($d);
469         ($d->{TYPE} eq "DECLARE") &&
470             HeaderDeclare($d);
471         ($d->{TYPE} eq "TYPEDEF") &&
472             HeaderTypedef($d);
473         ($d->{TYPE} eq "TYPEDEF") &&
474             HeaderTypedefProto($d);
475         ($d->{TYPE} eq "FUNCTION") &&
476             HeaderFunction($d);
477         ($d->{TYPE} eq "FUNCTION") &&
478             HeaderFnProto($interface, $d);
479     }
480         
481         (util::has_property($interface, "object")) &&
482                 HeaderVTable($interface);
483
484     $res .= "#endif /* _HEADER_NDR_$interface->{NAME} */\n";
485 }
486
487 #####################################################################
488 # parse a parsed IDL into a C header
489 sub Parse($)
490 {
491     my($idl) = shift;
492     $tab_depth = 0;
493
494     $res = "/* header auto-generated by pidl */\n\n";
495     foreach my $x (@{$idl}) {
496             if ($x->{TYPE} eq "INTERFACE") {
497                     needed::BuildNeeded($x);
498                     HeaderInterface($x);
499             }
500     }
501     return $res;
502 }
503
504 1;