Fix the problem with pidl generating invalid C for enums. According
[Samba/aatanasov.git] / pidl / lib / Parse / Pidl / Samba4 / Header.pm
blobbb497bb3a77471e331bdf91128efec86b26bae3e
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
7 package Parse::Pidl::Samba4::Header;
9 require Exporter;
11 @ISA = qw(Exporter);
12 @EXPORT_OK = qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
14 use strict;
15 use Parse::Pidl qw(fatal);
16 use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
17 use Parse::Pidl::Util qw(has_property is_constant unmake_str ParseExpr);
18 use Parse::Pidl::Samba4 qw(is_intree ElementStars ArrayBrackets choose_header);
20 use vars qw($VERSION);
21 $VERSION = '0.01';
23 my($res);
24 my($tab_depth);
26 sub pidl($) { $res .= shift; }
28 sub tabs()
30 my $res = "";
31 $res .="\t" foreach (1..$tab_depth);
32 return $res;
35 #####################################################################
36 # parse a properties list
37 sub HeaderProperties($$)
39 my($props,$ignores) = @_;
40 my $ret = "";
42 foreach my $d (keys %{$props}) {
43 next if (grep(/^$d$/, @$ignores));
44 if($props->{$d} ne "1") {
45 $ret.= "$d($props->{$d}),";
46 } else {
47 $ret.="$d,";
51 if ($ret) {
52 pidl "/* [" . substr($ret, 0, -1) . "] */";
56 #####################################################################
57 # parse a structure element
58 sub HeaderElement($)
60 my($element) = shift;
62 pidl tabs();
63 if (has_property($element, "represent_as")) {
64 pidl mapTypeName($element->{PROPERTIES}->{represent_as})." ";
65 } else {
66 if (ref($element->{TYPE}) eq "HASH") {
67 HeaderType($element, $element->{TYPE}, $element->{TYPE}->{NAME});
68 } else {
69 HeaderType($element, $element->{TYPE}, "");
71 pidl " ".ElementStars($element);
73 pidl $element->{NAME};
74 pidl ArrayBrackets($element);
76 pidl ";";
77 if (defined $element->{PROPERTIES}) {
78 HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
80 pidl "\n";
83 #####################################################################
84 # parse a struct
85 sub HeaderStruct($$;$)
87 my($struct,$name,$tail) = @_;
88 pidl "struct $name";
89 pidl $tail if defined($tail) and not defined($struct->{ELEMENTS});
90 return if (not defined($struct->{ELEMENTS}));
91 pidl " {\n";
92 $tab_depth++;
93 my $el_count=0;
94 foreach (@{$struct->{ELEMENTS}}) {
95 HeaderElement($_);
96 $el_count++;
98 if ($el_count == 0) {
99 # some compilers can't handle empty structures
100 pidl tabs()."char _empty_;\n";
102 $tab_depth--;
103 pidl tabs()."}";
104 if (defined $struct->{PROPERTIES}) {
105 HeaderProperties($struct->{PROPERTIES}, []);
107 pidl $tail if defined($tail);
110 #####################################################################
111 # parse a enum
112 sub HeaderEnum($$;$)
114 my($enum,$name,$tail) = @_;
115 my $first = 1;
117 pidl "enum $name";
118 if (defined($enum->{ELEMENTS})) {
119 pidl "\n#ifndef USE_UINT_ENUMS\n";
120 pidl " {\n";
121 $tab_depth++;
122 foreach my $e (@{$enum->{ELEMENTS}}) {
123 my @enum_els = ();
124 unless ($first) { pidl ",\n"; }
125 $first = 0;
126 pidl tabs();
127 @enum_els = split(/=/, $e);
128 if (@enum_els == 2) {
129 pidl $enum_els[0];
130 pidl "=(int)";
131 pidl $enum_els[1];
132 } else {
133 pidl $e;
136 pidl "\n";
137 $tab_depth--;
138 pidl "}";
139 pidl "\n";
140 pidl "#else\n";
141 my $count = 0;
142 my $with_val = 0;
143 my $without_val = 0;
144 pidl " { __donnot_use_enum_$name=0x7FFFFFFF}\n";
145 foreach my $e (@{$enum->{ELEMENTS}}) {
146 my $t = "$e";
147 my $name;
148 my $value;
149 if ($t =~ /(.*)=(.*)/) {
150 $name = $1;
151 $value = $2;
152 $with_val = 1;
153 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
154 unless ($without_val == 0);
155 } else {
156 $name = $t;
157 $value = $count++;
158 $without_val = 1;
159 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
160 unless ($with_val == 0);
162 pidl "#define $name ( $value )\n";
164 pidl "#endif\n";
166 pidl $tail if defined($tail);
169 #####################################################################
170 # parse a bitmap
171 sub HeaderBitmap($$)
173 my($bitmap,$name) = @_;
175 return unless defined($bitmap->{ELEMENTS});
177 pidl "/* bitmap $name */\n";
178 pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
179 pidl "\n";
182 #####################################################################
183 # parse a union
184 sub HeaderUnion($$;$)
186 my($union,$name,$tail) = @_;
187 my %done = ();
189 pidl "union $name";
190 pidl $tail if defined($tail) and not defined($union->{ELEMENTS});
191 return if (not defined($union->{ELEMENTS}));
192 pidl " {\n";
193 $tab_depth++;
194 my $needed = 0;
195 foreach my $e (@{$union->{ELEMENTS}}) {
196 if ($e->{TYPE} ne "EMPTY") {
197 if (! defined $done{$e->{NAME}}) {
198 HeaderElement($e);
200 $done{$e->{NAME}} = 1;
201 $needed++;
204 if (!$needed) {
205 # sigh - some compilers don't like empty structures
206 pidl tabs()."int _dummy_element;\n";
208 $tab_depth--;
209 pidl "}";
211 if (defined $union->{PROPERTIES}) {
212 HeaderProperties($union->{PROPERTIES}, []);
214 pidl $tail if defined($tail);
217 #####################################################################
218 # parse a type
219 sub HeaderType($$$;$)
221 my($e,$data,$name,$tail) = @_;
222 if (ref($data) eq "HASH") {
223 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name, $tail);
224 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
225 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name, $tail);
226 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name, $tail);
227 return;
230 if (has_property($e, "charset")) {
231 pidl "const char";
232 } else {
233 pidl mapTypeName($e->{TYPE});
235 pidl $tail if defined($tail);
238 #####################################################################
239 # parse a typedef
240 sub HeaderTypedef($;$)
242 my($typedef,$tail) = @_;
243 # Don't print empty "enum foo;", since some compilers don't like it.
244 return if ($typedef->{DATA}->{TYPE} eq "ENUM" and not defined($typedef->{DATA}->{ELEMENTS}));
245 HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME}, $tail) if defined ($typedef->{DATA});
248 #####################################################################
249 # parse a const
250 sub HeaderConst($)
252 my($const) = shift;
253 if (!defined($const->{ARRAY_LEN}[0])) {
254 pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
255 } else {
256 pidl "#define $const->{NAME}\t $const->{VALUE}\n";
260 sub ElementDirection($)
262 my ($e) = @_;
264 return "inout" if (has_property($e, "in") and has_property($e, "out"));
265 return "in" if (has_property($e, "in"));
266 return "out" if (has_property($e, "out"));
267 return "inout";
270 #####################################################################
271 # parse a function
272 sub HeaderFunctionInOut($$)
274 my($fn,$prop) = @_;
276 return unless defined($fn->{ELEMENTS});
278 foreach my $e (@{$fn->{ELEMENTS}}) {
279 HeaderElement($e) if (ElementDirection($e) eq $prop);
283 #####################################################################
284 # determine if we need an "in" or "out" section
285 sub HeaderFunctionInOut_needed($$)
287 my($fn,$prop) = @_;
289 return 1 if ($prop eq "out" && defined($fn->{RETURN_TYPE}));
291 return undef unless defined($fn->{ELEMENTS});
293 foreach my $e (@{$fn->{ELEMENTS}}) {
294 return 1 if (ElementDirection($e) eq $prop);
297 return undef;
300 my %headerstructs;
302 #####################################################################
303 # parse a function
304 sub HeaderFunction($)
306 my($fn) = shift;
308 return if ($headerstructs{$fn->{NAME}});
310 $headerstructs{$fn->{NAME}} = 1;
312 pidl "\nstruct $fn->{NAME} {\n";
313 $tab_depth++;
314 my $needed = 0;
316 if (HeaderFunctionInOut_needed($fn, "in") or
317 HeaderFunctionInOut_needed($fn, "inout")) {
318 pidl tabs()."struct {\n";
319 $tab_depth++;
320 HeaderFunctionInOut($fn, "in");
321 HeaderFunctionInOut($fn, "inout");
322 $tab_depth--;
323 pidl tabs()."} in;\n\n";
324 $needed++;
327 if (HeaderFunctionInOut_needed($fn, "out") or
328 HeaderFunctionInOut_needed($fn, "inout")) {
329 pidl tabs()."struct {\n";
330 $tab_depth++;
331 HeaderFunctionInOut($fn, "out");
332 HeaderFunctionInOut($fn, "inout");
333 if (defined($fn->{RETURN_TYPE})) {
334 pidl tabs().mapTypeName($fn->{RETURN_TYPE}) . " result;\n";
336 $tab_depth--;
337 pidl tabs()."} out;\n\n";
338 $needed++;
341 if (!$needed) {
342 # sigh - some compilers don't like empty structures
343 pidl tabs()."int _dummy_element;\n";
346 $tab_depth--;
347 pidl "};\n\n";
350 sub HeaderImport
352 my @imports = @_;
353 foreach my $import (@imports) {
354 $import = unmake_str($import);
355 $import =~ s/\.idl$//;
356 pidl choose_header("librpc/gen_ndr/$import\.h", "gen_ndr/$import.h") . "\n";
360 sub HeaderInclude
362 my @includes = @_;
363 foreach (@includes) {
364 pidl "#include $_\n";
368 #####################################################################
369 # parse the interface definitions
370 sub HeaderInterface($)
372 my($interface) = shift;
374 pidl "#ifndef _HEADER_$interface->{NAME}\n";
375 pidl "#define _HEADER_$interface->{NAME}\n\n";
377 foreach my $c (@{$interface->{CONSTS}}) {
378 HeaderConst($c);
381 foreach my $t (@{$interface->{TYPES}}) {
382 HeaderTypedef($t, ";\n\n") if ($t->{TYPE} eq "TYPEDEF");
383 HeaderStruct($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "STRUCT");
384 HeaderUnion($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "UNION");
385 HeaderEnum($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "ENUM");
386 HeaderBitmap($t, $t->{NAME}) if ($t->{TYPE} eq "BITMAP");
389 foreach my $fn (@{$interface->{FUNCTIONS}}) {
390 HeaderFunction($fn);
393 pidl "#endif /* _HEADER_$interface->{NAME} */\n";
396 sub HeaderQuote($)
398 my($quote) = shift;
400 pidl unmake_str($quote->{DATA}) . "\n";
403 #####################################################################
404 # parse a parsed IDL into a C header
405 sub Parse($)
407 my($ndr) = shift;
408 $tab_depth = 0;
410 $res = "";
411 %headerstructs = ();
412 pidl "/* header auto-generated by pidl */\n\n";
413 if (!is_intree()) {
414 pidl "#include <util/data_blob.h>\n";
416 pidl "#include <stdint.h>\n";
417 pidl "\n";
418 # FIXME: Include this only if NTSTATUS was actually used
419 pidl choose_header("libcli/util/ntstatus.h", "core/ntstatus.h") . "\n";
420 pidl "\n";
422 foreach (@{$ndr}) {
423 ($_->{TYPE} eq "CPP_QUOTE") && HeaderQuote($_);
424 ($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
425 ($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
426 ($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
429 return $res;
432 sub GenerateStructEnv($$)
434 my ($x, $v) = @_;
435 my %env;
437 foreach my $e (@{$x->{ELEMENTS}}) {
438 $env{$e->{NAME}} = "$v->$e->{NAME}";
441 $env{"this"} = $v;
443 return \%env;
446 sub EnvSubstituteValue($$)
448 my ($env,$s) = @_;
450 # Substitute the value() values in the env
451 foreach my $e (@{$s->{ELEMENTS}}) {
452 next unless (defined(my $v = has_property($e, "value")));
454 $env->{$e->{NAME}} = ParseExpr($v, $env, $e);
457 return $env;
460 sub GenerateFunctionInEnv($;$)
462 my ($fn, $base) = @_;
463 my %env;
465 $base = "r->" unless defined($base);
467 foreach my $e (@{$fn->{ELEMENTS}}) {
468 if (grep (/in/, @{$e->{DIRECTION}})) {
469 $env{$e->{NAME}} = $base."in.$e->{NAME}";
473 return \%env;
476 sub GenerateFunctionOutEnv($;$)
478 my ($fn, $base) = @_;
479 my %env;
481 $base = "r->" unless defined($base);
483 foreach my $e (@{$fn->{ELEMENTS}}) {
484 if (grep (/out/, @{$e->{DIRECTION}})) {
485 $env{$e->{NAME}} = $base."out.$e->{NAME}";
486 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
487 $env{$e->{NAME}} = $base."in.$e->{NAME}";
491 return \%env;