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