Make RDW_ValidateParent() modify the update region of all parents, not
[wine.git] / tools / winapi_check / winapi.pm
blob3a20328b429b0a2459578fd21b60a76653238b7e
1 package winapi;
3 use strict;
5 sub new {
6 my $proto = shift;
7 my $class = ref($proto) || $proto;
8 my $self = {};
9 bless ($self, $class);
11 my $options = \${$self->{OPTIONS}};
12 my $output = \${$self->{OUTPUT}};
13 my $name = \${$self->{NAME}};
15 $$options = shift;
16 $$output = shift;
17 $$name = shift;
18 my $path = shift;
20 my @files = map {
21 s/^.\/(.*)$/$1/;
22 $_;
23 } split(/\n/, `find $path -name \\*.api`);
25 foreach my $file (@files) {
26 my $module = $file;
27 $module =~ s/.*?\/([^\/]*?)\.api$/$1/;
28 $self->parse_api_file($file,$module);
31 return $self;
34 sub parse_api_file {
35 my $self = shift;
37 my $options = \${$self->{OPTIONS}};
38 my $output = \${$self->{OUTPUT}};
39 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
40 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
41 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
42 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
43 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
45 my $file = shift;
46 my $module = shift;
48 my $kind;
49 my $extension = 0;
50 my $forbidden = 0;
52 if($$options->progress) {
53 $$output->progress("$file");
56 open(IN, "< $file") || die "$file: $!\n";
57 $/ = "\n";
58 while(<IN>) {
59 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
60 s/^(.*?)\s*#.*$/$1/; # remove comments
61 /^$/ && next; # skip empty lines
63 if(s/^%(\S+)\s*//) {
64 $kind = $1;
65 $forbidden = 0;
66 $extension = 0;
68 $$allowed_kind{$kind} = 1;
69 if(/^--forbidden/) {
70 $forbidden = 1;
71 } elsif(/^--extension/) {
72 $extension = 1;
74 } elsif(defined($kind)) {
75 my $type = $_;
76 if(!$forbidden) {
77 if(defined($module)) {
78 if($$allowed_modules_unlimited{$type}) {
79 $$output->write("$file: type ($type) already specificed as an unlimited type\n");
80 } elsif(!$$allowed_modules{$type}{$module}) {
81 $$allowed_modules{$type}{$module} = 1;
82 $$allowed_modules_limited{$type} = 1;
83 } else {
84 $$output->write("$file: type ($type) already specificed\n");
86 } else {
87 $$allowed_modules_unlimited{$type} = 1;
89 } else {
90 $$allowed_modules_limited{$type} = 1;
92 if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
93 $$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
94 } else {
95 $$translate_argument{$type} = $kind;
97 } else {
98 $$output->write("$file: file must begin with %<type> statement\n");
99 exit 1;
102 close(IN);
105 sub get_spec_file_type {
106 my $proto = shift;
107 my $class = ref($proto) || $proto;
109 my $file = shift;
111 my $type;
113 open(IN, "< $file") || die "$file: $!\n";
114 $/ = "\n";
115 while(<IN>) {
116 if(/^type\s*(\w+)/) {
117 $type = $1;
118 last;
121 close(IN);
123 return $type;
126 sub read_spec_files {
127 my $proto = shift;
128 my $class = ref($proto) || $proto;
130 my $path = shift;
131 my $file_type = shift;
132 my $win16api = shift;
133 my $win32api = shift;
135 my @files = map {
136 s/^.\/(.*)$/$1/;
137 if(&$file_type($_) eq "library") {
139 } else {
142 } split(/\n/, `find $path -name \\*.spec`);
144 foreach my $file (@files) {
145 my $type = 'winapi'->get_spec_file_type($file);
146 if($type eq "win16") {
147 $win16api->parse_spec_file($file);
148 } elsif($type eq "win32") {
149 $win32api->parse_spec_file($file);
154 sub parse_spec_file {
155 my $self = shift;
157 my $options = \${$self->{OPTIONS}};
158 my $output = \${$self->{OUTPUT}};
159 my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
160 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
161 my $function_stub = \%{$self->{FUNCTION_STUB}};
162 my $function_module = \%{$self->{FUNCTION_MODULE}};
163 my $modules = \%{$self->{MODULES}};
165 my $file = shift;
167 my %ordinals;
168 my $type;
169 my $module;
171 if($$options->progress) {
172 $$output->progress("$file");
175 open(IN, "< $file") || die "$file: $!\n";
176 $/ = "\n";
177 my $header = 1;
178 my $lookahead = 0;
179 while($lookahead || defined($_ = <IN>)) {
180 $lookahead = 0;
181 s/^\s*(.*?)\s*$/$1/;
182 s/^(.*?)\s*#.*$/$1/;
183 /^$/ && next;
185 if($header) {
186 if(/^name\s*(\S*)/) { $module = $1; }
187 if(/^type\s*(\w+)/) { $type = $1; }
188 if(/^\d+|@/) { $header = 0; $lookahead = 1; }
189 next;
192 my $ordinal;
193 if(/^(\d+|@)\s+(pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/) {
194 my $calling_convention = $2;
195 my $external_name = $3;
196 my $arguments = $4;
197 my $internal_name = $5;
199 $ordinal = $1;
201 # FIXME: Internal name existing more than once not handled properly
202 $$function_arguments{$internal_name} = $arguments;
203 $$function_calling_convention{$internal_name} = $calling_convention;
204 if(!$$function_module{$internal_name}) {
205 $$function_module{$internal_name} = "$module";
206 } elsif($$function_module{$internal_name} !~ /$module/) {
207 $$function_module{$internal_name} .= " & $module";
210 if($$options->spec_mismatch) {
211 if($external_name eq "@") {
212 if($internal_name !~ /^\U$module\E_$ordinal$/) {
213 $$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
215 } else {
216 my $name = $external_name;
218 my $name1 = $name;
219 $name1 =~ s/^Zw/Nt/;
221 my $name2 = $name;
222 $name2 =~ s/^(?:_|Rtl|k32|K32)//;
224 my $name3 = $name;
225 $name3 =~ s/^INT_Int[0-9a-f]{2}Handler$/BUILTIN_DefaultIntHandler/;
227 my $name4 = $name;
228 $name4 =~ s/^(VxDCall)\d$/$1/;
230 # FIXME: This special case is becuase of a very ugly kludge that should be fixed IMHO
231 my $name5 = $name;
232 $name5 =~ s/^(.*?16)_(.*?)$/$1_fn$2/;
234 if(uc($internal_name) ne uc($external_name) &&
235 $internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/)
237 $$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
241 } elsif(/^(\d+|@)\s+stub\s+(\S+)$/) {
242 my $external_name = $2;
244 $ordinal = $1;
246 my $internal_name;
247 if($type eq "win16") {
248 $internal_name = $external_name . "16";
249 } else {
250 $internal_name = $external_name;
253 # FIXME: Internal name existing more than once not handled properly
254 $$function_stub{$internal_name} = 1;
255 if(!$$function_module{$internal_name}) {
256 $$function_module{$internal_name} = "$module";
257 } elsif($$function_module{$internal_name} !~ /$module/) {
258 $$function_module{$internal_name} .= " & $module";
260 } elsif(/^(\d+|@)\s+(equate|long|word|extern|forward)/) {
261 # ignore
262 } else {
263 my $next_line = <IN>;
264 if(!defined($next_line) || $next_line =~ /^\s*\d|@/) {
265 die "$file: $.: syntax error: '$_'\n";
266 } else {
267 $_ .= $next_line;
268 $lookahead = 1;
272 if(defined($ordinal)) {
273 if($ordinal ne "@" && $ordinals{$ordinal}) {
274 $$output->write("$file: ordinal redefined: $_\n");
276 $ordinals{$ordinal}++;
279 close(IN);
281 $$modules{$module}++;
284 sub name {
285 my $self = shift;
286 my $name = \${$self->{NAME}};
288 return $$name;
291 sub is_allowed_kind {
292 my $self = shift;
293 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
295 my $kind = shift;
296 if(defined($kind)) {
297 return $$allowed_kind{$kind};
298 } else {
299 return 0;
303 sub is_limited_type {
304 my $self = shift;
305 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
307 my $type = shift;
309 return $$allowed_modules_limited{$type};
312 sub allowed_type_in_module {
313 my $self = shift;
314 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
315 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
317 my $type = shift;
318 my @modules = split(/ \& /, shift);
320 if(!$$allowed_modules_limited{$type}) { return 1; }
322 foreach my $module (@modules) {
323 if($$allowed_modules{$type}{$module}) { return 1; }
326 return 0;
329 sub type_used_in_module {
330 my $self = shift;
331 my $used_modules = \%{$self->{USED_MODULES}};
333 my $type = shift;
334 my @modules = split(/ \& /, shift);
336 foreach my $module (@modules) {
337 $$used_modules{$type}{$module} = 1;
340 return ();
343 sub types_not_used {
344 my $self = shift;
345 my $used_modules = \%{$self->{USED_MODULES}};
346 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
348 my $not_used;
349 foreach my $type (sort(keys(%$allowed_modules))) {
350 foreach my $module (sort(keys(%{$$allowed_modules{$type}}))) {
351 if(!$$used_modules{$type}{$module}) {
352 $$not_used{$module}{$type} = 1;
356 return $not_used;
359 sub types_unlimited_used_in_modules {
360 my $self = shift;
362 my $output = \${$self->{OUTPUT}};
363 my $used_modules = \%{$self->{USED_MODULES}};
364 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
365 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
367 my $used_types;
368 foreach my $type (sort(keys(%$allowed_modules_unlimited))) {
369 my $count = 0;
370 my @modules = ();
371 foreach my $module (sort(keys(%{$$used_modules{$type}}))) {
372 $count++;
373 push @modules, $module;
375 if($count) {
376 foreach my $module (@modules) {
377 $$used_types{$type}{$module} = 1;
381 return $used_types;
384 sub translate_argument {
385 my $self = shift;
386 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
388 my $argument = shift;
390 return $$translate_argument{$argument};
393 sub all_declared_types {
394 my $self = shift;
395 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
397 return sort(keys(%$translate_argument));
400 sub found_type {
401 my $self = shift;
402 my $type_found = \%{$self->{TYPE_FOUND}};
404 my $name = shift;
406 $$type_found{$name}++;
409 sub type_found {
410 my $self = shift;
411 my $type_found= \%{$self->{TYPE_FOUND}};
413 my $name = shift;
415 return $$type_found{$name};
418 sub all_modules {
419 my $self = shift;
420 my $modules = \%{$self->{MODULES}};
422 return sort(keys(%$modules));
425 sub all_functions {
426 my $self = shift;
427 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
429 return sort(keys(%$function_calling_convention));
432 sub all_functions_stub {
433 my $self = shift;
434 my $function_stub = \%{$self->{FUNCTION_STUB}};
436 return sort(keys(%$function_stub));
439 sub all_functions_found {
440 my $self = shift;
441 my $function_found = \%{$self->{FUNCTION_FOUND}};
443 return sort(keys(%$function_found));
446 sub function_calling_convention {
447 my $self = shift;
448 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
450 my $name = shift;
452 return $$function_calling_convention{$name};
455 sub is_function {
456 my $self = shift;
457 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
459 my $name = shift;
461 return $$function_calling_convention{$name};
464 sub is_shared_function {
465 my $self = shift;
466 my $function_shared = \%{$self->{FUNCTION_SHARED}};
468 my $name = shift;
470 return $$function_shared{$name};
473 sub found_shared_function {
474 my $self = shift;
475 my $function_shared = \%{$self->{FUNCTION_SHARED}};
477 my $name = shift;
479 $$function_shared{$name} = 1;
482 sub function_arguments {
483 my $self = shift;
484 my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
486 my $name = shift;
488 return $$function_arguments{$name};
491 sub function_module {
492 my $self = shift;
493 my $function_module = \%{$self->{FUNCTION_MODULE}};
495 my $name = shift;
497 return $$function_module{$name};
500 sub function_stub {
501 my $self = shift;
502 my $function_stub = \%{$self->{FUNCTION_STUB}};
504 my $name = shift;
506 return $$function_stub{$name};
509 sub found_function {
510 my $self = shift;
511 my $function_found = \%{$self->{FUNCTION_FOUND}};
513 my $name = shift;
515 $$function_found{$name}++;
518 sub function_found {
519 my $self = shift;
520 my $function_found = \%{$self->{FUNCTION_FOUND}};
522 my $name = shift;
524 return $$function_found{$name};