r9460: - Move pidl to lib/. This fixes standalone installation of pidl.
[samba.git] / source4 / pidl / lib / Parse / Pidl / Samba / 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::Samba::Header;
8
9 use strict;
10 use Parse::Pidl::Typelist qw(mapType);
11 use Parse::Pidl::Util qw(has_property is_constant);
12 use Parse::Pidl::NDR qw(GetNextLevel GetPrevLevel);
13
14 my($res);
15 my($tab_depth);
16
17 sub pidl ($)
18 {
19         $res .= shift;
20 }
21
22 sub tabs()
23 {
24         my $res = "";
25         $res .="\t" foreach (1..$tab_depth);
26         return $res;
27 }
28
29 #####################################################################
30 # parse a properties list
31 sub HeaderProperties($$)
32 {
33     my($props,$ignores) = @_;
34         my $ret = "";
35
36     foreach my $d (keys %{$props}) {
37                 next if (grep(/^$d$/, @$ignores));
38                 if($props->{$d} ne "1") {
39                         $ret.= "$d($props->{$d}),";
40                 } else {
41                         $ret.="$d,";
42                 }
43         }
44
45         if ($ret) {
46                 pidl "/* [" . substr($ret, 0, -1) . "] */";
47         }
48 }
49
50 #####################################################################
51 # parse a structure element
52 sub HeaderElement($)
53 {
54         my($element) = shift;
55
56         pidl tabs();
57         HeaderType($element, $element->{TYPE}, "");
58         pidl " ";
59         my $numstar = $element->{POINTERS};
60         foreach (@{$element->{ARRAY_LEN}})
61         {
62                 next if is_constant($_) and 
63                         not has_property($element, "charset");
64                 $numstar++;
65         }
66         $numstar-- if Parse::Pidl::Typelist::scalar_is_reference($element->{TYPE});
67         pidl "*" foreach (1..$numstar);
68         pidl $element->{NAME};
69         foreach (@{$element->{ARRAY_LEN}}) {
70                 next unless (is_constant($_) and 
71                         not has_property($element, "charset"));
72                 pidl "[$_]";
73         }
74
75         pidl ";";
76         if (defined $element->{PROPERTIES}) {
77                 HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
78         }
79         pidl "\n";
80 }
81
82 #####################################################################
83 # parse a struct
84 sub HeaderStruct($$)
85 {
86     my($struct,$name) = @_;
87         pidl "struct $name {\n";
88     $tab_depth++;
89     my $el_count=0;
90     if (defined $struct->{ELEMENTS}) {
91                 foreach my $e (@{$struct->{ELEMENTS}}) {
92                     HeaderElement($e);
93                     $el_count++;
94                 }
95     }
96     if ($el_count == 0) {
97             # some compilers can't handle empty structures
98             pidl tabs()."char _empty_;\n";
99     }
100     $tab_depth--;
101     pidl tabs()."}";
102         if (defined $struct->{PROPERTIES}) {
103                 HeaderProperties($struct->{PROPERTIES}, []);
104         }
105 }
106
107 #####################################################################
108 # parse a enum
109 sub HeaderEnum($$)
110 {
111     my($enum,$name) = @_;
112     my $first = 1;
113
114     if (not Parse::Pidl::Util::useUintEnums()) {
115         pidl "enum $name {\n";
116         $tab_depth++;
117         foreach my $e (@{$enum->{ELEMENTS}}) {
118             unless ($first) { pidl ",\n"; }
119             $first = 0;
120             pidl tabs();
121             pidl $e;
122         }
123         pidl "\n";
124         $tab_depth--;
125         pidl "}";
126     } else {
127         my $count = 0;
128         pidl "enum $name { __donnot_use_enum_$name=0x7FFFFFFF};\n";
129         my $with_val = 0;
130         my $without_val = 0;
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                 die ("you can't mix enum member with values and without values when using --uint-enums!")
140                         unless ($without_val == 0);
141             } else {
142                 $name = $t;
143                 $value = $count++;
144                 $without_val = 1;
145                 die ("you can't mix enum member with values and without values when using --uint-enums!")
146                         unless ($with_val == 0);
147             }
148             pidl "#define $name ( $value )\n";
149         }
150         pidl "\n";
151     }
152 }
153
154 #####################################################################
155 # parse a bitmap
156 sub HeaderBitmap($$)
157 {
158     my($bitmap,$name) = @_;
159
160     pidl "/* bitmap $name */\n";
161     pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
162     pidl "\n";
163 }
164
165 #####################################################################
166 # parse a union
167 sub HeaderUnion($$)
168 {
169         my($union,$name) = @_;
170         my %done = ();
171
172         pidl "union $name {\n";
173         $tab_depth++;
174         foreach my $e (@{$union->{ELEMENTS}}) {
175                 if ($e->{TYPE} ne "EMPTY") {
176                         if (! defined $done{$e->{NAME}}) {
177                                 HeaderElement($e);
178                         }
179                         $done{$e->{NAME}} = 1;
180                 }
181         }
182         $tab_depth--;
183         pidl "}";
184
185         if (defined $union->{PROPERTIES}) {
186                 HeaderProperties($union->{PROPERTIES}, []);
187         }
188 }
189
190 #####################################################################
191 # parse a type
192 sub HeaderType($$$)
193 {
194         my($e,$data,$name) = @_;
195         if (ref($data) eq "HASH") {
196                 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
197                 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
198                 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
199                 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
200                 return;
201         }
202
203         if (has_property($e, "charset")) {
204                 pidl "const char";
205         } else {
206                 pidl mapType($e->{TYPE});
207         }
208 }
209
210 #####################################################################
211 # parse a typedef
212 sub HeaderTypedef($)
213 {
214     my($typedef) = shift;
215     HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
216     pidl ";\n\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
217 }
218
219 #####################################################################
220 # parse a const
221 sub HeaderConst($)
222 {
223     my($const) = shift;
224     if (!defined($const->{ARRAY_LEN}[0])) {
225         pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
226     } else {
227         pidl "#define $const->{NAME}\t $const->{VALUE}\n";
228     }
229 }
230
231 #####################################################################
232 # parse a function
233 sub HeaderFunctionInOut($$)
234 {
235     my($fn,$prop) = @_;
236
237     foreach my $e (@{$fn->{ELEMENTS}}) {
238             if (has_property($e, $prop)) {
239                     HeaderElement($e);
240             }
241     }
242 }
243
244 #####################################################################
245 # determine if we need an "in" or "out" section
246 sub HeaderFunctionInOut_needed($$)
247 {
248     my($fn,$prop) = @_;
249
250     return 1 if ($prop eq "out" && $fn->{RETURN_TYPE} ne "void");
251
252     foreach (@{$fn->{ELEMENTS}}) {
253             return 1 if (has_property($_, $prop));
254     }
255
256     return undef;
257 }
258
259 my %headerstructs = ();
260
261 #####################################################################
262 # parse a function
263 sub HeaderFunction($)
264 {
265     my($fn) = shift;
266
267     return if ($headerstructs{$fn->{NAME}});
268
269     $headerstructs{$fn->{NAME}} = 1;
270
271     pidl "\nstruct $fn->{NAME} {\n";
272     $tab_depth++;
273     my $needed = 0;
274
275     if (HeaderFunctionInOut_needed($fn, "in")) {
276             pidl tabs()."struct {\n";
277             $tab_depth++;
278             HeaderFunctionInOut($fn, "in");
279             $tab_depth--;
280             pidl tabs()."} in;\n\n";
281             $needed++;
282     }
283
284     if (HeaderFunctionInOut_needed($fn, "out")) {
285             pidl tabs()."struct {\n";
286             $tab_depth++;
287             HeaderFunctionInOut($fn, "out");
288             if ($fn->{RETURN_TYPE} ne "void") {
289                     pidl tabs().mapType($fn->{RETURN_TYPE}) . " result;\n";
290             }
291             $tab_depth--;
292             pidl tabs()."} out;\n\n";
293             $needed++;
294     }
295
296     if (! $needed) {
297             # sigh - some compilers don't like empty structures
298             pidl tabs()."int _dummy_element;\n";
299     }
300
301     $tab_depth--;
302     pidl "};\n\n";
303 }
304
305 #####################################################################
306 # parse the interface definitions
307 sub HeaderInterface($)
308 {
309         my($interface) = shift;
310
311         my $count = 0;
312
313         pidl "#ifndef _HEADER_$interface->{NAME}\n";
314         pidl "#define _HEADER_$interface->{NAME}\n\n";
315
316         if (defined $interface->{PROPERTIES}->{depends}) {
317                 my @d = split / /, $interface->{PROPERTIES}->{depends};
318                 foreach my $i (@d) {
319                         pidl "#include \"librpc/gen_ndr/$i\.h\"\n";
320                 }
321         }
322
323         foreach my $d (@{$interface->{DATA}}) {
324                 next if ($d->{TYPE} ne "CONST");
325                 HeaderConst($d);
326         }
327
328         foreach my $d (@{$interface->{DATA}}) {
329                 next if ($d->{TYPE} ne "TYPEDEF");
330                 HeaderTypedef($d);
331         }
332
333         foreach my $d (@{$interface->{DATA}}) {
334                 next if ($d->{TYPE} ne "FUNCTION");
335                 HeaderFunction($d);
336         }
337
338         pidl "#endif /* _HEADER_$interface->{NAME} */\n";
339 }
340
341 #####################################################################
342 # parse a parsed IDL into a C header
343 sub Parse($)
344 {
345     my($idl) = shift;
346     $tab_depth = 0;
347
348         $res = "";
349     pidl "/* header auto-generated by pidl */\n\n";
350     foreach my $x (@{$idl}) {
351             ($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
352     }
353     return $res;
354 }
355
356 1;