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