Handle forwarded functions properly (based on a patch by Francois

Gouget).
oldstable
Patrik Stridvall 2002-07-22 20:37:30 +00:00 committed by Alexandre Julliard
parent 4ae5380cbb
commit 1932045ec0
3 changed files with 167 additions and 63 deletions

View File

@ -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 = <IN>;
@ -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";
}
########################################################################

View File

@ -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");
}
}
}
}

View File

@ -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" },
);