- Implemented stub statistics. Turned off by default. (Requested by Francois Gouget). - Implemented missing prototype checking. Turned off by default (Requested by Dimitry Timoshkov). - Implemented .spec file name sanity checking. Turned off by default. - Implemented documentation width checking. Turned off by default. - Minor bug fixes.
diff --git a/tools/winapi_check/win32/advapi32.api b/tools/winapi_check/win32/advapi32.api index 0387450..b1e1a48 100644 --- a/tools/winapi_check/win32/advapi32.api +++ b/tools/winapi_check/win32/advapi32.api
@@ -19,6 +19,7 @@ TOKEN_INFORMATION_CLASS ULONG WORD + %long --extension LSA_HANDLE @@ -36,6 +37,7 @@ LPCWSTR * LPDWORD LPENUM_SERVICE_STATUSA +LPENUM_SERVICE_STATUSW LPHANDLER_FUNCTION LPHKEY LPLONG
diff --git a/tools/winapi_check/win32/shell32.api b/tools/winapi_check/win32/shell32.api index 0d43934..d4b0e93 100644 --- a/tools/winapi_check/win32/shell32.api +++ b/tools/winapi_check/win32/shell32.api
@@ -22,7 +22,6 @@ UINT ULONG WCHAR -WORD WPARAM %long # --forbidden
diff --git a/tools/winapi_check/win32/shlwapi.api b/tools/winapi_check/win32/shlwapi.api index 76290c4..e6dd239 100644 --- a/tools/winapi_check/win32/shlwapi.api +++ b/tools/winapi_check/win32/shlwapi.api
@@ -10,7 +10,6 @@ HWND UINT WCHAR -WORD %long # --forbidden
diff --git a/tools/winapi_check/winapi.pm b/tools/winapi_check/winapi.pm index 450ae7b..a755ba4 100644 --- a/tools/winapi_check/winapi.pm +++ b/tools/winapi_check/winapi.pm
@@ -8,9 +8,11 @@ my $self = {}; bless ($self, $class); + my $options = \${$self->{OPTIONS}}; my $output = \${$self->{OUTPUT}}; my $name = \${$self->{NAME}}; + $$options = shift; $$output = shift; $$name = shift; my $path = shift; @@ -143,13 +145,13 @@ sub parse_spec_file { my $self = shift; + my $options = \${$self->{OPTIONS}}; my $output = \${$self->{OUTPUT}}; my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}}; my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}}; my $function_stub = \%{$self->{FUNCTION_STUB}}; my $function_module = \%{$self->{FUNCTION_MODULE}}; - my $file = shift; my %ordinals; @@ -192,6 +194,38 @@ } elsif($$function_module{$internal_name} !~ /$module/) { $$function_module{$internal_name} .= " & $module"; } + + if($$options->spec_mismatch) { + if($external_name eq "@") { + if($internal_name !~ /^\U$module\E_$ordinal$/) { + $$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n"); + } + } else { + my $name = $external_name; + + my $name1 = $name; + $name1 =~ s/^Zw/Nt/; + + my $name2 = $name; + $name2 =~ s/^(?:_|Rtl|k32|K32)//; + + my $name3 = $name; + $name3 =~ s/^INT_Int[0-9a-f]{2}Handler$/BUILTIN_DefaultIntHandler/; + + my $name4 = $name; + $name4 =~ s/^(VxDCall)\d$/$1/; + + # FIXME: This special case is becuase of a very ugly kludge that should be fixed IMHO + my $name5 = $name; + $name5 =~ s/^(.*?16)_(.*?)$/$1_fn$2/; + + if(uc($internal_name) ne uc($external_name) && + $internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/) + { + $$output->write("$file: $external_name: internal name ($internal_name) mismatch\n"); + } + } + } } elsif(/^(\d+|@)\s+stub\s+(\S+)$/) { my $external_name = $2; @@ -374,6 +408,13 @@ return sort(keys(%$function_calling_convention)); } +sub all_functions_stub { + my $self = shift; + my $function_stub = \%{$self->{FUNCTION_STUB}}; + + return sort(keys(%$function_stub)); +} + sub all_functions_found { my $self = shift; my $function_found = \%{$self->{FUNCTION_FOUND}};
diff --git a/tools/winapi_check/winapi_check b/tools/winapi_check/winapi_check index b05480c..86b5fd6 100755 --- a/tools/winapi_check/winapi_check +++ b/tools/winapi_check/winapi_check
@@ -42,7 +42,7 @@ import winapi_parser; } -my $options = winapi_options->new(\@ARGV); +my $options = winapi_options->new(\@ARGV, $wine_dir); if($options->help) { $options->show_help; exit; @@ -50,8 +50,8 @@ my $output = 'output'->new; -my $win16api = 'winapi'->new($output, "win16", "$winapi_check_dir/win16"); -my $win32api = 'winapi'->new($output, "win32", "$winapi_check_dir/win32"); +my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16"); +my $win32api = 'winapi'->new($options, $output, "win32", "$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"); @@ -108,11 +108,51 @@ } } +my %declared_functions; + my $progress_output; my $progress_current=0; -my $progress_max=scalar($options->files); -foreach my $file ($options->files) { - my %functions; +my $progress_max=scalar($options->c_files); + +if($options->headers) { + $progress_max += scalar($options->h_files); + + foreach my $file ($options->h_files) { + my %functions; + + $progress_current++; + if($options->progress) { + $output->progress("$file: file $progress_current of $progress_max"); + } + + my $found_function = sub { + my $documentation = shift; + my $linkage = shift; + my $return_type = shift; + my $calling_convention = shift; + my $name = shift; + my $refarguments = shift; + my @arguments = @$refarguments; + my $statements = shift; + + $declared_functions{$name}++; + }; + + my $found_preprocessor = sub { + my $directive = shift; + my $argument = shift; + }; + + winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor; + } +} + +my %comment_width; +my %module_pseudo_stub_count16; +my %module_pseudo_stub_count32; + +foreach my $file ($options->c_files) { + my %functions = (); $progress_current++; if($options->progress) { @@ -187,7 +227,18 @@ }; my $output16 = &$output_module($module16); my $output32 = &$output_module($module32); - + + if($options->headers) { + if(!$declared_functions{$name}) { + if($options->win16 && $options->report_module($module16)) { + &$output16("no prototype"); + } + if($options->win32 && $options->report_module($module32)) { + &$output32("no prototype"); + } + } + } + if($options->argument) { if($options->win16 && $options->report_module($module16)) { winapi_local::check_function $options, $output16, @@ -235,16 +286,28 @@ } } } + + if($options->stubs) { + if(defined($statements) && $statements =~ /FIXME[^;]*stub/) { + if($options->win16 && $options->report_module($module16)) { + foreach my $module (split(/ \& /, $module16)) { + $module_pseudo_stub_count16{$module}++; + } + } + if($options->win32 && $options->report_module($module32)) { + foreach my $module (split(/ \& /, $module32)) { + $module_pseudo_stub_count32{$module}++; + } + } + } + } if($options->documentation && (defined($module16) || defined($module32)) && $linkage ne "extern" && $statements ne "") { my $name1; my $name2; - my $name3; - my $name4; - my $name5; - + if(defined($module16) && !defined($module32)) { my @uc_modules16 = split(/\s*\&\s*/, uc($module16)); push @uc_modules16, "WIN16"; @@ -254,17 +317,9 @@ if($name1 =~ s/^$uc_module16\_//) { last; } } + # FIXME: This special case is becuase of a very ugly kludge that should be fixed IMHO $name2 = $name1; - # $name2 =~ s/([AW])$/16$1/; - - $name3 = $name1; - $name3 =~ s/16(([AW])?)$/$1/; - - $name4 = $name1; - # $name4 =~ s/^(.*?)(?:16)?$/\U$1\E/; - - $name5 = $name1; - $name5 = s/^(.*?)16_fn(.*?)$/$116_$2/; + $name2 = s/^(.*?)16_fn(.*?)$/$116_$2/; } elsif(!defined($module16) && defined($module32)) { my @uc_modules32 = split(/\s*\&\s*/, uc($module32)); @@ -274,15 +329,7 @@ } $name2 = $name1; - # $name2 =~ s/([AW])$/32$1/; - - $name3 = $name1; - # $name3 =~ s/32(([AW])?)$/$1/; - - $name4 = $name1; - $name4 =~ s/AW$//; - - $name5 = $name1; + $name2 =~ s/AW$//; } else { my @uc_modules = split(/\s*\&\s*/, uc($module16)); push @uc_modules, split(/\s*\&\s*/, uc($module32)); @@ -293,20 +340,24 @@ } $name2 = $name1; - - $name3 = $name1; - - $name4 = $name1; - - $name5 = $name1; } - if($name !~ /^SMapLS|SUnMapLS/ && $documentation !~ /\b($name|$name1|$name2|$name3|$name4|$name5)\b/) { + if($documentation !~ /\b($name|$name1|$name2)\b/) { $output->write("$file: $name: \\\n"); $output->write("$documentation\n"); - } - } + } + if($options->documentation_width) { + if($documentation =~ /(\/\**)/) { + my $width = length($1); + + $comment_width{$width}++; + if($width <= 65 || $width >= 81) { + $output->write("$file: $name: comment is $width columns wide\n"); + } + } + } + } } }; @@ -424,10 +475,81 @@ $output->hide_progress; if($options->global) { + if($options->documentation_width) { + foreach my $width (sort(keys(%comment_width))) { + my $count = $comment_width{$width}; + $output->write("*.c: $count functions have comments of width $width\n"); + } + } + + if($options->stubs) { + if($options->win16) { + my %module_stub_count16; + my %module_total_count16; + + foreach my $name ($win16api->all_functions,$win16api->all_functions_stub) { + foreach my $module (split(/ \& /, $win16api->function_module($name))) { + if($win16api->function_stub($name)) { + $module_stub_count16{$module}++; + } + $module_total_count16{$module}++; + } + } + + foreach my $module (sort(keys(%module_pseudo_stub_count16))) { + if($options->report_module($module)) { + my $real_stubs = $module_stub_count16{$module}; + my $pseudo_stubs = $module_pseudo_stub_count16{$module}; + + if(!defined($real_stubs)) { $real_stubs = 0; } + if(!defined($pseudo_stubs)) { $pseudo_stubs = 0; } + + my $stubs = $real_stubs + $pseudo_stubs; + my $total = $module_total_count16{$module}; + + if($stubs) { + $output->write("*.c: $module: $stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n"); + } + } + } + } + + if($options->win32) { + my %module_stub_count32; + my %module_total_count32; + + foreach my $name ($win32api->all_functions,$win32api->all_functions_stub) { + foreach my $module (split(/ \& /, $win32api->function_module($name))) { + if($win32api->function_stub($name)) { + $module_stub_count32{$module}++; + } + $module_total_count32{$module}++; + } + } + + foreach my $module (sort(keys(%module_pseudo_stub_count32))) { + if($options->report_module($module)) { + my $real_stubs = $module_stub_count32{$module}; + my $pseudo_stubs = $module_pseudo_stub_count32{$module}; + + if(!defined($real_stubs)) { $real_stubs = 0; } + if(!defined($pseudo_stubs)) { $pseudo_stubs = 0; } + + my $stubs = $real_stubs + $pseudo_stubs; + my $total = $module_total_count32{$module}; + + if($stubs) { + $output->write("*.c: $module: $stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n"); + } + } + } + } + } + foreach my $name (sort(keys(%includes))) { if(!$includes{$name}{used}) { if($options->include) { - $output->write("$name: include file is never used\n"); + $output->write("*.c: $name: include file is never used\n"); } } } @@ -435,4 +557,3 @@ winapi_global::check $options, $output, $win16api, $nativeapi if $options->win16; winapi_global::check $options, $output, $win32api, $nativeapi if $options->win32; } -
diff --git a/tools/winapi_check/winapi_options.pm b/tools/winapi_check/winapi_options.pm index 3c326cb..59e0849 100644 --- a/tools/winapi_check/winapi_options.pm +++ b/tools/winapi_check/winapi_options.pm
@@ -34,6 +34,8 @@ "config" => { default => 1, description => "check configuration include consistancy" }, "config-unnessary" => { default => 0, parent => "config", description => "check for unnessary #include \"config.h\"" }, + "spec-mismatch" => { default => 0, description => "spec file mismatch checking" }, + "local" => { default => 1, description => "local checking" }, "module" => { default => { active => 1, filter => 0, hash => {} }, @@ -60,12 +62,15 @@ "misplaced" => { default => 0, parent => "local", description => "check for misplaced functions" }, "cross-call" => { default => 0, parent => "local", description => "check for cross calling functions" }, "documentation" => { default => 1, parent => "local", description => "check for documentation inconsistances\n" }, - - "global" => { default => 1, description => "global checking" }, + "documentation-width" => { default => 0, parent => "documentation", description => "check for documentation width inconsistances\n" }, + + "global" => { default => 1, description => "global checking" }, "declared" => { default => 1, parent => "global", description => "declared checking" }, "implemented" => { default => 1, parent => "global", description => "implemented checking" }, "implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" }, - "include" => { default => 1, parent => "global", description => "include checking" } + "include" => { default => 1, parent => "global", description => "include checking" }, + "headers" => { default => 0, parent => "global", description => "headers checking" }, + "stubs" => { default => 0, parent => "global", description => "stubs checking" } ); my %short_options = ( @@ -82,6 +87,7 @@ my $refarguments = shift; my @ARGV = @$refarguments; + my $wine_dir = shift; for my $name (sort(keys(%options))) { my $option = $options{$name}; @@ -92,7 +98,8 @@ $$refvalue = $$option{default}; } - my $files = \@{$self->{FILES}}; + my $c_files = \@{$self->{C_FILES}}; + my $h_files = \@{$self->{H_FILES}}; my $module = \${$self->{MODULE}}; my $global = \${$self->{GLOBAL}}; @@ -161,26 +168,33 @@ print STDERR "<internal>: usage: winapi-check [--help] [<files>]\n"; exit 1; } else { - push @$files, $_; + push @$c_files, $_; } } - my $paths; - if($#$files == -1) { - $paths = "."; + my $c_paths; + if($#$c_files == -1) { + $c_paths = "."; $$global = 1; } else { - $paths = join(" ",@$files); + $c_paths = join(" ", @$c_files); } - @$files = sort(map { + my $h_paths = "$wine_dir/include $wine_dir/include/wine"; + + @$c_files = sort(map { s/^.\/(.*)$/$1/; if(!/spec\.c$/) { $_; } else { (); } - } split(/\n/, `find $paths -name \\*.c`)); + } split(/\n/, `find $c_paths -name \\*.c`)); + + @$h_files = sort(map { + s/^.\/(.*)$/$1/; + $_; + } split(/\n/, `find $h_paths -name \\*.h`)); return $self; } @@ -250,7 +264,9 @@ return $$refvalue; } -sub files { my $self = shift; return @{$self->{FILES}}; } +sub c_files { my $self = shift; return @{$self->{C_FILES}}; } + +sub h_files { my $self = shift; return @{$self->{H_FILES}}; } sub report_module { my $self = shift;
diff --git a/tools/winapi_check/winapi_parser.pm b/tools/winapi_check/winapi_parser.pm index e8b263c..2c21eb3 100644 --- a/tools/winapi_check/winapi_parser.pm +++ b/tools/winapi_check/winapi_parser.pm
@@ -36,6 +36,7 @@ my %regs_entrypoints; my @comments = (); my $level = 0; + my $extern_c = 0; my $again = 0; my $lookahead = 0; my $lookahead_count = 0; @@ -55,7 +56,8 @@ $lookahead_count = 0; } $lookahead_count++; - print " $level: $line\n" if $options->debug >= 2; + print " $level($lookahead_count): $line\n" if $options->debug >= 2; + print "*** $_\n" if $options->debug >= 3; } else { $lookahead_count = 0; $again = 0; @@ -88,11 +90,17 @@ } else { &$preprocessor_found_callback($1, ""); } - $again = 1; next; } } + # Remove extern "C" + if(s/^\s*extern\s+"C"\s+\{//m) { + $extern_c = 1; + $again = 1; + next; + } + my $documentation; { my $n = $#comments; @@ -157,6 +165,10 @@ $line .= "}" if $level > 1; print "-1: \}$_\n" if $options->debug >= 2; $level--; + if($level == -1 && $extern_c) { + $extern_c = 0; + $level = 0; + } } if($line !~ /^\s*$/) { @@ -166,7 +178,7 @@ if($function && $level == 0) { &$function_end; } - next; + next; } elsif(/(extern\s+|static\s+)?((struct\s+|union\s+|enum\s+)?\w+((\s*\*)+\s*|\s+))((__cdecl|__stdcall|VFWAPIV|VFWAPI|WINAPIV|WINAPI)\s+)?(\w+(\(\w+\))?)\s*\(([^\)]*)\)\s*(\{|\;)/s) { $_ = $'; $again = 1; @@ -300,6 +312,8 @@ $_ = $'; $again = 1; } elsif(/;/s) { $_ = $'; $again = 1; + } elsif(/extern\s+"C"\s+{/s) { + $_ = $'; $again = 1; } elsif(/\{/s) { $_ = $'; $again = 1; print "+1: $_\n" if $options->debug >= 2;