9e27719d5196c97270bc794c754ea20d80b5c21b
[ira/wip.git] / source / 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 choose_header);
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";
112         if (defined($enum->{ELEMENTS})) {
113                 pidl " {\n";
114                 $tab_depth++;
115                 foreach my $e (@{$enum->{ELEMENTS}}) {
116                         unless ($first) { pidl ",\n"; }
117                         $first = 0;
118                         pidl tabs();
119                         pidl $e;
120                 }
121                 pidl "\n";
122                 $tab_depth--;
123                 pidl "}";
124         }
125         pidl "\n";
126         pidl "#else\n";
127         my $count = 0;
128         pidl "enum $name";
129         my $with_val = 0;
130         my $without_val = 0;
131         if (defined($enum->{ELEMENTS})) {
132                 pidl " { __donnot_use_enum_$name=0x7FFFFFFF}";
133                 foreach my $e (@{$enum->{ELEMENTS}}) {
134                         my $t = "$e";
135                         my $name;
136                         my $value;
137                         if ($t =~ /(.*)=(.*)/) {
138                                 $name = $1;
139                                 $value = $2;
140                                 $with_val = 1;
141                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
142                                         unless ($without_val == 0);
143                         } else {
144                                 $name = $t;
145                                 $value = $count++;
146                                 $without_val = 1;
147                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
148                                         unless ($with_val == 0);
149                         }
150                         pidl "\n#define $name ( $value )";
151                 }
152         }
153         pidl "\n";
154         pidl "#endif\n";
155 }
156
157 #####################################################################
158 # parse a bitmap
159 sub HeaderBitmap($$)
160 {
161         my($bitmap,$name) = @_;
162
163         return unless defined($bitmap->{ELEMENTS});
164
165         pidl "/* bitmap $name */\n";
166         pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
167         pidl "\n";
168 }
169
170 #####################################################################
171 # parse a union
172 sub HeaderUnion($$)
173 {
174         my($union,$name) = @_;
175         my %done = ();
176
177         pidl "union $name";
178         return if (not defined($union->{ELEMENTS}));
179         pidl " {\n";
180         $tab_depth++;
181         foreach my $e (@{$union->{ELEMENTS}}) {
182                 if ($e->{TYPE} ne "EMPTY") {
183                         if (! defined $done{$e->{NAME}}) {
184                                 HeaderElement($e);
185                         }
186                         $done{$e->{NAME}} = 1;
187                 }
188         }
189         $tab_depth--;
190         pidl "}";
191
192         if (defined $union->{PROPERTIES}) {
193                 HeaderProperties($union->{PROPERTIES}, []);
194         }
195 }
196
197 #####################################################################
198 # parse a type
199 sub HeaderType($$$)
200 {
201         my($e,$data,$name) = @_;
202         if (ref($data) eq "HASH") {
203                 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
204                 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
205                 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
206                 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
207                 return;
208         }
209
210         if (has_property($e, "charset")) {
211                 pidl "const char";
212         } else {
213                 pidl mapTypeName($e->{TYPE});
214         }
215 }
216
217 #####################################################################
218 # parse a typedef
219 sub HeaderTypedef($)
220 {
221         my($typedef) = shift;
222         HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME}) if defined ($typedef->{DATA});
223 }
224
225 #####################################################################
226 # parse a const
227 sub HeaderConst($)
228 {
229         my($const) = shift;
230         if (!defined($const->{ARRAY_LEN}[0])) {
231                 pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
232         } else {
233                 pidl "#define $const->{NAME}\t $const->{VALUE}\n";
234         }
235 }
236
237 sub ElementDirection($)
238 {
239         my ($e) = @_;
240
241         return "inout" if (has_property($e, "in") and has_property($e, "out"));
242         return "in" if (has_property($e, "in"));
243         return "out" if (has_property($e, "out"));
244         return "inout";
245 }
246
247 #####################################################################
248 # parse a function
249 sub HeaderFunctionInOut($$)
250 {
251         my($fn,$prop) = @_;
252
253         return unless defined($fn->{ELEMENTS});
254
255         foreach my $e (@{$fn->{ELEMENTS}}) {
256                 HeaderElement($e) if (ElementDirection($e) eq $prop);
257         }
258 }
259
260 #####################################################################
261 # determine if we need an "in" or "out" section
262 sub HeaderFunctionInOut_needed($$)
263 {
264         my($fn,$prop) = @_;
265
266         return 1 if ($prop eq "out" && defined($fn->{RETURN_TYPE}));
267
268         return undef unless defined($fn->{ELEMENTS});
269
270         foreach my $e (@{$fn->{ELEMENTS}}) {
271                 return 1 if (ElementDirection($e) eq $prop);
272         }
273
274         return undef;
275 }
276
277 my %headerstructs;
278
279 #####################################################################
280 # parse a function
281 sub HeaderFunction($)
282 {
283         my($fn) = shift;
284
285         return if ($headerstructs{$fn->{NAME}});
286
287         $headerstructs{$fn->{NAME}} = 1;
288
289         pidl "\nstruct $fn->{NAME} {\n";
290         $tab_depth++;
291         my $needed = 0;
292
293         if (HeaderFunctionInOut_needed($fn, "in") or
294             HeaderFunctionInOut_needed($fn, "inout")) {
295                 pidl tabs()."struct {\n";
296                 $tab_depth++;
297                 HeaderFunctionInOut($fn, "in");
298                 HeaderFunctionInOut($fn, "inout");
299                 $tab_depth--;
300                 pidl tabs()."} in;\n\n";
301                 $needed++;
302         }
303
304         if (HeaderFunctionInOut_needed($fn, "out") or
305             HeaderFunctionInOut_needed($fn, "inout")) {
306                 pidl tabs()."struct {\n";
307                 $tab_depth++;
308                 HeaderFunctionInOut($fn, "out");
309                 HeaderFunctionInOut($fn, "inout");
310                 if (defined($fn->{RETURN_TYPE})) {
311                         pidl tabs().mapTypeName($fn->{RETURN_TYPE}) . " result;\n";
312                 }
313                 $tab_depth--;
314                 pidl tabs()."} out;\n\n";
315                 $needed++;
316         }
317
318         if (!$needed) {
319                 # sigh - some compilers don't like empty structures
320                 pidl tabs()."int _dummy_element;\n";
321         }
322
323         $tab_depth--;
324         pidl "};\n\n";
325 }
326
327 sub HeaderImport
328 {
329         my @imports = @_;
330         foreach (@imports) {
331                 s/\.idl\"$//;
332                 s/^\"//;
333                 pidl choose_header("librpc/gen_ndr/$_\.h", "gen_ndr/$_.h") . "\n";
334         }
335 }
336
337 sub HeaderInclude
338 {
339         my @includes = @_;
340         foreach (@includes) {
341                 pidl "#include $_\n";
342         }
343 }
344
345 #####################################################################
346 # parse the interface definitions
347 sub HeaderInterface($)
348 {
349         my($interface) = shift;
350
351         pidl "#ifndef _HEADER_$interface->{NAME}\n";
352         pidl "#define _HEADER_$interface->{NAME}\n\n";
353
354         foreach my $c (@{$interface->{CONSTS}}) {
355                 HeaderConst($c);
356         }
357
358         foreach my $t (@{$interface->{TYPES}}) {
359                 HeaderTypedef($t) if ($t->{TYPE} eq "TYPEDEF");
360                 HeaderStruct($t, $t->{NAME}) if ($t->{TYPE} eq "STRUCT");
361                 HeaderUnion($t, $t->{NAME}) if ($t->{TYPE} eq "UNION");
362                 HeaderEnum($t, $t->{NAME}) if ($t->{TYPE} eq "ENUM");
363                 HeaderBitmap($t, $t->{NAME}) if ($t->{TYPE} eq "BITMAP");
364                 pidl ";\n\n" if ($t->{TYPE} eq "BITMAP" or 
365                                  $t->{TYPE} eq "STRUCT" or 
366                                  $t->{TYPE} eq "TYPEDEF" or 
367                                  $t->{TYPE} eq "UNION" or 
368                                  $t->{TYPE} eq "ENUM");
369         }
370
371         foreach my $fn (@{$interface->{FUNCTIONS}}) {
372                 HeaderFunction($fn);
373         }
374
375         pidl "#endif /* _HEADER_$interface->{NAME} */\n";
376 }
377
378 sub HeaderQuote($)
379 {
380         my($quote) = shift;
381
382         pidl unmake_str($quote->{DATA}) . "\n";
383 }
384
385 #####################################################################
386 # parse a parsed IDL into a C header
387 sub Parse($)
388 {
389         my($ndr) = shift;
390         $tab_depth = 0;
391
392         $res = "";
393         %headerstructs = ();
394         pidl "/* header auto-generated by pidl */\n\n";
395         if (!is_intree()) {
396                 pidl "#include <util/data_blob.h>\n";
397         }
398         pidl "#include <stdint.h>\n";
399         pidl "\n";
400
401         foreach (@{$ndr}) {
402                 ($_->{TYPE} eq "CPP_QUOTE") && HeaderQuote($_);
403                 ($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
404                 ($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
405                 ($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
406         }
407
408         return $res;
409 }
410
411 1;