3 # Copyright 1999 Patrik Stridvall
12 if($0 =~ /^((.*?)\/?tools\/winapi_check)\/winapi_check$/)
14 $winapi_check_dir = $1;
22 @INC = ($winapi_check_dir);
24 require "nativeapi.pm";
26 require "preprocessor.pm";
28 require "winapi_function.pm";
29 require "winapi_local.pm";
30 require "winapi_global.pm";
31 require "winapi_options.pm";
32 require "winapi_parser.pm";
38 import winapi_function;
41 import winapi_options;
45 my $options = winapi_options->new(\@ARGV);
51 my $output = 'output'->new;
53 my $win16api = 'winapi'->new($output, "win16", "$winapi_check_dir/win16");
54 my $win32api = 'winapi'->new($output, "win32", "$winapi_check_dir/win32");
55 'winapi'->read_spec_files($wine_dir, $win16api, $win32api);
57 my $nativeapi = 'nativeapi'->new($output, "$winapi_check_dir/nativeapi.dat", "$wine_dir/configure.in", "$wine_dir/include/config.h.in");
59 for my $name ($win32api->all_functions) {
60 my $module16 = $win16api->function_module($name);
61 my $module32 = $win32api->function_module($name);
63 if(defined($module16)) {
64 $win16api->found_shared_function($name);
65 $win32api->found_shared_function($name);
67 if($options->shared) {
68 $output->write("*.spec: $name: is shared between $module16 (Win16) and $module32 (Win32)\n");
78 } split(/\n/, `find . -name \\*.h`);
80 foreach my $file (@files) {
82 if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) {
86 $includes{$file} = { name => $file };
90 if(/^\s*\#\s*include\s*\"(.*?)\"/) {
92 if(-e "$file_dir/$header") {
93 $includes{$file}{includes}{"$file_dir/$header"}++;
94 } elsif(-e "$wine_dir/include/$header") {
95 $includes{$file}{includes}{"include/$header"}++;
97 $output->write("$file: #include \"$header\" is not a local include ($file_dir)\n");
104 my @files2 = ("acconfig.h", "poppack.h", "pshpack1.h", "pshpack2.h", "pshpack4.h", "pshpack8.h",
105 "storage.h", "ver.h");
106 foreach my $file2 (@files2) {
107 $includes{"include/$file2"}{used}++;
112 my $progress_current=0;
113 my $progress_max=scalar($options->files);
114 foreach my $file ($options->files) {
118 if($options->progress) {
119 $output->progress("$file: file $progress_current of $progress_max");
122 my $file_dir = $file;
123 if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) {
128 if($file_dir =~ /^(libtest|program|rc|tools)/ ||
129 $file =~ /dbgmain\.c$/ ||
130 $file =~ /wineclipsrv\.c$/) # FIXME: Kludge
132 $file_type = "application";
133 } elsif($file_dir =~ /^(debug|miscemu)/) {
134 $file_type = "emulator";
136 $file_type = "library";
139 my $found_function = sub {
140 my $documentation = shift;
142 my $return_type = shift;
143 my $calling_convention = shift;
145 my $refarguments = shift;
146 my @arguments = @$refarguments;
147 my $statements = shift;
149 if($options->global) {
150 $win16api->found_type($return_type) if $options->win16;
151 $win32api->found_type($return_type) if $options->win32;
152 for my $argument (@arguments) {
153 $win16api->found_type($argument) if $options->win16;
154 $win32api->found_type($argument) if $options->win32;
157 $win16api->found_function($name) if $options->win16;
158 $win32api->found_function($name) if $options->win32;
161 if($options->local && $file_type ne "application") {
162 my $module16 = $win16api->function_module($name);
163 my $module32 = $win32api->function_module($name);
165 my $function = 'winapi_function'->new;
166 $functions{$name} = $function;
168 $function->documentation($documentation);
169 $function->linkage($linkage);
170 $function->file($file);
171 $function->return_type($return_type);
172 $function->calling_convention($calling_convention);
173 $function->name($name);
174 $function->arguments([@arguments]);
175 $function->statements($statements);
176 $function->module16($module16);
177 $function->module32($module32);
179 my $output_module = sub {
183 $output->write("$file: $module: $return_type ");
184 $output->write("$calling_convention ") if $calling_convention;
185 $output->write("$name(" . join(",", @arguments) . "): $msg\n");
188 my $output16 = &$output_module($module16);
189 my $output32 = &$output_module($module32);
191 if($options->argument) {
192 if($options->win16 && $options->report_module($module16)) {
193 winapi_local::check_function $options, $output16,
194 $return_type, $calling_convention, $name, [@arguments], $win16api;
196 if($options->win32 && $options->report_module($module32)) {
197 winapi_local::check_function $options, $output32,
198 $return_type, $calling_convention, $name, [@arguments], $win32api;
201 if($options->misplaced) {
203 if($file =~ m'^dlls/(.*)/') {
207 if($options->win16 && $options->report_module($module16)) {
208 if(!defined($module) || $module ne $module16) {
209 &$output16("function misplaced");
213 if($options->win32 && $options->report_module($module32)) {
214 if(!defined($module) || $module ne $module32) {
215 &$output32("function misplaced");
219 if($options->cross_call) {
220 local $_ = $statements;
221 my $called_function_names = {};
223 if(/(\w+)\((.*?)\)/) {
225 my $called_name = $1;
226 if($called_name !~ /^if|for|while|switch|sizeof$/) {
227 $functions{$name}->function_called($called_name);
228 if(!defined($functions{$called_name})) {
229 $functions{$called_name} = 'function'->new;
231 $functions{$called_name}->function_called_by($name);
239 if($options->documentation && (defined($module16) || defined($module32)) &&
240 $linkage ne "extern" && $statements ne "")
248 if(defined($module16) && !defined($module32)) {
249 my @uc_modules16 = split(/\s*\&\s*/, uc($module16));
250 push @uc_modules16, "WIN16";
253 foreach my $uc_module16 (@uc_modules16) {
254 if($name1 =~ s/^$uc_module16\_//) { last; }
258 $name2 =~ s/([AW])$/16$1/;
261 $name3 =~ s/16(([AW])?)$/$1/;
264 $name4 =~ s/^(.*?)(?:16)?$/\U$1\E/;
267 $name5 = s/^(.*?)16_fn(.*?)$/$116_$2/;
268 } elsif(!defined($module16) && defined($module32)) {
269 my @uc_modules32 = split(/\s*\&\s*/, uc($module32));
272 foreach my $uc_module32 (@uc_modules32) {
273 if($name1 =~ s/^$uc_module32\_//) { last; }
277 $name2 =~ s/([AW])$/32$1/;
280 $name3 =~ s/32(([AW])?)$/$1/;
287 my @uc_modules = split(/\s*\&\s*/, uc($module16));
288 push @uc_modules, split(/\s*\&\s*/, uc($module32));
291 foreach my $uc_module (@uc_modules) {
292 if($name1 =~ s/^$uc_module\_//) { last; }
304 if($name !~ /^SMapLS|SUnMapLS/ && $documentation !~ /($name|$name1|$name2|$name3|$name4|$name5)/) {
305 $output->write("$file: $name: \\\n");
306 $output->write("$documentation\n");
315 my $found_include = sub {
317 if(/^\"config\.h\"/) {
321 my $found_conditional = sub {
322 if($file_type ne "application") {
324 if(!$nativeapi->is_conditional($_)) {
325 if(/^HAVE_/ && !/^HAVE_(IPX|MESAGL|BUGGY_MESAGL|WINE_CONSTRUCTOR)$/)
327 $output->write("$file: $_ is not declared as a conditional\n");
332 $output->write("$file: conditional $_ used but config.h is not included\n");
337 my $preprocessor = 'preprocessor'->new($found_include, $found_conditional);
338 my $found_preprocessor = sub {
339 my $directive = shift;
340 my $argument = shift;
342 $preprocessor->directive($directive, $argument);
344 if($options->config) {
345 if($directive eq "include") {
347 my $check_protection;
349 if($argument =~ /^<(.*?)>$/) {
351 if($file_type ne "application") {
352 $check_protection = 1;
354 $check_protection = 0;
357 } elsif($argument =~ /^"(.*?)"$/) {
359 $check_protection = 0;
363 if($check_protection) {
364 if((-e "$wine_dir/include/$header" || -e "$file_dir/$header")) {
365 if($header !~ /^ctype.h$/) {
366 $output->write("$file: #include \<$header\> is a local include\n");
370 my $macro = uc($header);
371 $macro =~ y/\.\//__/;
372 $macro = "HAVE_" . $macro;
374 if($nativeapi->is_conditional_header($header)) {
375 if(!$preprocessor->is_def($macro)) {
376 if($macro =~ /^HAVE_X11/) {
377 if(!$preprocessor->is_undef("X_DISPLAY_MISSING")) {
378 $output->write("$file: #$directive $argument: is a conditional include, " .
379 "but is not protected\n");
381 } elsif($macro =~ /^HAVE_(.*?)_H$/) {
382 if($header ne "alloca.h" && !$preprocessor->is_def("STATFS_DEFINED_BY_$1")) {
383 $output->write("$file: #$directive $argument: is a conditional include, " .
384 "but is not protected\n");
388 } elsif($preprocessor->is_def($macro)) {
389 $output->write("$file: #$directive $argument: is protected, " .
390 "but is not a conditional include\n");
395 if(-e "$file_dir/$header") {
396 $includes{"$file_dir/$header"}{used}++;
397 foreach my $name (keys(%{$includes{"$file_dir/$header"}{includes}})) {
398 $includes{$name}{used}++;
400 } elsif(-e "$wine_dir/include/$header") {
401 $includes{"include/$header"}{used}++;
402 foreach my $name (keys(%{$includes{"include/$header"}{includes}})) {
403 $includes{$name}{used}++;
406 $output->write("$file: #include \"$header\" is not a local include\n");
413 winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor;
415 if($options->config_unnessary) {
416 if($config && $conditional == 0) {
417 $output->write("$file: includes config.h but do not use any conditionals\n");
421 winapi_local::check_file $options, $output, $file, \%functions;
424 $output->hide_progress;
426 if($options->global) {
427 foreach my $name (sort(keys(%includes))) {
428 if(!$includes{$name}{used}) {
429 if($options->include) {
430 $output->write("$name: include file is never used\n");
435 winapi_global::check $options, $output, $win16api, $nativeapi if $options->win16;
436 winapi_global::check $options, $output, $win32api, $nativeapi if $options->win32;