1 ###################################################
2 # check that a parsed IDL file is valid
3 # Copyright tridge@samba.org 2003
4 # released under the GNU GPL
11 #####################################################################
12 # signal a fatal validation error
17 die("$pos->{FILE}:$pos->{LINE}:$s\n");
24 warn ("$pos->{FILE}:$pos->{LINE}:warning:$s\n");
31 if ($e->{PARENT} && $e->{PARENT}->{NAME}) {
32 return "$e->{PARENT}->{NAME}.$e->{NAME}";
35 if ($e->{PARENT} && $e->{PARENT}->{PARENT}->{NAME}) {
36 return "$e->{PARENT}->{PARENT}->{NAME}.$e->{NAME}";
40 return "$e->{PARENT}->{NAME}.$e->{NAME}";
45 ###################################
46 # find a sibling var in a structure
51 my($fn) = $e->{PARENT};
53 if ($name =~ /\*(.*)/) {
57 for my $e2 (@{$fn->{ELEMENTS}}) {
58 return $e2 if ($e2->{NAME} eq $name);
67 "helpstring" => ["INTERFACE", "FUNCTION"],
68 "version" => ["INTERFACE"],
69 "uuid" => ["INTERFACE"],
70 "endpoint" => ["INTERFACE"],
71 "pointer_default" => ["INTERFACE"],
72 "pointer_default_top" => ["INTERFACE"],
73 "depends" => ["INTERFACE"],
74 "authservice" => ["INTERFACE"],
77 "object" => ["INTERFACE"],
78 "local" => ["INTERFACE", "FUNCTION"],
79 "iid_is" => ["ELEMENT"],
80 "call_as" => ["FUNCTION"],
81 "idempotent" => ["FUNCTION"],
84 "noopnum" => ["FUNCTION"],
91 "unique" => ["ELEMENT"],
92 "relative" => ["ELEMENT"],
94 "gensize" => ["TYPEDEF"],
95 "value" => ["ELEMENT"],
96 "flag" => ["ELEMENT", "TYPEDEF"],
99 "public" => ["FUNCTION", "TYPEDEF"],
100 "nopush" => ["FUNCTION", "TYPEDEF"],
101 "nopull" => ["FUNCTION", "TYPEDEF"],
102 "noprint" => ["FUNCTION", "TYPEDEF"],
105 "switch_is" => ["ELEMENT"],
106 "switch_type" => ["ELEMENT", "TYPEDEF"],
107 "nodiscriminant" => ["TYPEDEF"],
108 "case" => ["ELEMENT"],
109 "default" => ["ELEMENT"],
112 "subcontext" => ["ELEMENT"],
113 "subcontext_size" => ["ELEMENT"],
114 "compression" => ["ELEMENT"],
115 "obfuscation" => ["ELEMENT"],
118 "enum8bit" => ["TYPEDEF"],
119 "enum16bit" => ["TYPEDEF"],
120 "v1_enum" => ["TYPEDEF"],
123 "bitmap8bit" => ["TYPEDEF"],
124 "bitmap16bit" => ["TYPEDEF"],
125 "bitmap32bit" => ["TYPEDEF"],
126 "bitmap64bit" => ["TYPEDEF"],
129 "range" => ["ELEMENT"],
130 "size_is" => ["ELEMENT"],
131 "length_is" => ["ELEMENT"],
134 #####################################################################
135 # check for unknown properties
136 sub ValidProperties($$)
141 return unless defined $e->{PROPERTIES};
143 foreach my $key (keys %{$e->{PROPERTIES}}) {
144 fatal($e, el_name($e) . ": unknown property '$key'\n")
145 unless defined($property_list{$key});
147 fatal($e, el_name($e) . ": property '$key' not allowed on '$t'\n")
148 unless grep($t, @{$property_list{$key}});
155 my $ti = typelist::getType($t);
157 if (not defined ($ti)) {
159 } elsif ($ti->{DATA}->{TYPE} eq "ENUM") {
160 return typelist::enum_type_fn($ti->{DATA});
161 } elsif ($ti->{DATA}->{TYPE} eq "BITMAP") {
162 return typelist::enum_type_fn($ti->{DATA});
163 } elsif ($ti->{DATA}->{TYPE} eq "SCALAR") {
171 #####################################################################
177 ValidProperties($e,"ELEMENT");
179 if (util::has_property($e, "ptr")) {
180 fatal($e, el_name($e) . " : pidl does not support full NDR pointers yet\n");
183 # Check whether switches are used correctly.
184 if (my $switch = util::has_property($e, "switch_is")) {
185 my $e2 = find_sibling($e, $switch);
186 my $type = typelist::getType($e->{TYPE});
188 if (defined($type) and $type->{DATA}->{TYPE} ne "UNION") {
189 fatal($e, el_name($e) . ": switch_is() used on non-union type $e->{TYPE} which is a $type->{DATA}->{TYPE}");
192 if (!util::has_property($type, "nodiscriminant") and defined($e2)) {
193 my $discriminator_type = util::has_property($type, "switch_type");
194 $discriminator_type = "uint32" unless defined ($discriminator_type);
196 my $t1 = mapToScalar($discriminator_type);
198 if (not defined($t1)) {
199 fatal($e, el_name($e) . ": unable to map discriminator type '$discriminator_type' to scalar");
202 my $t2 = mapToScalar($e2->{TYPE});
203 if (not defined($t2)) {
204 fatal($e, el_name($e) . ": unable to map variable used for switch_is() to scalar");
208 nonfatal($e, el_name($e) . ": switch_is() is of type $e2->{TYPE} ($t2), while discriminator type for union $type->{NAME} is $discriminator_type ($t1)");
213 if (defined (util::has_property($e, "subcontext_size")) and not defined(util::has_property($e, "subcontext"))) {
214 fatal($e, el_name($e) . " : subcontext_size() on non-subcontext element");
217 if (defined (util::has_property($e, "compression")) and not defined(util::has_property($e, "subcontext"))) {
218 fatal($e, el_name($e) . " : compression() on non-subcontext element");
221 if (defined (util::has_property($e, "obfuscation")) and not defined(util::has_property($e, "subcontext"))) {
222 fatal($e, el_name($e) . " : obfuscation() on non-subcontext element");
225 if (!$e->{POINTERS} && (
226 util::has_property($e, "ptr") or
227 util::has_property($e, "unique") or
228 util::has_property($e, "relative") or
229 util::has_property($e, "ref"))) {
230 fatal($e, el_name($e) . " : pointer properties on non-pointer element\n");
234 #####################################################################
240 ValidProperties($struct,"STRUCT");
242 foreach my $e (@{$struct->{ELEMENTS}}) {
243 $e->{PARENT} = $struct;
248 #####################################################################
254 ValidProperties($union,"UNION");
256 if (util::has_property($union->{PARENT}, "nodiscriminant") and util::has_property($union->{PARENT}, "switch_type")) {
257 fatal($union->{PARENT}, $union->{PARENT}->{NAME} . ": switch_type() on union without discriminant");
260 foreach my $e (@{$union->{ELEMENTS}}) {
261 $e->{PARENT} = $union;
263 if (defined($e->{PROPERTIES}->{default}) and
264 defined($e->{PROPERTIES}->{case})) {
265 fatal $e, "Union member $e->{NAME} can not have both default and case properties!\n";
268 unless (defined ($e->{PROPERTIES}->{default}) or
269 defined ($e->{PROPERTIES}->{case})) {
270 fatal $e, "Union member $e->{NAME} must have default or case property\n";
273 if (util::has_property($e, "ref")) {
274 fatal($e, el_name($e) . " : embedded ref pointers are not supported yet\n");
282 #####################################################################
286 my($typedef) = shift;
287 my $data = $typedef->{DATA};
289 ValidProperties($typedef,"TYPEDEF");
291 $data->{PARENT} = $typedef;
293 if (ref($data) eq "HASH") {
294 if ($data->{TYPE} eq "STRUCT") {
298 if ($data->{TYPE} eq "UNION") {
304 #####################################################################
310 ValidProperties($fn,"FUNCTION");
312 foreach my $e (@{$fn->{ELEMENTS}}) {
314 if (util::has_property($e, "ref") && !$e->{POINTERS}) {
315 fatal $e, "[ref] variables must be pointers ($fn->{NAME}/$e->{NAME})\n";
321 #####################################################################
322 # parse the interface definitions
323 sub ValidInterface($)
325 my($interface) = shift;
326 my($data) = $interface->{DATA};
328 ValidProperties($interface,"INTERFACE");
330 if (util::has_property($interface, "pointer_default") &&
331 $interface->{PROPERTIES}->{pointer_default} eq "ptr") {
332 fatal $interface, "Full pointers are not supported yet\n";
335 if (util::has_property($interface, "object")) {
336 if (util::has_property($interface, "version") &&
337 $interface->{PROPERTIES}->{version} != 0) {
338 fatal $interface, "Object interfaces must have version 0.0 ($interface->{NAME})\n";
341 if (!defined($interface->{BASE}) &&
342 not ($interface->{NAME} eq "IUnknown")) {
343 fatal $interface, "Object interfaces must all derive from IUnknown ($interface->{NAME})\n";
347 foreach my $d (@{$data}) {
348 ($d->{TYPE} eq "TYPEDEF") &&
350 ($d->{TYPE} eq "FUNCTION") &&
356 #####################################################################
357 # parse a parsed IDL into a C header
362 foreach my $x (@{$idl}) {
363 ($x->{TYPE} eq "INTERFACE") &&