|  | #!/usr/bin/perl -w | 
|  |  | 
|  | # 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; | 
|  |  | 
|  | 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 "modules.pm"; | 
|  | require "nativeapi.pm"; | 
|  | require "output.pm"; | 
|  | require "preprocessor.pm"; | 
|  | require "winapi.pm"; | 
|  | require "winapi_documentation.pm"; | 
|  | require "winapi_function.pm"; | 
|  | require "winapi_local.pm"; | 
|  | require "winapi_global.pm"; | 
|  | require "winapi_options.pm"; | 
|  | require "winapi_parser.pm"; | 
|  |  | 
|  | import modules; | 
|  | import nativeapi; | 
|  | import output; | 
|  | import preprocessor; | 
|  | import winapi; | 
|  | import winapi_documentation; | 
|  | import winapi_function; | 
|  | import winapi_local; | 
|  | import winapi_global; | 
|  | import winapi_options; | 
|  | import winapi_parser; | 
|  | } | 
|  |  | 
|  | my $current_dir = "."; | 
|  | if(length($wine_dir) != 1) { | 
|  | my $pwd; chomp($pwd = `pwd`); | 
|  | foreach my $n (1..((length($wine_dir) + 1) / 3)) { | 
|  | $pwd =~ s/\/([^\/]*)$//; | 
|  | $current_dir = "$1/$current_dir"; | 
|  | } | 
|  | $current_dir =~ s/\/.$//; | 
|  | } | 
|  |  | 
|  | my $output = 'output'->new; | 
|  |  | 
|  | my $options = winapi_options->new($output, \@ARGV, $wine_dir); | 
|  | if(!defined($options)) { | 
|  | $output->write("usage: winapi_check [--help] [<files>]\n"); | 
|  |  | 
|  | exit 1; | 
|  | } elsif($options->help) { | 
|  | $options->show_help; | 
|  | exit; | 
|  | } | 
|  |  | 
|  | sub file_type { | 
|  | my $file = shift; | 
|  |  | 
|  | my $file_dir = $file; | 
|  | if(!($file_dir =~ s/^(.*?)\/[^\/]*$/$1/)) { | 
|  | $file_dir = "."; | 
|  | } | 
|  |  | 
|  | $file_dir =~ s/^$wine_dir\///; | 
|  |  | 
|  | if($file_dir =~ /^(libtest|program|rc|tests|tools)/ || | 
|  | $file =~ /dbgmain\.c$/ || | 
|  | $file =~ /wineclipsrv\.c$/) # FIXME: Kludge | 
|  | { | 
|  | return "application"; | 
|  | } elsif($file_dir =~ /^(debug|miscemu)/) { | 
|  | return "emulator"; | 
|  | } else { | 
|  | return "library"; | 
|  | } | 
|  | } | 
|  |  | 
|  | my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat"); | 
|  |  | 
|  | 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); | 
|  | } else { | 
|  | my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir); | 
|  | 'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api); | 
|  | } | 
|  |  | 
|  | my $nativeapi = 'nativeapi'->new($options, $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 "$file_dir/../$header") { # FIXME: This is not correct | 
|  | $includes{$file}{includes}{"$file_dir/../$header"}++; # FIXME: This is not correct | 
|  | } elsif(-e "$wine_dir/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", | 
|  | "storage.h", "ver.h"); | 
|  | foreach my $file2 (@files2) { | 
|  | $includes{"include/$file2"}{used}++; | 
|  | } | 
|  | } | 
|  |  | 
|  | my %declared_functions; | 
|  |  | 
|  | my $progress_output; | 
|  | my $progress_current=0; | 
|  | 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 $internal_name = shift; | 
|  | my $refargument_types = shift; | 
|  | my @argument_types = @$refargument_types; | 
|  | my $refargument_names = shift; | 
|  | my @argument_names = @$refargument_names; | 
|  | my $refargument_documentations = shift; | 
|  | my @argument_documentations = @$refargument_documentations; | 
|  | my $statements = shift; | 
|  |  | 
|  | 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 { | 
|  | my $directive = shift; | 
|  | my $argument = shift; | 
|  | }; | 
|  |  | 
|  | winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor; | 
|  | } | 
|  | } | 
|  |  | 
|  | my %module_pseudo_stub_count16; | 
|  | my %module_pseudo_stub_count32; | 
|  |  | 
|  | foreach my $file ($options->c_files) { | 
|  | my %functions = (); | 
|  |  | 
|  | my $file_module16 = $modules->allowed_modules_in_file("$current_dir/$file"); | 
|  | my $file_module32 = $modules->allowed_modules_in_file("$current_dir/$file"); | 
|  |  | 
|  | $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 = file_type($file); | 
|  |  | 
|  | my $found_function = sub { | 
|  | my $documentation = shift; | 
|  | my $linkage = shift; | 
|  | my $return_type = shift; | 
|  | my $calling_convention = shift; | 
|  | my $internal_name = shift; | 
|  | my $refargument_types = shift; | 
|  | my @argument_types = @$refargument_types; | 
|  | my $refargument_names = shift; | 
|  | my @argument_names = @$refargument_names; | 
|  | my $refargument_documentations = shift; | 
|  | my @argument_documentations = @$refargument_documentations; | 
|  | 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; | 
|  | for my $argument (@argument_types) { | 
|  | $win16api->found_type($argument) if $options->win16; | 
|  | $win32api->found_type($argument) if $options->win32; | 
|  | } | 
|  |  | 
|  | $win16api->found_function($internal_name) if $options->win16; | 
|  | $win32api->found_function($internal_name) if $options->win32; | 
|  | } | 
|  |  | 
|  | if($file_type ne "application") { | 
|  | my $module16 = $win16api->function_module($internal_name); | 
|  | my $module32 = $win32api->function_module($internal_name); | 
|  |  | 
|  | if(defined($module16)) { | 
|  | $modules->found_module_in_dir($module16, $file_dir); | 
|  | } | 
|  | if(defined($module32)) { | 
|  | $modules->found_module_in_dir($module32, $file_dir); | 
|  | } | 
|  |  | 
|  | my $function = 'winapi_function'->new; | 
|  | $functions{$internal_name} = $function; | 
|  |  | 
|  | $function->documentation($documentation); | 
|  | $function->linkage($linkage); | 
|  | $function->file($file); | 
|  | $function->return_type($return_type); | 
|  | $function->calling_convention($calling_convention); | 
|  | $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]); | 
|  | $function->argument_documentations([@argument_documentations]); | 
|  | $function->statements($statements); | 
|  | $function->module16($module16); | 
|  | $function->module32($module32); | 
|  |  | 
|  | my $prefix = ""; | 
|  | $prefix .= "$file: "; | 
|  | if(defined($module16) && !defined($module32)) { | 
|  | $prefix .= "$module16: "; | 
|  | } elsif(!defined($module16) && defined($module32)) { | 
|  | $prefix .= "$module32: "; | 
|  | } elsif(defined($module16) && defined($module32)) { | 
|  | $prefix .= "$module16 & $module32: "; | 
|  | } else { | 
|  | $prefix .= "<>: "; | 
|  | } | 
|  | $prefix .= "$return_type "; | 
|  | $prefix .= "$calling_convention " if $calling_convention; | 
|  | $prefix .= "$internal_name(" . join(",", @argument_types) . "): "; | 
|  | $output->prefix($prefix); | 
|  |  | 
|  | if($options->local && $options->misplaced && | 
|  | $linkage ne "extern" && $statements) | 
|  | { | 
|  | if($options->win16 && $options->report_module($module16)) { | 
|  | my $match = 0; | 
|  | foreach my $module (split(/ & /, $module16)) { | 
|  | foreach my $file_module (split(/ & /, $file_module16)) { | 
|  | if($module eq $file_module) { | 
|  | $match++; | 
|  | } | 
|  | } | 
|  | } | 
|  | if(!$match && $file ne "library/port.c" && !$nativeapi->is_function($internal_name)) { | 
|  | $output->write("is misplaced\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if($options->win32 && $options->report_module($module32)) { | 
|  | my $match = 0; | 
|  | foreach my $module (split(/ & /, $module32)) { | 
|  | foreach my $file_module (split(/ & /, $file_module32)) { | 
|  | if($module eq $file_module) { | 
|  | $match++; | 
|  | } | 
|  | } | 
|  | } | 
|  | if(!$match && $file ne "library/port.c" && !$nativeapi->is_function($internal_name)) { | 
|  | $output->write("is misplaced\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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)?$/)) | 
|  | { | 
|  | $output->write("no prototype\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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+)$/)) | 
|  | { | 
|  | $output->write("no prototype\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if($options->local && $options->argument) { | 
|  | if($options->win16 && $options->report_module($module16)) { | 
|  | winapi_local::check_function $options, $output, | 
|  | $return_type, $calling_convention, $external_name16, $internal_name, [@argument_types], $nativeapi, $win16api; | 
|  | } | 
|  | if($options->win32 && $options->report_module($module32)) { | 
|  | winapi_local::check_function $options, $output, | 
|  | $return_type, $calling_convention, $external_name32, $internal_name, [@argument_types], $nativeapi, $win32api; | 
|  | } | 
|  | } | 
|  |  | 
|  | if($options->local && $options->statements) { | 
|  | if($options->win16 && $options->report_module($module16)) { | 
|  | winapi_local::check_statements $options, $output, $win16api, \%functions, $function; | 
|  | } | 
|  |  | 
|  | if($options->win32 && $options->report_module($module32)) { | 
|  | winapi_local::check_statements $options, $output, $win32api, \%functions, $function; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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->local && $options->documentation && | 
|  | (defined($module16) || defined($module32)) && | 
|  | $linkage ne "extern" && $statements) | 
|  | { | 
|  | winapi_documentation::check_documentation $options, $output, $win16api, $win32api, $function; | 
|  | } | 
|  | $output->prefix(""); | 
|  | } | 
|  | }; | 
|  |  | 
|  | my $config = 0; | 
|  | my $conditional = 0; | 
|  | my $found_include = sub { | 
|  | local $_ = shift; | 
|  | if(/^\"config\.h\"/) { | 
|  | $config++; | 
|  | } | 
|  | }; | 
|  | my $found_conditional = sub { | 
|  | local $_ = shift; | 
|  |  | 
|  | $nativeapi->found_conditional($_); | 
|  |  | 
|  | if($options->config) { | 
|  | if($file_type ne "application") { | 
|  | if(!$nativeapi->is_conditional($_)) { | 
|  | if(/^HAVE_/ && !/^HAVE_(IPX|MESAGL|BUGGY_MESAGL|WINE_CONSTRUCTOR)$/) | 
|  | { | 
|  | $output->write("$file: $_ is not 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") { | 
|  | my $header; | 
|  | my $check_protection; | 
|  | my $check_local; | 
|  | if($argument =~ /^<(.*?)>$/) { | 
|  | $header = $1; | 
|  | if($file_type ne "application") { | 
|  | $check_protection = 1; | 
|  | } else { | 
|  | $check_protection = 0; | 
|  | } | 
|  | $check_local = 0; | 
|  | } elsif($argument =~ /^"(.*?)"$/) { | 
|  | $header = $1; | 
|  | $check_protection = 0; | 
|  | $check_local = 1; | 
|  | } | 
|  |  | 
|  | if($check_protection) { | 
|  | if((-e "$wine_dir/include/$header" || -e "$file_dir/$header")) { | 
|  | if($header !~ /^ctype.h$/) { | 
|  | $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/) { | 
|  | # Do nothing X Windows is handled differently | 
|  | } 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"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if($check_local) { | 
|  | if(-e "$file_dir/$header") { | 
|  | $includes{"$file_dir/$header"}{used}++; | 
|  | foreach my $name (keys(%{$includes{"$file_dir/$header"}{includes}})) { | 
|  | $includes{$name}{used}++; | 
|  | } | 
|  | } elsif(-e "$file_dir/../$header") { # FIXME: Kludge | 
|  | $includes{"$file_dir/../$header"}{used}++; # FIXME: This is not correct | 
|  | foreach my $name (keys(%{$includes{"$file_dir/../$header"}{includes}})) { # FIXME: This is not correct | 
|  | $includes{$name}{used}++; | 
|  | } | 
|  | } elsif($header eq "controls.h") { # FIXME: Kludge | 
|  | $includes{"dlls/user/$header"}{used}++; | 
|  | foreach my $name (keys(%{$includes{"dlls/user/$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) { | 
|  | winapi_documentation::report_documentation $options, $output; | 
|  |  | 
|  | 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 ($win16api->all_modules) { | 
|  | 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(!defined($total)) { $total = 0;} | 
|  |  | 
|  | $output->write("*.c: $module: "); | 
|  | $output->write("$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 ($win32api->all_modules) { | 
|  | 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(!defined($total)) { $total = 0;} | 
|  |  | 
|  | $output->write("*.c: $module: "); | 
|  | $output->write("$stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if($options->headers) { | 
|  | foreach my $name (sort(keys(%includes))) { | 
|  | if(!$includes{$name}{used}) { | 
|  | if($options->include) { | 
|  | $output->write("*.c: $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; | 
|  |  | 
|  | $modules->global_report; | 
|  | $nativeapi->global_report; | 
|  | } |