diff --git a/tools/winapi/winapi.pm b/tools/winapi/winapi.pm index 430680d1ce8..20c73479fee 100644 --- a/tools/winapi/winapi.pm +++ b/tools/winapi/winapi.pm @@ -74,12 +74,13 @@ sub new { $self->parse_api_file("$$name.api"); - foreach my $forward_name (sort(keys(%$function_forward))) { - $$function_forward{$forward_name} =~ /^(\S*):(\S*)\.(\S*)$/; - (my $from_module, my $to_module, my $external_name) = ($1, $2, $3); - my $internal_name = $$function_internal_name{$external_name}; - if(defined($internal_name)) { - $$function_module{$internal_name} .= " & $from_module"; + foreach my $module (sort(keys(%$function_forward))) { + foreach my $external_name (sort(keys(%{$$function_forward{$module}}))) { + (my $forward_module, my $forward_external_name) = @{$$function_forward{$module}{$external_name}}; + my $forward_internal_name = $$function_internal_name{$forward_external_name}; + if(defined($forward_internal_name)) { + $$function_module{$forward_internal_name} .= " & $module"; + } } } @@ -212,12 +213,12 @@ sub parse_spec_file { my $function_external_calling_convention = \%{$self->{FUNCTION_EXTERNAL_CALLING_CONVENTION}}; my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}}; my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}}; - my $function_stub = \%{$self->{FUNCTION_STUB}}; my $function_forward = \%{$self->{FUNCTION_FORWARD}}; my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}}; my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}}; my $modules = \%{$self->{MODULES}}; my $module_files = \%{$self->{MODULE_FILES}}; + my $module_external_calling_convention = \%{$self->{MODULE_EXTERNAL_CALLING_CONVENTION}}; my $file = shift; $file =~ s%^\./%%; @@ -230,6 +231,7 @@ sub parse_spec_file { $module = $file; $module =~ s/^.*?([^\/]*)\.spec$/$1/; + open(IN, "< $file") || die "$file: $!\n"; $/ = "\n"; my $header = 1; @@ -265,6 +267,11 @@ sub parse_spec_file { $arguments .= "ptr"; } + if($external_name ne "@") { + $$module_external_calling_convention{$module}{$external_name} = $calling_convention; + } else { + $$module_external_calling_convention{$module}{"\@$ordinal"} = $calling_convention; + } if(!$$function_internal_name{$external_name}) { $$function_internal_name{$external_name} = $internal_name; } else { @@ -338,7 +345,11 @@ sub parse_spec_file { my $internal_name = $external_name; - $$function_stub{$module}{$external_name} = 1; + if ($external_name ne "@") { + $$module_external_calling_convention{$module}{$external_name} = "stub"; + } else { + $$module_external_calling_convention{$module}{"\@$ordinal"} = "stub"; + } if(!$$function_internal_name{$external_name}) { $$function_internal_name{$external_name} = $internal_name; } else { @@ -376,8 +387,24 @@ sub parse_spec_file { my $forward_module = lc($3); my $forward_name = $4; - $$function_forward{$external_name} = "$module:$forward_module.$forward_name"; - } elsif(/^(\d+|@)\s+(equate|extern|variable)/) { + if ($external_name ne "@") { + $$module_external_calling_convention{$module}{$external_name} = "forward"; + } else { + $$module_external_calling_convention{$module}{"\@$ordinal"} = "forward"; + } + $$function_forward{$module}{$external_name} = [$forward_module, $forward_name]; + } elsif(/^(\d+|@)\s+extern\s+(\S+)\s+(\S+)$/) { + $ordinal = $1; + + my $external_name = $2; + my $internal_name = $3; + + if ($external_name ne "@") { + $$module_external_calling_convention{$module}{$external_name} = "extern"; + } else { + $$module_external_calling_convention{$module}{"\@$ordinal"} = "extern"; + } + } elsif(/^(\d+|@)\s+(equate|variable)/) { # ignore } else { my $next_line = ; @@ -638,20 +665,20 @@ sub all_internal_functions_in_module { sub all_external_functions { my $self = shift; - my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}}; + my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}}; - return sort(keys(%$function_internal_name)); + return sort(keys(%$function_external_name)); } sub all_external_functions_in_module { my $self = shift; - my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}}; + my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}}; my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}}; my $module = shift; my @names; - foreach my $name (keys(%$function_internal_name)) { + foreach my $name (keys(%$function_external_name)) { if($$function_external_module{$name} eq $module) { push @names, $name; } @@ -660,27 +687,36 @@ sub all_external_functions_in_module { return sort(@names); } -sub all_functions_stub { +sub all_functions_in_module { my $self = shift; - my $function_stub = \%{$self->{FUNCTION_STUB}}; - my $modules = \%{$self->{MODULES}}; - - my @stubs = (); - foreach my $module (keys(%$modules)) { - push @stubs, keys(%{$$function_stub{$module}}); - } - return sort(@stubs); -} - -sub all_functions_stub_in_module { - my $self = shift; - my $function_stub = \%{$self->{FUNCTION_STUB}}; + my $module_external_calling_convention = \%{$self->{MODULE_EXTERNAL_CALLING_CONVENTION}}; my $module = shift; - return sort(keys(%{$$function_stub{$module}})); + return sort(keys(%{$$module_external_calling_convention{$module}})); } +sub all_broken_forwards { + my $self = shift; + my $function_forward = \%{$self->{FUNCTION_FORWARD}}; + + my @broken_forwards = (); + foreach my $module (sort(keys(%$function_forward))) { + foreach my $external_name (sort(keys(%{$$function_forward{$module}}))) { + (my $forward_module, my $forward_external_name) = @{$$function_forward{$module}{$external_name}}; + + my $forward_external_calling_convention = + $self->function_external_calling_convention_in_module($forward_module, $forward_external_name); + + if(!defined($forward_external_calling_convention)) { + push @broken_forwards, [$module, $external_name, $forward_module, $forward_external_name]; + } + } + } + return @broken_forwards; +} + + sub function_internal_ordinal { my $self = shift; my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}}; @@ -717,6 +753,16 @@ sub function_external_calling_convention { return $$function_external_calling_convention{$name}; } +sub function_external_calling_convention_in_module { + my $self = shift; + my $module_external_calling_convention = \%{$self->{MODULE_EXTERNAL_CALLING_CONVENTION}}; + + my $module = shift; + my $name = shift; + + return $$module_external_calling_convention{$module}{$name}; +} + sub function_internal_name { my $self = shift; my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}}; @@ -735,6 +781,23 @@ sub function_external_name { return $$function_external_name{$name}; } +sub function_forward_final_destination { + my $self = shift; + + my $function_forward = \%{$self->{FUNCTION_FORWARD}}; + + my $module = shift; + my $name = shift; + + my $forward_module = $module; + my $forward_name = $name; + while(defined(my $forward = $$function_forward{$forward_module}{$forward_name})) { + ($forward_module, $forward_name) = @$forward; + } + + return ($forward_module, $forward_name); +} + sub is_function { my $self = shift; my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}}; @@ -807,14 +870,14 @@ sub function_external_module { sub is_function_stub { my $self = shift; - my $function_stub = \%{$self->{FUNCTION_STUB}}; + my $module_external_calling_convention = \%{$self->{MODULE_EXTERNAL_CALLING_CONVENTION}}; my $modules = \%{$self->{MODULES}}; my $module = shift; my $name = shift; foreach my $module (keys(%$modules)) { - if($$function_stub{$module}{$name}) { + if($$module_external_calling_convention{$module}{$name} eq "stub") { return 1; } } @@ -824,12 +887,15 @@ sub is_function_stub { sub is_function_stub_in_module { my $self = shift; - my $function_stub = \%{$self->{FUNCTION_STUB}}; + my $module_external_calling_convention = \%{$self->{MODULE_EXTERNAL_CALLING_CONVENTION}}; my $module = shift; my $name = shift; - return $$function_stub{$module}{$name}; + if(!defined($$module_external_calling_convention{$module}{$name})) { + return 0; + } + return $$module_external_calling_convention{$module}{$name} eq "stub"; } ######################################################################## diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract index 013a2d8dafe..ccf3bec2ae4 100755 --- a/tools/winapi/winapi_extract +++ b/tools/winapi/winapi_extract @@ -152,8 +152,7 @@ sub documentation_specifications { } } -my %module_pseudo_stub_count16; -my %module_pseudo_stub_count32; +my %module_pseudo_stub; sub statements_stub { my $function = shift; @@ -161,21 +160,26 @@ sub statements_stub { my $statements = $function->statements; if(defined($statements) && $statements =~ /FIXME[^;]*stub/s) { if($options->win16) { + my $external_name16 = $function->external_name16; foreach my $module16 ($function->modules16) { - $module_pseudo_stub_count16{$module16}++; + $module_pseudo_stub{$module16}{$external_name16}++; } } if($options->win32) { + my $external_name32 = $function->external_name32; foreach my $module32 ($function->modules32) { - $module_pseudo_stub_count32{$module32}++; + $module_pseudo_stub{$module32}{$external_name32}++; } } } } -my @c_files = $options->c_files; -@c_files = files_skip(@c_files); -@c_files = files_filter("winelib", @c_files); +my @c_files = (); +if($options->spec_files || $options->pseudo_stub_statistics) { + @c_files = $options->c_files; + @c_files = files_skip(@c_files); + @c_files = files_filter("winelib", @c_files); +} my $progress_output; my $progress_current = 0; @@ -391,37 +395,70 @@ if($options->stub_statistics) { if($type eq "win16" && !$options->win16) { next; } if($type eq "win32" && !$options->win32) { next; } - my %module_stub_count; - my %module_total_count; + my %module_counts; + foreach my $module ($winapi->all_modules) { + foreach my $external_name ($winapi->all_functions_in_module($module)) { + my $external_calling_convention = + $winapi->function_external_calling_convention_in_module($module, $external_name); + if($external_calling_convention !~ /^forward|stub$/) { + if($module_pseudo_stub{$module}{$external_name}) { + $external_calling_convention = "pseudo_stub"; + } + } elsif($external_calling_convention eq "forward") { + (my $forward_module, my $forward_external_name) = + $winapi->function_forward_final_destination($module, $external_name); - foreach my $internal_name ($winapi->all_internal_functions,$winapi->all_functions_stub) { - foreach my $module (split(/ \& /, $winapi->function_internal_module($internal_name))) { - if($winapi->is_function_stub_in_module($module, $internal_name)) { - $module_stub_count{$module}++; - } - $module_total_count{$module}++; - } - } + my $forward_external_calling_convention = + $winapi->function_external_calling_convention_in_module($forward_module, $forward_external_name); + + if(!defined($forward_external_calling_convention)) { + next; + } + + if($forward_external_calling_convention ne "stub" && + $module_pseudo_stub{$forward_module}{$forward_external_name}) + { + $forward_external_calling_convention = "pseudo_stub"; + } + + $external_calling_convention = "forward_$forward_external_calling_convention"; + } + + $module_counts{$module}{$external_calling_convention}++; + } + } foreach my $module ($winapi->all_modules) { - my $pseudo_stubs; - if($winapi->name eq "win16") { - $pseudo_stubs = $module_pseudo_stub_count16{$module}; - } elsif($winapi->name eq "win32") { - $pseudo_stubs = $module_pseudo_stub_count32{$module}; + my $pseudo_stubs = $module_counts{$module}{pseudo_stub} || 0; + my $real_stubs = $module_counts{$module}{stub} || 0; + my $forward_pseudo_stubs = $module_counts{$module}{forward_pseudo_stub} || 0; + my $forward_real_stubs = $module_counts{$module}{forward_stub} || 0; + + my $forwards = 0; + my $total = 0; + foreach my $calling_convention (keys(%{$module_counts{$module}})) { + my $count = $module_counts{$module}{$calling_convention}; + if($calling_convention =~ /^forward/) { + $forwards += $count; + } + $total += $count; } - my $real_stubs = $module_stub_count{$module}; - my $total = $module_total_count{$module}; + if($total > 0) { + my $stubs = $real_stubs + $pseudo_stubs; - if(!defined($real_stubs)) { $real_stubs = 0; } - if(!defined($pseudo_stubs)) { $pseudo_stubs = 0; } - if(!defined($total)) { $total = 0;} + $output->write("*.c: $module: "); + $output->write("$stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo) " . + "and $forwards are forwards\n"); + } - my $stubs = $real_stubs + $pseudo_stubs; + if($forwards > 0) { + my $forward_stubs = $forward_real_stubs + $forward_pseudo_stubs; - $output->write("*.c: $module: "); - $output->write("$stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n"); + $output->write("*.c: $module: "); + $output->write("$forward_stubs of $forwards forwarded functions are stubs " . + "($forward_real_stubs real, $forward_pseudo_stubs pseudo)\n"); + } } } } diff --git a/tools/winapi/winapi_extract_options.pm b/tools/winapi/winapi_extract_options.pm index d21ce9a6ea2..a63baa361b3 100644 --- a/tools/winapi/winapi_extract_options.pm +++ b/tools/winapi/winapi_extract_options.pm @@ -45,6 +45,7 @@ my %options_long = ( "spec-files" => { default => 0, parent => "global", description => "spec files extraction" }, "stub-statistics" => { default => 1, parent => "global", description => "stub statistics" }, + "pseudo-stub-statistics" => { default => 1, parent => "global", description => "pseudo stub statistics" }, "winetest" => { default => 1, parent => "global", description => "winetest extraction" }, );