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