Fix check.
[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 require Exporter;
10
11 @ISA = qw(Exporter);
12 @EXPORT_OK = qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
13
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);
19
20 use vars qw($VERSION);
21 $VERSION = '0.01';
22
23 my($res);
24 my($tab_depth);
25
26 sub pidl($) { $res .= shift; }
27
28 sub tabs()
29 {
30         my $res = "";
31         $res .="\t" foreach (1..$tab_depth);
32         return $res;
33 }
34
35 #####################################################################
36 # parse a properties list
37 sub HeaderProperties($$)
38 {
39         my($props,$ignores) = @_;
40         my $ret = "";
41
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,";
48                 }
49         }
50
51         if ($ret) {
52                 pidl "/* [" . substr($ret, 0, -1) . "] */";
53         }
54 }
55
56 #####################################################################
57 # parse a structure element
58 sub HeaderElement($)
59 {
60         my($element) = shift;
61
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}, "");
70                 }
71                 pidl " ".ElementStars($element);
72         }
73         pidl $element->{NAME};
74         pidl ArrayBrackets($element);
75
76         pidl ";";
77         if (defined $element->{PROPERTIES}) {
78                 HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
79         }
80         pidl "\n";
81 }
82
83 #####################################################################
84 # parse a struct
85 sub HeaderStruct($$;$)
86 {
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++;
97         }
98         if ($el_count == 0) {
99                 # some compilers can't handle empty structures
100                 pidl tabs()."char _empty_;\n";
101         }
102         $tab_depth--;
103         pidl tabs()."}";
104         if (defined $struct->{PROPERTIES}) {
105                 HeaderProperties($struct->{PROPERTIES}, []);
106         }
107         pidl $tail if defined($tail);
108 }
109
110 #####################################################################
111 # parse a enum
112 sub HeaderEnum($$;$)
113 {
114         my($enum,$name,$tail) = @_;
115         my $first = 1;
116
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                         unless ($first) { pidl ",\n"; }
124                         $first = 0;
125                         pidl tabs();
126                         pidl $e;
127                 }
128                 pidl "\n";
129                 $tab_depth--;
130                 pidl "}";
131                 pidl "\n";
132                 pidl "#else\n";
133                 my $count = 0;
134                 my $with_val = 0;
135                 my $without_val = 0;
136                 pidl " { __donnot_use_enum_$name=0x7FFFFFFF}\n";
137                 foreach my $e (@{$enum->{ELEMENTS}}) {
138                         my $t = "$e";
139                         my $name;
140                         my $value;
141                         if ($t =~ /(.*)=(.*)/) {
142                                 $name = $1;
143                                 $value = $2;
144                                 $with_val = 1;
145                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
146                                         unless ($without_val == 0);
147                         } else {
148                                 $name = $t;
149                                 $value = $count++;
150                                 $without_val = 1;
151                                 fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
152                                         unless ($with_val == 0);
153                         }
154                         pidl "#define $name ( $value )\n";
155                 }
156                 pidl "#endif\n";
157         }
158         pidl $tail if defined($tail);
159 }
160
161 #####################################################################
162 # parse a bitmap
163 sub HeaderBitmap($$)
164 {
165         my($bitmap,$name) = @_;
166
167         return unless defined($bitmap->{ELEMENTS});
168
169         pidl "/* bitmap $name */\n";
170         pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
171         pidl "\n";
172 }
173
174 #####################################################################
175 # parse a union
176 sub HeaderUnion($$;$)
177 {
178         my($union,$name,$tail) = @_;
179         my %done = ();
180
181         pidl "union $name";
182         pidl $tail if defined($tail) and not defined($union->{ELEMENTS});
183         return if (not defined($union->{ELEMENTS}));
184         pidl " {\n";
185         $tab_depth++;
186         foreach my $e (@{$union->{ELEMENTS}}) {
187                 if ($e->{TYPE} ne "EMPTY") {
188                         if (! defined $done{$e->{NAME}}) {
189                                 HeaderElement($e);
190                         }
191                         $done{$e->{NAME}} = 1;
192                 }
193         }
194         $tab_depth--;
195         pidl "}";
196
197         if (defined $union->{PROPERTIES}) {
198                 HeaderProperties($union->{PROPERTIES}, []);
199         }
200         pidl $tail if defined($tail);
201 }
202
203 #####################################################################
204 # parse a type
205 sub HeaderType($$$;$)
206 {
207         my($e,$data,$name,$tail) = @_;
208         if (ref($data) eq "HASH") {
209                 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name, $tail);
210                 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
211                 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name, $tail);
212                 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name, $tail);
213                 return;
214         }
215
216         if (has_property($e, "charset")) {
217                 pidl "const char";
218         } else {
219                 pidl mapTypeName($e->{TYPE});
220         }
221         pidl $tail if defined($tail);
222 }
223
224 #####################################################################
225 # parse a typedef
226 sub HeaderTypedef($;$)
227 {
228         my($typedef,$tail) = @_;
229         HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME}, $tail) if defined ($typedef->{DATA});
230 }
231
232 #####################################################################
233 # parse a const
234 sub HeaderConst($)
235 {
236         my($const) = shift;
237         if (!defined($const->{ARRAY_LEN}[0])) {
238                 pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
239         } else {
240                 pidl "#define $const->{NAME}\t $const->{VALUE}\n";
241         }
242 }
243
244 sub ElementDirection($)
245 {
246         my ($e) = @_;
247
248         return "inout" if (has_property($e, "in") and has_property($e, "out"));
249         return "in" if (has_property($e, "in"));
250         return "out" if (has_property($e, "out"));
251         return "inout";
252 }
253
254 #####################################################################
255 # parse a function
256 sub HeaderFunctionInOut($$)
257 {
258         my($fn,$prop) = @_;
259
260         return unless defined($fn->{ELEMENTS});
261
262         foreach my $e (@{$fn->{ELEMENTS}}) {
263                 HeaderElement($e) if (ElementDirection($e) eq $prop);
264         }
265 }
266
267 #####################################################################
268 # determine if we need an "in" or "out" section
269 sub HeaderFunctionInOut_needed($$)
270 {
271         my($fn,$prop) = @_;
272
273         return 1 if ($prop eq "out" && defined($fn->{RETURN_TYPE}));
274
275         return undef unless defined($fn->{ELEMENTS});
276
277         foreach my $e (@{$fn->{ELEMENTS}}) {
278                 return 1 if (ElementDirection($e) eq $prop);
279         }
280
281         return undef;
282 }
283
284 my %headerstructs;
285
286 #####################################################################
287 # parse a function
288 sub HeaderFunction($)
289 {
290         my($fn) = shift;
291
292         return if ($headerstructs{$fn->{NAME}});
293
294         $headerstructs{$fn->{NAME}} = 1;
295
296         pidl "\nstruct $fn->{NAME} {\n";
297         $tab_depth++;
298         my $needed = 0;
299
300         if (HeaderFunctionInOut_needed($fn, "in") or
301             HeaderFunctionInOut_needed($fn, "inout")) {
302                 pidl tabs()."struct {\n";
303                 $tab_depth++;
304                 HeaderFunctionInOut($fn, "in");
305                 HeaderFunctionInOut($fn, "inout");
306                 $tab_depth--;
307                 pidl tabs()."} in;\n\n";
308                 $needed++;
309         }
310
311         if (HeaderFunctionInOut_needed($fn, "out") or
312             HeaderFunctionInOut_needed($fn, "inout")) {
313                 pidl tabs()."struct {\n";
314                 $tab_depth++;
315                 HeaderFunctionInOut($fn, "out");
316                 HeaderFunctionInOut($fn, "inout");
317                 if (defined($fn->{RETURN_TYPE})) {
318                         pidl tabs().mapTypeName($fn->{RETURN_TYPE}) . " result;\n";
319                 }
320                 $tab_depth--;
321                 pidl tabs()."} out;\n\n";
322                 $needed++;
323         }
324
325         if (!$needed) {
326                 # sigh - some compilers don't like empty structures
327                 pidl tabs()."int _dummy_element;\n";
328         }
329
330         $tab_depth--;
331         pidl "};\n\n";
332 }
333
334 sub HeaderImport
335 {
336         my @imports = @_;
337         foreach my $import (@imports) {
338                 $import = unmake_str($import);
339                 $import =~ s/\.idl$//;
340                 pidl choose_header("librpc/gen_ndr/$import\.h", "gen_ndr/$import.h") . "\n";
341         }
342 }
343
344 sub HeaderInclude
345 {
346         my @includes = @_;
347         foreach (@includes) {
348                 pidl "#include $_\n";
349         }
350 }
351
352 #####################################################################
353 # parse the interface definitions
354 sub HeaderInterface($)
355 {
356         my($interface) = shift;
357
358         pidl "#ifndef _HEADER_$interface->{NAME}\n";
359         pidl "#define _HEADER_$interface->{NAME}\n\n";
360
361         foreach my $c (@{$interface->{CONSTS}}) {
362                 HeaderConst($c);
363         }
364
365         foreach my $t (@{$interface->{TYPES}}) {
366                 HeaderTypedef($t, ";\n\n") if ($t->{TYPE} eq "TYPEDEF");
367                 HeaderStruct($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "STRUCT");
368                 HeaderUnion($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "UNION");
369                 HeaderEnum($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "ENUM");
370                 HeaderBitmap($t, $t->{NAME}) if ($t->{TYPE} eq "BITMAP");
371         }
372
373         foreach my $fn (@{$interface->{FUNCTIONS}}) {
374                 HeaderFunction($fn);
375         }
376
377         pidl "#endif /* _HEADER_$interface->{NAME} */\n";
378 }
379
380 sub HeaderQuote($)
381 {
382         my($quote) = shift;
383
384         pidl unmake_str($quote->{DATA}) . "\n";
385 }
386
387 #####################################################################
388 # parse a parsed IDL into a C header
389 sub Parse($)
390 {
391         my($ndr) = shift;
392         $tab_depth = 0;
393
394         $res = "";
395         %headerstructs = ();
396         pidl "/* header auto-generated by pidl */\n\n";
397         if (!is_intree()) {
398                 pidl "#include <util/data_blob.h>\n";
399         }
400         pidl "#include <stdint.h>\n";
401         pidl "\n";
402
403         foreach (@{$ndr}) {
404                 ($_->{TYPE} eq "CPP_QUOTE") && HeaderQuote($_);
405                 ($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
406                 ($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
407                 ($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
408         }
409
410         return $res;
411 }
412
413 sub GenerateStructEnv($$)
414 {
415         my ($x, $v) = @_;
416         my %env;
417
418         foreach my $e (@{$x->{ELEMENTS}}) {
419                 $env{$e->{NAME}} = "$v->$e->{NAME}";
420         }
421
422         $env{"this"} = $v;
423
424         return \%env;
425 }
426
427 sub EnvSubstituteValue($$)
428 {
429         my ($env,$s) = @_;
430
431         # Substitute the value() values in the env
432         foreach my $e (@{$s->{ELEMENTS}}) {
433                 next unless (defined(my $v = has_property($e, "value")));
434                 
435                 $env->{$e->{NAME}} = ParseExpr($v, $env, $e);
436         }
437
438         return $env;
439 }
440
441 sub GenerateFunctionInEnv($;$)
442 {
443         my ($fn, $base) = @_;
444         my %env;
445
446         $base = "r->" unless defined($base);
447
448         foreach my $e (@{$fn->{ELEMENTS}}) {
449                 if (grep (/in/, @{$e->{DIRECTION}})) {
450                         $env{$e->{NAME}} = $base."in.$e->{NAME}";
451                 }
452         }
453
454         return \%env;
455 }
456
457 sub GenerateFunctionOutEnv($;$)
458 {
459         my ($fn, $base) = @_;
460         my %env;
461
462         $base = "r->" unless defined($base);
463
464         foreach my $e (@{$fn->{ELEMENTS}}) {
465                 if (grep (/out/, @{$e->{DIRECTION}})) {
466                         $env{$e->{NAME}} = $base."out.$e->{NAME}";
467                 } elsif (grep (/in/, @{$e->{DIRECTION}})) {
468                         $env{$e->{NAME}} = $base."in.$e->{NAME}";
469                 }
470         }
471
472         return \%env;
473 }
474
475 1;