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