diff --git a/tools/winapi_check/modules.dat b/tools/winapi_check/modules.dat index e40f151f037..e1d38926447 100644 --- a/tools/winapi_check/modules.dat +++ b/tools/winapi_check/modules.dat @@ -145,14 +145,21 @@ files dlls/ole32 -% dlls/ole32/ole2nls.spec - -dlls/ole32 - % dlls/ole32/ole32.spec dlls/ole32 +% dlls/ole32/ole2conv.spec + +% dlls/ole32/ole2nls.spec + +dlls/ole32 +ole + +% dlls/ole32/ole2prox.spec + +% dlls/ole32/ole2thk.spec + % dlls/ole32/storage.spec dlls/ole32 @@ -258,6 +265,11 @@ dlls/user memory windows +% dlls/user/ddeml.spec + +dlls/user +misc + % dlls/user/user.spec controls @@ -393,10 +405,6 @@ dlls/x11drv % if1632/comm.spec -% if1632/ddeml.spec - -misc - % if1632/dispdib.spec graphics @@ -414,16 +422,6 @@ relay32 scheduler win32 -% if1632/ole2conv.spec - -% if1632/ole2nls.spec - -ole - -% if1632/ole2prox.spec - -% if1632/ole2thk.spec - % if1632/system.spec misc diff --git a/tools/winapi_check/modules.pm b/tools/winapi_check/modules.pm index 20185332a40..e1d2cb4ad10 100644 --- a/tools/winapi_check/modules.pm +++ b/tools/winapi_check/modules.pm @@ -52,6 +52,11 @@ sub new { if(/^%\s+(.*?)$/) { $spec_file = $1; + + if(!-f "$wine_dir/$spec_file") { + $$output->write("$module_file: $spec_file: file ($spec_file) doesn't exist or is no file\n"); + } + if($wine_dir eq ".") { $all_spec_files{$spec_file}--; } else { diff --git a/tools/winapi_check/nativeapi.dat b/tools/winapi_check/nativeapi.dat index 8a3de0f9e5d..6e0c0af5c2f 100644 --- a/tools/winapi_check/nativeapi.dat +++ b/tools/winapi_check/nativeapi.dat @@ -16,6 +16,7 @@ _sysconf _xmknod _xstat abs +accept access acos asctime @@ -26,14 +27,18 @@ atexit atof atoi atol +bind bsearch bzero calloc ceil cfgetospeed chmod +clock close closedir +closesocket +connect cos cosh ctime @@ -66,23 +71,39 @@ fputs fread free frexp +freopen +fscanf fseek fsetpos fsync +ftell ftruncate fwrite +getc getcwd getenv +gethostbyaddr +gethostbyname +gethostname getlogin getnetbyname +getpeername getpid getpwuid +gets +getservbyname +getsockname gettimeofday getuid gmtime +htonl +htons hypot +inet_addr inet_network +inet_ntoa ioctl +ioctlsocket isalnum isalpha isatty @@ -102,6 +123,7 @@ kill labs ldexp ldiv +listen localtime log log10 @@ -121,6 +143,8 @@ modf mprotect msync munmap +ntohl +ntohs open opendir perror @@ -128,6 +152,7 @@ pipe poll pow printf +putc putchar putenv puts @@ -137,19 +162,25 @@ rand read readdir realloc +recv +recvfrom remove rename rmdir select +send +sendto setbuf setlocale setsid +setsockopt settimeofday setvbuf shmat shmctl shmdt shmget +shutdown sigaction sigaddset sigaltstack @@ -160,6 +191,7 @@ sin sin sinh sleep +socket snprintf sprintf sqrt diff --git a/tools/winapi_check/win32/opengl32.api b/tools/winapi_check/win32/opengl32.api index 7e874ee325f..fd8d7d84537 100644 --- a/tools/winapi_check/win32/opengl32.api +++ b/tools/winapi_check/win32/opengl32.api @@ -1,3 +1,8 @@ +%double + +GLclampd +GLdouble + %long BOOL @@ -6,9 +11,7 @@ FLOAT GLbitfield GLboolean GLbyte -GLclampd GLclampf -GLdouble GLenum GLfloat GLint diff --git a/tools/winapi_check/winapi.pm b/tools/winapi_check/winapi.pm index c91cdabba8a..cc96b709b14 100644 --- a/tools/winapi_check/winapi.pm +++ b/tools/winapi_check/winapi.pm @@ -215,6 +215,7 @@ sub parse_spec_file { my $output = \${$self->{OUTPUT}}; my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}}; my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}}; + my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}}; my $function_stub = \%{$self->{FUNCTION_STUB}}; my $function_module = \%{$self->{FUNCTION_MODULE}}; my $modules = \%{$self->{MODULES}}; @@ -256,6 +257,7 @@ sub parse_spec_file { $ordinal = $1; # FIXME: Internal name existing more than once not handled properly + $$function_external_name{$internal_name} = $external_name; $$function_arguments{$internal_name} = $arguments; $$function_calling_convention{$internal_name} = $calling_convention; if(!$$function_module{$internal_name}) { @@ -571,6 +573,15 @@ sub function_calling_convention { return $$function_calling_convention{$name}; } +sub function_external_name { + my $self = shift; + my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}}; + + my $name = shift; + + return $$function_external_name{$name}; +} + sub is_function { my $self = shift; my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}}; diff --git a/tools/winapi_check/winapi_check b/tools/winapi_check/winapi_check index 75e6aa2de68..f517dfa0e2e 100755 --- a/tools/winapi_check/winapi_check +++ b/tools/winapi_check/winapi_check @@ -1,6 +1,16 @@ #!/usr/bin/perl -w -# Copyright 1999 Patrik Stridvall +# Copyright 1999-2000 Patrik Stridvall + +# Note that winapi_check are using heuristics quite heavily. +# So always remember that: +# +# "Heuristics are bug ridden by definition. +# If they didn't have bugs, then they'd be algorithms." +# +# In other words, reported bugs are only potential bugs not +# real bugs, so they are called issues rather than bugs. +# use strict; @@ -92,6 +102,7 @@ my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_ my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16"); my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32"); +my @winapis = ($win16api, $win32api); if($options->global) { 'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api); @@ -176,12 +187,49 @@ if($options->headers) { my $linkage = shift; my $return_type = shift; my $calling_convention = shift; - my $name = shift; - my $refarguments = shift; - my @arguments = @$refarguments; + my $internal_name = shift; + my $refargument_types = shift; + my @argument_types = @$refargument_types; + my $refargument_names = shift; + my @argument_names = @$refargument_names; my $statements = shift; - - $declared_functions{$name}++; + + foreach my $winapi (@winapis) { + my $module = $winapi->function_module($internal_name); + if(!defined($module)) { next } + + my $external_name = $winapi->function_external_name($internal_name); + # FIXME: Kludge because of the THUNK variants + if(!defined($external_name)) { + next; + } + + my $output_function = sub { + my $message = shift; + + $output->write("$file: $module: $return_type "); + $output->write("$calling_convention ") if $calling_convention; + $output->write("$internal_name(" . join(",", @argument_types) . "): $message\n"); + }; + + if(!defined($declared_functions{$winapi->name}{$external_name})) { + $declared_functions{$winapi->name}{$external_name} = "$file"; + } elsif($options->headers_duplicated) { + my $message = "declared more than once"; + if($file ne $declared_functions{$winapi->name}{$external_name}) { + $message .= ", first declaration in '" . $declared_functions{$winapi->name}{$external_name} . "'"; + } + &$output_function("$message"); + } + + if($options->headers_misplaced) { + if($file =~ /^include\/[^\/]*$/ && $winapi->name eq "win16") { + &$output_function("declaration misplaced"); + } elsif($file =~ /^include\/wine\/[^\/]*$/ && $winapi->name eq "win32") { + &$output_function("declaration misplaced"); + } + } + } }; my $found_preprocessor = sub { @@ -221,13 +269,15 @@ foreach my $file ($options->c_files) { my $return_type = shift; my $calling_convention = shift; my $internal_name = shift; - my $external_name = $internal_name; my $refargument_types = shift; my @argument_types = @$refargument_types; my $refargument_names = shift; my @argument_names = @$refargument_names; my $statements = shift; + my $external_name16 = $win16api->function_external_name($internal_name); + my $external_name32 = $win32api->function_external_name($internal_name); + if($options->global) { $win16api->found_type($return_type) if $options->win16; $win32api->found_type($return_type) if $options->win32; @@ -242,40 +292,7 @@ foreach my $file ($options->c_files) { if($file_type ne "application") { my $module16 = $win16api->function_module($internal_name); - if(!defined($module16)) { - if($internal_name =~ /^(.*?)_(.*?)$/) { - my $module2 = lc($1); - my $name2 = $2; - if($win16api->is_module($module2)) { - $module16 = $win16api->function_module($name2); - if(defined($module16)) { - if(uc($module16) !~ /\U$module2\E/) { - $external_name = $name2; - } else { - $module16 = undef; - } - } - } - } - } - my $module32 = $win32api->function_module($internal_name); - if(!defined($module32)) { - if($internal_name =~ /^(.*?)_(.*?)$/) { - my $module2 = lc($1); - my $name2 = $2; - if($win32api->is_module($module2)) { - $module32 = $win32api->function_module($name2); - if(defined($module32)) { - if(uc($module32) =~ /\U$module2\E/) { - $external_name = $name2; - } else { - $module32 = undef; - } - } - } - } - } my $function = 'winapi_function'->new; $functions{$internal_name} = $function; @@ -285,7 +302,8 @@ foreach my $file ($options->c_files) { $function->file($file); $function->return_type($return_type); $function->calling_convention($calling_convention); - $function->external_name($external_name); + $function->external_name16($external_name16); + $function->external_name32($external_name32); $function->internal_name($internal_name); $function->argument_types([@argument_types]); $function->argument_names([@argument_names]); @@ -337,25 +355,43 @@ foreach my $file ($options->c_files) { } } - if($options->local && $options->headers) { - if(!$declared_functions{$internal_name}) { - if($options->win16 && $options->report_module($module16)) { - &$output16("no prototype"); + if($options->local && $options->headers && $options->prototype) { + if($options->win16 && $options->report_module($module16)) { + if(!defined($external_name16) || (!$nativeapi->is_function($external_name16) && + !defined($declared_functions{$win16api->name}{$external_name16}))) + { + if(!defined($external_name16) || ($external_name16 !~ /^DllEntryPoint$/ && + $internal_name !~ /^I(?:Malloc|Storage)16_fn/ && + $internal_name !~ /^(?:\Q$module16\E|THUNK|WIN16)_\Q$external_name16\E(?:16)?$/)) + { + &$output16("no prototype"); + } } - if($options->win32 && $options->report_module($module32)) { - &$output32("no prototype"); + } + + if($options->win32 && $options->report_module($module32)) { + if(!defined($external_name32) || (!$nativeapi->is_function($external_name32) && !defined($declared_functions{$win32api->name}{$external_name32}))) + { + if(!defined($external_name32) || ($external_name32 !~ /^Dll(?: + Install|CanUnloadNow|GetClassObject|GetVersion| + RegisterServer|RegisterServerEx|UnregisterServer)|DriverProc$/x && + $internal_name !~ /^COMCTL32_Str/ && + $internal_name !~ /^(?:\Q$module32\E|wine)_(?:\Q$external_name32\E|\d+)$/)) + { + &$output32("no prototype"); + } } - } + } } if($options->local && $options->argument) { if($options->win16 && $options->report_module($module16)) { winapi_local::check_function $options, $output16, - $return_type, $calling_convention, $external_name, $internal_name, [@argument_types], $win16api; + $return_type, $calling_convention, $external_name16, $internal_name, [@argument_types], $win16api; } if($options->win32 && $options->report_module($module32)) { winapi_local::check_function $options, $output32, - $return_type, $calling_convention, $external_name, $internal_name, [@argument_types], $win32api; + $return_type, $calling_convention, $external_name32, $internal_name, [@argument_types], $win32api; } } diff --git a/tools/winapi_check/winapi_function.pm b/tools/winapi_check/winapi_function.pm index fa166ca86d9..50a52b5131e 100644 --- a/tools/winapi_check/winapi_function.pm +++ b/tools/winapi_check/winapi_function.pm @@ -66,15 +66,26 @@ sub calling_convention { return $$calling_convention; } -sub external_name { +sub external_name16 { my $self = shift; - my $external_name = \${$self->{EXTERNAL_NAME}}; + my $external_name16 = \${$self->{EXTERNAL_NAME16}}; local $_ = shift; - if(defined($_)) { $$external_name = $_; } + if(defined($_)) { $$external_name16 = $_; } - return $$external_name; + return $$external_name16; +} + +sub external_name32 { + my $self = shift; + my $external_name32 = \${$self->{EXTERNAL_NAME32}}; + + local $_ = shift; + + if(defined($_)) { $$external_name32 = $_; } + + return $$external_name32; } sub internal_name { diff --git a/tools/winapi_check/winapi_local.pm b/tools/winapi_check/winapi_local.pm index 576c5722f09..5dd90a4530f 100644 --- a/tools/winapi_check/winapi_local.pm +++ b/tools/winapi_check/winapi_local.pm @@ -13,23 +13,23 @@ sub check_function { my @argument_types = @$refargument_types; my $winapi = shift; - my $module = $winapi->function_module($external_name); + my $module = $winapi->function_module($internal_name); if($winapi->name eq "win16") { - my $name16 = $external_name; + my $name16 = $internal_name; $name16 =~ s/16$//; - if($name16 ne $external_name && $winapi->function_stub($name16)) { + if($name16 ne $internal_name && $winapi->function_stub($name16)) { if($options->implemented) { &$output("function implemented but declared as stub in .spec file"); } return; - } elsif($winapi->function_stub($external_name)) { + } elsif($winapi->function_stub($internal_name)) { if($options->implemented_win32) { &$output("32-bit variant of function implemented but declared as stub in .spec file"); } return; } - } elsif($winapi->function_stub($external_name)) { + } elsif($winapi->function_stub($internal_name)) { if($options->implemented) { &$output("function implemented but declared as stub in .spec file"); } @@ -80,8 +80,8 @@ sub check_function { } } - my $declared_calling_convention = $winapi->function_calling_convention($external_name); - my @declared_argument_kinds = split(/\s+/, $winapi->function_arguments($external_name)); + my $declared_calling_convention = $winapi->function_calling_convention($internal_name); + my @declared_argument_kinds = split(/\s+/, $winapi->function_arguments($internal_name)); if($declared_calling_convention =~ /^register|interrupt$/) { push @declared_argument_kinds, "ptr"; @@ -112,7 +112,7 @@ sub check_function { } if($#argument_types != -1 && $argument_types[$#argument_types] eq "CONTEXT *" && - $external_name !~ /^(Get|Set)ThreadContext$/) # FIXME: Kludge + $internal_name !~ /^(Get|Set)ThreadContext$/) # FIXME: Kludge { $#argument_types--; } diff --git a/tools/winapi_check/winapi_options.pm b/tools/winapi_check/winapi_options.pm index 533a7937cf6..5c90f9167a0 100644 --- a/tools/winapi_check/winapi_options.pm +++ b/tools/winapi_check/winapi_options.pm @@ -61,7 +61,7 @@ my %options = ( "calling-convention" => { default => 0, parent => "local", description => "calling convention checking" }, "misplaced" => { default => 1, parent => "local", description => "check for misplaced functions" }, "statements" => { default => 0, parent => "local", description => "check for statements inconsistances" }, - "cross-call" => { default => 0, parent => "statements", description => "check for cross calling functions" }, + "cross-call" => { default => 0, parent => "statements", description => "check for cross calling functions" }, "cross-call-win32-win16" => { default => 0, parent => "cross-call", description => "check for cross calls between win32 and win16" }, @@ -71,13 +71,16 @@ my %options = ( "debug-messages" => { default => 0, parent => "statements", description => "check for debug messages inconsistances" }, "documentation" => { default => 1, parent => "local", description => "check for documentation inconsistances\n" }, "documentation-width" => { default => 0, parent => "documentation", description => "check for documentation width inconsistances\n" }, + "prototype" => { default => 0, parent => ["local", "headers"], description => "prototype checking" }, "global" => { default => 1, description => "global checking" }, - "declared" => { default => 1, parent => "global", description => "declared 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" }, "headers" => { default => 0, parent => "global", description => "headers checking" }, + "headers-duplicated" => { default => 0, parent => "headers", description => "duplicated function declarations checking" }, + "headers-misplaced" => { default => 0, parent => "headers", description => "misplaced function declarations checking" }, "stubs" => { default => 0, parent => "global", description => "stubs checking" } ); @@ -106,6 +109,8 @@ sub new { my $module = \${$self->{MODULE}}; my $global = \${$self->{GLOBAL}}; + my @files; + if($wine_dir eq ".") { $$global = 1; } else { @@ -151,8 +156,16 @@ sub new { if(defined($option)) { my $key = $$option{key}; my $parser = $$option{parser}; - my $parent = $$option{parent}; my $refvalue = \${$self->{$key}}; + my @parents = (); + + if(defined($$option{parent})) { + if(ref($$option{parent}) eq "ARRAY") { + @parents = @{$$option{parent}}; + } else { + @parents = $$option{parent}; + } + } if(defined($parser)) { $$refvalue = &$parser($prefix,$value); @@ -167,12 +180,23 @@ sub new { } if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) { - while(defined($parent)) { - my $parentkey = $options{$parent}{key}; - my $refparentvalue = \${$self->{$parentkey}}; - - $$refparentvalue = 1; - $parent = $options{$parent}{parent}; + while($#parents >= 0) { + my @old_parents = @parents; + @parents = (); + foreach my $parent (@old_parents) { + my $parentkey = $options{$parent}{key}; + my $refparentvalue = \${$self->{$parentkey}}; + + $$refparentvalue = 1; + + if(defined($options{$parent}{parent})) { + if(ref($options{$parent}{parent}) eq "ARRAY") { + push @parents, @{$options{$parent}{parent}}; + } else { + push @parents, $options{$parent}{parent}; + } + } + } } } next; @@ -201,7 +225,7 @@ sub new { return undef; } - push @$c_files, $_; + push @files, $_; } } @@ -209,30 +233,56 @@ sub new { return $self; } - my $c_paths; - if($#$c_files == -1 || ($#$c_files == 0 && $$c_files[0] eq $wine_dir)) { - $c_paths = "."; + my @paths = (); + my @c_files = (); + my @h_files = (); + foreach my $file (@files) { + if($file =~ /\.c$/) { + push @c_files, $file; + } elsif($file =~ /\.h$/) { + push @h_files, $file; + } else { + push @paths, $file; + } + } + + if($#c_files == -1 && $#h_files == -1 && + ($#paths == -1 || ($#paths == 0 && $paths[0] eq $wine_dir))) + { + @paths = "."; + push @h_files, "$wine_dir/include"; } else { - $c_paths = join(" ", @$c_files); $$global = 0; } - my $h_paths = "$wine_dir/include $wine_dir/include/wine"; + if($#paths != -1 || $#c_files != -1) { + my $c_command = "find " . join(" ", @paths, @c_files) . " -name \\*.c"; + my %found; + @$c_files = sort(map { + s/^\.\/(.*)$/$1/; + if(defined($found{$_}) || /glue\.c|spec\.c$/) { + (); + } else { + $found{$_}++; + $_; + } + } split(/\n/, `$c_command`)); + } - @$c_files = sort(map { - s/^.\/(.*)$/$1/; - if(/glue\.c|spec\.c$/) { - (); - } else { - $_; - } - } split(/\n/, `find $c_paths -name \\*.c`)); - - @$h_files = sort(map { - s/^.\/(.*)$/$1/; - $_; - } split(/\n/, `find $h_paths -name \\*.h`)); + if($#h_files != -1) { + my $h_command = "find " . join(" ", @h_files) . " -name \\*.h"; + my %found; + @$h_files = sort(map { + s/^\.\/(.*)$/$1/; + if(defined($found{$_})) { + (); + } else { + $found{$_}++; + $_; + } + } split(/\n/, `$h_command`)); + } return $self; }