| #!/usr/bin/perl -w |
| |
| # Copyright 1999 Patrik Stridvall |
| |
| use strict; |
| |
| my $wine_dir; |
| my $winapi_check_dir; |
| |
| BEGIN { |
| |
| if($0 =~ /^((.*?)\/?tools\/winapi_check)\/winapi_check$/) |
| { |
| $winapi_check_dir = $1; |
| if($2 ne "") |
| { |
| $wine_dir = $2; |
| } else { |
| $wine_dir = "."; |
| } |
| } |
| @INC = ($winapi_check_dir); |
| |
| require "nativeapi.pm"; |
| require "output.pm"; |
| require "preprocessor.pm"; |
| require "winapi.pm"; |
| require "winapi_function.pm"; |
| require "winapi_local.pm"; |
| require "winapi_global.pm"; |
| require "winapi_options.pm"; |
| require "winapi_parser.pm"; |
| |
| import nativeapi; |
| import output; |
| import preprocessor; |
| import winapi; |
| import winapi_function; |
| import winapi_local; |
| import winapi_global; |
| import winapi_options; |
| import winapi_parser; |
| } |
| |
| my $options = winapi_options->new(\@ARGV); |
| if($options->help) { |
| $options->show_help; |
| exit; |
| } |
| |
| my $output = 'output'->new; |
| |
| my $win16api = 'winapi'->new($output, "win16", "$winapi_check_dir/win16api.dat", "$winapi_check_dir/win16"); |
| my $win32api = 'winapi'->new($output, "win32", "$winapi_check_dir/win32api.dat", "$winapi_check_dir/win32"); |
| 'winapi'->read_spec_files($wine_dir, $win16api, $win32api); |
| |
| my $nativeapi = 'nativeapi'->new($output, "$winapi_check_dir/nativeapi.dat", "$wine_dir/configure.in", "$wine_dir/include/config.h.in"); |
| |
| for my $name ($win32api->all_functions) { |
| my $module16 = $win16api->function_module($name); |
| my $module32 = $win32api->function_module($name); |
| |
| if(defined($module16)) { |
| $win16api->found_shared_function($name); |
| $win32api->found_shared_function($name); |
| |
| if($options->shared) { |
| $output->write("*.spec: $name: is shared between $module16 (Win16) and $module32 (Win32)\n"); |
| } |
| } |
| } |
| |
| my %includes; |
| { |
| my @files = map { |
| s/^.\/(.*)$/$1/; |
| $_; |
| } split(/\n/, `find . -name \\*.h`); |
| |
| foreach my $file (@files) { |
| my $file_dir = $file; |
| if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) { |
| $file_dir = "."; |
| } |
| |
| $includes{$file} = { name => $file }; |
| |
| open(IN, "< $file"); |
| while(<IN>) { |
| if(/^\s*\#\s*include\s*\"(.*?)\"/) { |
| my $header = $1; |
| if(-e "$file_dir/$header") { |
| $includes{$file}{includes}{"$file_dir/$header"}++; |
| } elsif(-e "include/$header") { |
| $includes{$file}{includes}{"include/$header"}++; |
| } else { |
| $output->write("$file: #include \"$header\" is not a local include\n"); |
| } |
| } |
| } |
| close(IN); |
| } |
| |
| my @files2 = ("acconfig.h", "poppack.h", "pshpack1.h", "pshpack2.h", "pshpack4.h", "pshpack8.h"); |
| |
| foreach my $file2 (@files2) { |
| $includes{"include/$file2"}{used}++; |
| } |
| } |
| |
| my $progress_output; |
| my $progress_current=0; |
| my $progress_max=scalar($options->files); |
| foreach my $file ($options->files) { |
| my %functions; |
| |
| $progress_current++; |
| if($options->progress) { |
| $output->progress("$file: file $progress_current of $progress_max"); |
| } |
| |
| my $file_dir = $file; |
| if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) { |
| $file_dir = "."; |
| } |
| |
| my $file_type; |
| if($file_dir =~ /^(libtest|program|rc)/) { |
| $file_type = "application"; |
| } elsif($file_dir =~ /^(debug|miscemu)/) { |
| $file_type = "emulator"; |
| } elsif($file_dir =~ /^(tools)/) { |
| $file_type = "tool"; |
| } else { |
| $file_type = "library"; |
| } |
| |
| my $found_function = sub { |
| my $documentation = shift; |
| my $return_type = shift; |
| my $calling_convention = shift; |
| my $name = shift; |
| my $refarguments = shift; |
| my @arguments = @$refarguments; |
| my $statements = shift; |
| |
| if($options->global) { |
| $win16api->found_type($return_type) if $options->win16; |
| $win32api->found_type($return_type) if $options->win32; |
| for my $argument (@arguments) { |
| $win16api->found_type($argument) if $options->win16; |
| $win32api->found_type($argument) if $options->win32; |
| } |
| |
| $win16api->found_function($name) if $options->win16; |
| $win32api->found_function($name) if $options->win32; |
| } |
| |
| if($options->local) { |
| my $module16 = $win16api->function_module($name); |
| my $module32 = $win32api->function_module($name); |
| |
| my $function = 'winapi_function'->new; |
| $functions{$name} = $function; |
| |
| $function->documentation($documentation); |
| $function->file($file); |
| $function->return_type($return_type); |
| $function->calling_convention($calling_convention); |
| $function->name($name); |
| $function->arguments([@arguments]); |
| $function->statements($statements); |
| $function->module16($module16); |
| $function->module32($module32); |
| |
| my $output_module = sub { |
| my $module = shift; |
| return sub { |
| my $msg = shift; |
| $output->write("$file: $module: $return_type "); |
| $output->write("$calling_convention ") if $calling_convention; |
| $output->write("$name(" . join(",", @arguments) . "): $msg\n"); |
| } |
| }; |
| my $output16 = &$output_module($module16); |
| my $output32 = &$output_module($module32); |
| |
| if($options->argument) { |
| if($options->win16 && $options->report_module($module16)) { |
| winapi_local::check_function $options, $output16, |
| $return_type, $calling_convention, $name, [@arguments], $win16api; |
| } |
| if($options->win32 && $options->report_module($module32)) { |
| winapi_local::check_function $options, $output32, |
| $return_type, $calling_convention, $name, [@arguments], $win32api; |
| } |
| } |
| if($options->misplaced) { |
| my $module; |
| if($file =~ m'^dlls/(.*)/') { |
| $module = $1; |
| } |
| |
| if($options->win16 && $options->report_module($module16)) { |
| if(!defined($module) || $module ne $module16) { |
| &$output16("function misplaced"); |
| } |
| } |
| |
| if($options->win32 && $options->report_module($module32)) { |
| if(!defined($module) || $module ne $module32) { |
| &$output32("function misplaced"); |
| } |
| } |
| } |
| if($options->cross_call) { |
| local $_ = $statements; |
| my $called_function_names = {}; |
| while(defined($_)) { |
| if(/(\w+)\((.*?)\)/) { |
| $_ = $'; |
| my $called_name = $1; |
| if($called_name !~ /^if|for|while|switch|sizeof$/) { |
| $functions{$name}->function_called($called_name); |
| if(!defined($functions{$called_name})) { |
| $functions{$called_name} = 'function'->new; |
| } |
| $functions{$called_name}->function_called_by($name); |
| } |
| } else { |
| undef $_ |
| } |
| } |
| } |
| |
| if($options->documentation && (defined($module16) || defined($module32))) { |
| my $name2 = $name; |
| my $name3 = $name; |
| my $name4 = $name; |
| my $name5 = $name; |
| |
| if(defined($module16) && !defined($module32)) { |
| $name2 =~ s/([AW])$/16$1/; |
| $name3 =~ s/16(([AW])?)$/$1/; |
| $name4 =~ s/^\U$module16\E\_//; |
| $name5 =~ s/^WIN16_//; |
| } elsif(!defined($module16) && defined($module32)) { |
| $name2 =~ s/([AW])$/32$1/; |
| $name3 =~ s/32(([AW])?)$/$1/; |
| $name4 =~ s/^\U$module32\E\_//; |
| $name5 =~ s/^WIN16_//; |
| } |
| |
| if($name !~ /^SMapLS|SUnMapLS/ && $documentation !~ /($name|$name2|$name3|$name4|$name5)/) { |
| $output->write("$file: $name: \\\n"); |
| $output->write("$documentation\n"); |
| } |
| } |
| |
| } |
| }; |
| |
| my $config = 0; |
| my $conditional = 0; |
| my $found_include = sub { |
| local $_ = shift; |
| if(/^\"(config\.h|native\.h)\"/) { |
| $config++; |
| } |
| }; |
| my $found_conditional = sub { |
| local $_ = shift; |
| if(!$nativeapi->is_conditional($_)) { |
| if(/^HAVE_/ && !/^HAVE_(IPX|MESAGL|BUGGY_MESAGL|WINE_CONSTRUCTOR)$/) |
| { |
| $output->write("$file: $_ is not a declared as a conditional\n"); |
| } |
| } else { |
| $conditional++; |
| if(!$config) { |
| $output->write("$file: conditional $_ used but config.h is not included\n"); |
| } |
| } |
| }; |
| my $preprocessor = 'preprocessor'->new($found_include, $found_conditional); |
| my $found_preprocessor = sub { |
| my $directive = shift; |
| my $argument = shift; |
| |
| $preprocessor->directive($directive, $argument); |
| |
| if($options->config) { |
| if($directive eq "include") { |
| if($argument =~ /^<(.*?)>$/) { |
| my $header = $1; |
| |
| if((-e "$wine_dir/include/$header" || -e "$file_dir/$header") && $file_type ne "application") { |
| $output->write("$file: #include \<$header\> is a local include\n"); |
| } |
| |
| my $macro = uc($header); |
| $macro =~ y/\.\//__/; |
| $macro = "HAVE_" . $macro; |
| |
| if($nativeapi->is_conditional_header($header)) { |
| if(!$preprocessor->is_def($macro)) { |
| if($macro =~ /^HAVE_X11/) { |
| if(!$preprocessor->is_undef("X_DISPLAY_MISSING")) { |
| $output->write("$file: #$directive $argument: is a conditional include, but is not protected\n"); |
| } |
| } elsif($macro =~ /^HAVE_(.*?)_H$/) { |
| if($header ne "alloca.h" && !$preprocessor->is_def("STATFS_DEFINED_BY_$1")) { |
| $output->write("$file: #$directive $argument: is a conditional include, but is not protected\n"); |
| } |
| } |
| } |
| } elsif($preprocessor->is_def($macro)) { |
| $output->write("$file: #$directive $argument: is protected, but is not a conditional include\n"); |
| } |
| } elsif($argument =~ /^"(.*?)"$/) { |
| my $header = $1; |
| |
| if(-e "$file_dir/$header") { |
| $includes{"$file_dir/$header"}{used}++; |
| foreach my $name (keys(%{$includes{"$file_dir/$header"}{includes}})) { |
| $includes{$name}{used}++; |
| } |
| } elsif(-e "$wine_dir/include/$header") { |
| $includes{"include/$header"}{used}++; |
| foreach my $name (keys(%{$includes{"include/$header"}{includes}})) { |
| $includes{$name}{used}++; |
| } |
| } else { |
| $output->write("$file: #include \"$header\" is not a local include\n"); |
| } |
| } |
| } |
| } |
| }; |
| |
| winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor; |
| |
| if($options->config_unnessary) { |
| if($config && $conditional == 0) { |
| $output->write("$file: includes config.h but do not use any conditionals\n"); |
| } |
| } |
| |
| winapi_local::check_file $options, $output, $file, \%functions; |
| } |
| |
| $output->hide_progress; |
| |
| if($options->global) { |
| foreach my $name (sort(keys(%includes))) { |
| if(!$includes{$name}{used}) { |
| if($options->include) { |
| $output->write("$name: include file is never used\n"); |
| } |
| } |
| } |
| |
| winapi_global::check $options, $output, $win16api, $nativeapi if $options->win16; |
| winapi_global::check $options, $output, $win32api, $nativeapi if $options->win32; |
| } |
| |