75d4c235cb4203d8ce1a6acd8af543264f921524
[kai/samba.git] / source4 / pidl / lib / Parse / Pidl / Samba4 / Header.pm
1 ###################################################
2 # create C header files for an IDL structure
3 # Copyright tridge@samba.org 2000
4 # Copyright jelmer@samba.org 2005
5 # released under the GNU GPL
6
7 package Parse::Pidl::Samba4::Header;
8
9 use strict;
10 use Parse::Pidl qw(fatal);
11 use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
12 use Parse::Pidl::Util qw(has_property is_constant unmake_str);
13 use Parse::Pidl::Samba4 qw(is_intree ElementStars ArrayBrackets);
14
15 use vars qw($VERSION);
16 $VERSION = '0.01';
17
18 my($res);
19 my($tab_depth);
20
21 sub pidl($) { $res .= shift; }
22
23 sub tabs()
24 {
25         my $res = "";
26         $res .="\t" foreach (1..$tab_depth);
27         return $res;
28 }
29
30 #####################################################################
31 # parse a properties list
32 sub HeaderProperties($$)
33 {
34         my($props,$ignores) = @_;
35         my $ret = "";
36
37         foreach my $d (keys %{$props}) {
38                 next if (grep(/^$d$/, @$ignores));
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         pidl tabs();
58         if (has_property($element, "represent_as")) {
59                 pidl mapTypeName($element->{PROPERTIES}->{represent_as})." ";
60         } else {
61                 if (ref($element->{TYPE}) eq "HASH") {
62                         HeaderType($element, $element->{TYPE}, $element->{TYPE}->{NAME});
63                 } else {
64                         HeaderType($element, $element->{TYPE}, "");
65                 }
66                 pidl " ".ElementStars($element);
67         }
68         pidl $element->{NAME};
69         pidl ArrayBrackets($element);
70
71         pidl ";";
72         if (defined $element->{PROPERTIES}) {
73                 HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
74         }
75         pidl "\n";
76 }
77
78 #####################################################################
79 # parse a struct
80 sub HeaderStruct($$)
81 {
82         my($struct,$name) = @_;
83         pidl "struct $name";
84         return if (not defined($struct->{ELEMENTS}));
85         pidl " {\n";
86         $tab_depth++;
87         my $el_count=0;
88         foreach (@{$struct->{ELEMENTS}}) {
89                 HeaderElement($_);
90                 $el_count++;
91         }
92         if ($el_count == 0) {
93                 # some compilers can't handle empty structures
94                 pidl tabs()."char _empty_;\n";
95         }
96         $tab_depth--;
97         pidl tabs()."}";
98         if (defined $struct->{PROPERTIES}) {
99                 HeaderProperties($struct->{PROPERTIES}, []);
100         }
101 }
102
103 #####################################################################
104 # parse a enum
105 sub HeaderEnum($$)
106 {
107         my($enum,$name) = @_;
108         my $first = 1;
109
110         pidl "#ifndef USE_UINT_ENUMS\n";
111         pidl "enum $name {\n";
112         $tab_depth++;
113         if (defined($enum->{ELEMENTS})) {
114                 foreach my $e (@{$enum->{ELEMENTS}}) {
115                         unless ($first) { pidl ",\n"; }
116                         $first = 0;
117                         pidl tabs();
118                         pidl $e;
119                 }
120         }
121         pidl "\n";
122         $tab_depth--;
123         pidl "}\n";
124         pidl "#else\n";
125         my $count = 0;
126         pidl "enum $name { __donnot_use_enum_$name=0x7FFFFFFF}\n";
127         my $with_val = 0;
128         my $without_val = 0;
129         if (defined($enum->{ELEMENTS})) {
130                 foreach my $e (@{$enum->{ELEMENTS}}) {
131                         my $t = "$e";
132                         my $name;
133                         my $value;
134                         if ($t =~ /(.*)=(.*)/) {
135                                 $name = $1;
136                                 $value = $2;
137                                 $with_val = 1;
138                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
139                                         unless ($without_val == 0);
140                         } else {
141                                 $name = $t;
142                                 $value = $count++;
143                                 $without_val = 1;
144                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
145                                         unless ($with_val == 0);
146                         }
147                         pidl "#define $name ( $value )\n";
148                 }
149         }
150         pidl "#endif\n";
151 }
152
153 #####################################################################
154 # parse a bitmap
155 sub HeaderBitmap($$)
156 {
157         my($bitmap,$name) = @_;
158
159         return unless defined($bitmap->{ELEMENTS});
160
161         pidl "/* bitmap $name */\n";
162         pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
163         pidl "\n";
164 }
165
166 #####################################################################
167 # parse a union
168 sub HeaderUnion($$)
169 {
170         my($union,$name) = @_;
171         my %done = ();
172
173         pidl "union $name";
174         return if (not defined($union->{ELEMENTS}));
175         pidl " {\n";
176         $tab_depth++;
177         foreach my $e (@{$union->{ELEMENTS}}) {
178                 if ($e->{TYPE} ne "EMPTY") {
179                         if (! defined $done{$e->{NAME}}) {
180                                 HeaderElement($e);
181                         }
182                         $done{$e->{NAME}} = 1;
183                 }
184         }
185         $tab_depth--;
186         pidl "}";
187
188         if (defined $union->{PROPERTIES}) {
189                 HeaderProperties($union->{PROPERTIES}, []);
190         }
191 }
192
193 #####################################################################
194 # parse a type
195 sub HeaderType($$$)
196 {
197         my($e,$data,$name) = @_;
198         if (ref($data) eq "HASH") {
199                 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
200                 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
201                 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
202                 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
203                 return;
204         }
205
206         if (has_property($e, "charset")) {
207                 pidl "const char";
208         } else {
209                 pidl mapTypeName($e->{TYPE});
210         }
211 }
212
213 #####################################################################
214 # parse a typedef
215 sub HeaderTypedef($)
216 {
217         my($typedef) = shift;
218         HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
219 }
220
221 #####################################################################
222 # parse a const
223 sub HeaderConst($)
224 {
225         my($const) = shift;
226         if (!defined($const->{ARRAY_LEN}[0])) {
227                 pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
228         } else {
229                 pidl "#define $const->{NAME}\t $const->{VALUE}\n";
230         }
231 }
232
233 sub ElementDirection($)
234 {
235         my ($e) = @_;
236
237         return "inout" if (has_property($e, "in") and has_property($e, "out"));
238         return "in" if (has_property($e, "in"));
239         return "out" if (has_property($e, "out"));
240         return "inout";
241 }
242
243 #####################################################################
244 # parse a function
245 sub HeaderFunctionInOut($$)
246 {
247         my($fn,$prop) = @_;
248
249         return unless defined($fn->{ELEMENTS});
250
251         foreach my $e (@{$fn->{ELEMENTS}}) {
252                 HeaderElement($e) if (ElementDirection($e) eq $prop);
253         }
254 }
255
256 #####################################################################
257 # determine if we need an "in" or "out" section
258 sub HeaderFunctionInOut_needed($$)
259 {
260         my($fn,$prop) = @_;
261
262         return 1 if ($prop eq "out" && defined($fn->{RETURN_TYPE}));
263
264         return undef unless defined($fn->{ELEMENTS});
265
266         foreach my $e (@{$fn->{ELEMENTS}}) {
267                 return 1 if (ElementDirection($e) eq $prop);
268         }
269
270         return undef;
271 }
272
273 my %headerstructs;
274
275 #####################################################################
276 # parse a function
277 sub HeaderFunction($)
278 {
279         my($fn) = shift;
280
281         return if ($headerstructs{$fn->{NAME}});
282
283         $headerstructs{$fn->{NAME}} = 1;
284
285         pidl "\nstruct $fn->{NAME} {\n";
286         $tab_depth++;
287         my $needed = 0;
288
289         if (HeaderFunctionInOut_needed($fn, "in") or
290             HeaderFunctionInOut_needed($fn, "inout")) {
291                 pidl tabs()."struct {\n";
292                 $tab_depth++;
293                 HeaderFunctionInOut($fn, "in");
294                 HeaderFunctionInOut($fn, "inout");
295                 $tab_depth--;
296                 pidl tabs()."} in;\n\n";
297                 $needed++;
298         }
299
300         if (HeaderFunctionInOut_needed($fn, "out") or
301             HeaderFunctionInOut_needed($fn, "inout")) {
302                 pidl tabs()."struct {\n";
303                 $tab_depth++;
304                 HeaderFunctionInOut($fn, "out");
305                 HeaderFunctionInOut($fn, "inout");
306                 if (defined($fn->{RETURN_TYPE})) {
307                         pidl tabs().mapTypeName($fn->{RETURN_TYPE}) . " result;\n";
308                 }
309                 $tab_depth--;
310                 pidl tabs()."} out;\n\n";
311                 $needed++;
312         }
313
314         if (!$needed) {
315                 # sigh - some compilers don't like empty structures
316                 pidl tabs()."int _dummy_element;\n";
317         }
318
319         $tab_depth--;
320         pidl "};\n\n";
321 }
322
323 sub HeaderImport
324 {
325         my @imports = @_;
326         foreach (@imports) {
327                 s/\.idl\"$//;
328                 s/^\"//;
329                 pidl "#include \"librpc/gen_ndr/$_\.h\"\n";
330         }
331 }
332
333 sub HeaderInclude
334 {
335         my @includes = @_;
336         foreach (@includes) {
337                 pidl "#include $_\n";
338         }
339 }
340
341 #####################################################################
342 # parse the interface definitions
343 sub HeaderInterface($)
344 {
345         my($interface) = shift;
346
347         pidl "#ifndef _HEADER_$interface->{NAME}\n";
348         pidl "#define _HEADER_$interface->{NAME}\n\n";
349
350         foreach my $c (@{$interface->{CONSTS}}) {
351                 HeaderConst($c);
352         }
353
354         foreach my $t (@{$interface->{TYPES}}) {
355                 HeaderTypedef($t) if ($t->{TYPE} eq "TYPEDEF");
356                 HeaderStruct($t, $t->{NAME}) if ($t->{TYPE} eq "STRUCT");
357                 HeaderUnion($t, $t->{NAME}) if ($t->{TYPE} eq "UNION");
358                 HeaderEnum($t, $t->{NAME}) if ($t->{TYPE} eq "ENUM");
359                 HeaderBitmap($t, $t->{NAME}) if ($t->{TYPE} eq "BITMAP");
360                 pidl ";\n\n" if ($t->{TYPE} eq "BITMAP" or 
361                                  $t->{TYPE} eq "STRUCT" or 
362                                  $t->{TYPE} eq "TYPEDEF" or 
363                                  $t->{TYPE} eq "UNION" or 
364                                  $t->{TYPE} eq "ENUM");
365         }
366
367         foreach my $fn (@{$interface->{FUNCTIONS}}) {
368                 HeaderFunction($fn);
369         }
370
371         pidl "#endif /* _HEADER_$interface->{NAME} */\n";
372 }
373
374 sub HeaderQuote($)
375 {
376         my($quote) = shift;
377
378         pidl unmake_str($quote->{DATA}) . "\n";
379 }
380
381 #####################################################################
382 # parse a parsed IDL into a C header
383 sub Parse($)
384 {
385         my($ndr) = shift;
386         $tab_depth = 0;
387
388         $res = "";
389         %headerstructs = ();
390         pidl "/* header auto-generated by pidl */\n\n";
391         if (!is_intree()) {
392                 pidl "#include <util/data_blob.h>\n";
393         }
394         pidl "#include <stdint.h>\n";
395         pidl "\n";
396
397         foreach (@{$ndr}) {
398                 ($_->{TYPE} eq "CPP_QUOTE") && HeaderQuote($_);
399                 ($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
400                 ($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
401                 ($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
402         }
403
404         return $res;
405 }
406
407 1;