- Check for missing modules in modules.dat.

- New options --debug-messages for debug message checking (turned off
  by default)
- Do not discard the argument name (use in debug message checking)
- Improved parsing
- Minor bug fixes
This commit is contained in:
Patrik Stridvall 2000-05-11 21:46:17 +00:00 committed by Alexandre Julliard
parent 11353fcb6c
commit f93f998e8c
15 changed files with 240 additions and 52 deletions

View File

@ -145,6 +145,10 @@ files
dlls/ole32
% dlls/ole32/ole2nls.spec
dlls/ole32
% dlls/ole32/ole32.spec
dlls/ole32

View File

@ -7,7 +7,6 @@ LCID
%long # --forbidden
int
unsigned
%ptr
@ -19,6 +18,10 @@ IUnknown *
REFCLSID
char *
%ptr # --forbidden
unsigned long *
%segstr
BSTR16

View File

@ -9,7 +9,6 @@ HCRYPTKEY
HKEY
LONG
NTSTATUS
PHANDLE
POLICY_INFORMATION_CLASS
REGSAM
SC_HANDLE
@ -50,6 +49,7 @@ PACL
PACL *
PDWORD
PGENERIC_MAPPING
PHANDLE
PLSA_HANDLE
PLSA_OBJECT_ATTRIBUTES
PLSA_REFERENCED_DOMAIN_LIST *

View File

@ -16,7 +16,8 @@ time_t
int
long
unsigned
unsigned int
unsigned long
%ptr
@ -44,6 +45,7 @@ struct find_t *
struct stat *
struct win_stat *
time_t *
unsigned char *
va_list
void *

View File

@ -2,7 +2,6 @@
BOOL
BOOLEAN
DIGEST_HANDLE
DWORD
HANDLE
HMODULE
@ -13,6 +12,7 @@ WORD
%ptr
DIGEST_FUNCTION
DIGEST_HANDLE
LPDWORD
LPSYSTEMTIME
LPVOID

View File

@ -20,7 +20,6 @@ INT
LANGID
LCID
LONG
PHANDLE
UINT
WCHAR
WORD
@ -121,12 +120,13 @@ OFSTRUCT *
OSVERSIONINFOA *
OSVERSIONINFOW *
PAPCFUNC
PDWORD
PEXCEPTION_POINTERS
PHANDLE
PLARGE_INTEGER
PLONG
PTIMERAPCROUTINE
PULARGE_INTEGER
PDWORD
PVOID
PVOID *
SECURITY_ATTRIBUTES *

View File

@ -15,7 +15,6 @@ KEY_VALUE_INFORMATION_CLASS
LONG
NTSTATUS
OBJECT_INFORMATION_CLASS
PHANDLE
PROCESSINFOCLASS
SECTION_INHERIT
SECURITY_IMPERSONATION_LEVEL
@ -32,7 +31,7 @@ WCHAR
%long # --forbidden
int
unsigned
unsigned int
%longlong
@ -65,6 +64,7 @@ PDWORD
PEXCEPTION_FRAME
PEXCEPTION_RECORD
PGENERIC_MAPPING
PHANDLE
PIMAGE_NT_HEADERS
PIO_APC_ROUTINE
PIO_STATUS_BLOCK

View File

@ -34,7 +34,7 @@ WORD
int
short
unsigned
unsigned int
%ptr

View File

@ -0,0 +1,7 @@
%long
HRESULT
%ptr
DLLVERSIONINFO *

View File

@ -41,11 +41,13 @@ sub parse_api_file {
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
my $type_format = \%{$self->{TYPE_FORMAT}};
my $file = shift;
my $module = shift;
my $kind;
my $format;
my $extension = 0;
my $forbidden = 0;
@ -62,6 +64,7 @@ sub parse_api_file {
if(s/^%(\S+)\s*//) {
$kind = $1;
$format = undef;
$forbidden = 0;
$extension = 0;
@ -70,6 +73,36 @@ sub parse_api_file {
$forbidden = 1;
} elsif(/^--extension/) {
$extension = 1;
} elsif(/^--format=(\".*?\"|\S*)/) {
$format = $1;
$format =~ s/^\"(.*?)\"$/$1/;
}
if(!defined($format)) {
if($kind eq "long") {
$format = "%d|%u|%x|%X|";
$format .= "%hd|%hu|%hx|%hX|";
$format .= "%ld|%lu|%lx|%lX|";
$format .= "%04x|%04X|0x%04x|0x%04X|";
$format .= "%08x|%08X|0x%08x|0x%08X|";
$format .= "%08lx|%08lX|0x%08lx|0x%08lX";
} elsif($kind eq "longlong") {
$format = "%lld";
} elsif($kind eq "ptr") {
$format = "%p";
} elsif($kind eq "segptr") {
$format = "%p";
} elsif($kind eq "str") {
$format = "%p|%s";
} elsif($kind eq "wstr") {
$format = "%p|%s";
} elsif($kind eq "word") {
$format = "%d|%u|%x|%X|";
$format .= "%hd|%hu|%hx|%hX|";
$format .= "%04x|%04X|0x%04x|0x%04X";
} else {
$format = "<unknown>";
}
}
} elsif(defined($kind)) {
my $type = $_;
@ -94,6 +127,8 @@ sub parse_api_file {
} else {
$$translate_argument{$type} = $kind;
}
$$type_format{$module}{$type} = $format;
} else {
$$output->write("$file: file must begin with %<type> statement\n");
exit 1;
@ -437,6 +472,42 @@ sub type_found {
return $$type_found{$name};
}
sub is_allowed_type_format {
my $self = shift;
my $type_format = \%{$self->{TYPE_FORMAT}};
my $module = shift;
my $type = shift;
my $format = shift;
my $formats;
if(defined($module) && defined($type)) {
local $_;
foreach (split(/ & /, $module)) {
if(defined($formats)) {
$formats .= "|";
} else {
$formats = "";
}
if(defined($$type_format{$_}{$type})) {
$formats .= $$type_format{$_}{$type};
}
}
}
if(defined($formats)) {
local $_;
foreach (split(/\|/, $formats)) {
if($_ eq $format) {
return 1;
}
}
}
return 0;
}
sub all_modules {
my $self = shift;
my $modules = \%{$self->{MODULES}};

View File

@ -222,14 +222,16 @@ foreach my $file ($options->c_files) {
my $calling_convention = shift;
my $internal_name = shift;
my $external_name = $internal_name;
my $refarguments = shift;
my @arguments = @$refarguments;
my $refargument_types = shift;
my @argument_types = @$refargument_types;
my $refargument_names = shift;
my @argument_names = @$refargument_names;
my $statements = shift;
if($options->global) {
$win16api->found_type($return_type) if $options->win16;
$win32api->found_type($return_type) if $options->win32;
for my $argument (@arguments) {
for my $argument (@argument_types) {
$win16api->found_type($argument) if $options->win16;
$win32api->found_type($argument) if $options->win32;
}
@ -285,7 +287,8 @@ foreach my $file ($options->c_files) {
$function->calling_convention($calling_convention);
$function->external_name($external_name);
$function->internal_name($internal_name);
$function->arguments([@arguments]);
$function->argument_types([@argument_types]);
$function->argument_names([@argument_names]);
$function->statements($statements);
$function->module16($module16);
$function->module32($module32);
@ -296,7 +299,7 @@ foreach my $file ($options->c_files) {
my $msg = shift;
$output->write("$file: $module: $return_type ");
$output->write("$calling_convention ") if $calling_convention;
$output->write("$internal_name(" . join(",", @arguments) . "): $msg\n");
$output->write("$internal_name(" . join(",", @argument_types) . "): $msg\n");
}
};
my $output16 = &$output_module($module16);
@ -348,31 +351,21 @@ foreach my $file ($options->c_files) {
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, [@arguments], $win16api;
$return_type, $calling_convention, $external_name, $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, [@arguments], $win32api;
$return_type, $calling_convention, $external_name, $internal_name, [@argument_types], $win32api;
}
}
if($options->local && $options->cross_call) {
local $_ = $statements;
my $called_function_names = {};
while(defined($_)) {
if(/(\w+)\((.*?)\)/) {
$_ = $';
my $called_name = $1;
if($called_name !~ /^if|for|while|switch|sizeof$/) {
$functions{$internal_name}->function_called($called_name);
if(!defined($functions{$called_name})) {
$functions{$called_name} = 'winapi_function'->new;
}
$functions{$called_name}->function_called_by($internal_name);
}
} else {
undef $_
}
if($options->local && $options->statements) {
if($options->win16 && $options->report_module($module16)) {
winapi_local::check_statements $options, $output16, $win16api, \%functions, $function;
}
if($options->win32 && $options->report_module($module32)) {
winapi_local::check_statements $options, $output32, $win32api, \%functions, $function;
}
}

View File

@ -88,15 +88,26 @@ sub internal_name {
return $$internal_name;
}
sub arguments {
sub argument_types {
my $self = shift;
my $arguments = \${$self->{ARGUMENTS}};
my $argument_types = \${$self->{ARGUMENT_TYPES}};
local $_ = shift;
if(defined($_)) { $$arguments = $_; }
if(defined($_)) { $$argument_types = $_; }
return $$arguments;
return $$argument_types;
}
sub argument_names {
my $self = shift;
my $argument_names = \${$self->{ARGUMENT_NAMES}};
local $_ = shift;
if(defined($_)) { $$argument_names = $_; }
return $$argument_names;
}
sub module16 {

View File

@ -173,6 +173,78 @@ sub check_function {
}
}
sub check_statements {
my $options = shift;
my $output = shift;
my $winapi = shift;
my $functions = shift;
my $function = shift;
my $module = $function->module;
my $internal_name = $function->internal_name;
my $first_debug_message = 1;
local $_ = $function->statements;
while(defined($_)) {
if(s/(\w+)\s*(?:\(\s*(\w+)\s*\))?\s*\(\s*((?:\"[^\"]*\"|\([^\)]*\)|[^\)])*?)\s*\)//) {
my $called_name = $1;
my $channel = $2;
my $called_arguments = $3;
if($called_name =~ /^if|for|while|switch|sizeof$/) {
# Nothing
} elsif($called_name =~ /^ERR|FIXME|MSG|TRACE|WARN$/) {
if($first_debug_message && $called_name =~ /^FIXME|TRACE$/) {
$first_debug_message = 0;
if($called_arguments =~ /^\"\((.*?)\)(.*?)\"\s*,\s*(.*?)$/) {
my $formating = $1;
my $extra = $2;
my $arguments = $3;
my $format;
my $argument;
my $n = 0;
while($formating && ($formating =~ s/^([^,]*),?//, $format = $1, $format =~ s/^\s*(.*?)\s*$/$1/) &&
$arguments && ($arguments =~ s/^([^,]*),?//, $argument = $1, $argument =~ s/^\s*(.*?)\s*$/$1/))
{
my $type = @{$function->argument_types}[$n];
my $name = @{$function->argument_names}[$n];
$n++;
if(!defined($type)) { last; }
$format =~ s/^\w+\s*[:=]?\s*//;
$format =~ s/\s*\{[^\{\}]*\}$//;
$format =~ s/\s*\[[^\[\]]*\]$//;
$format =~ s/^\'(.*?)\'$/$1/;
$format =~ s/^\\\"(.*?)\\\"$/$1/;
if($argument !~ /$name/) {
&$output("$called_name: argument $n is wrong ($name != '$argument')");
} elsif(!$winapi->is_allowed_type_format($module, $type, $format)) {
&$output("$called_name: argument $n ($type $name) has illegal format ($format)");
}
}
my $count = $#{$function->argument_types} + 1;
if($n != $count) {
&$output("$called_name: argument count mismatch ($n != $count)");
}
}
}
} else {
$$functions{$internal_name}->function_called($called_name);
if(!defined($$functions{$called_name})) {
$$functions{$called_name} = 'winapi_function'->new;
}
$$functions{$called_name}->function_called_by($internal_name);
}
} else {
undef $_;
}
}
}
sub check_file {
my $options = shift;
my $output = shift;

View File

@ -60,13 +60,15 @@ my %options = (
},
"calling-convention" => { default => 0, parent => "local", description => "calling convention checking" },
"misplaced" => { default => 1, parent => "local", description => "check for misplaced functions" },
"cross-call" => { default => 0, parent => "local", description => "check for cross calling 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-win32-win16" => {
default => 0, parent => "cross-call", description => "check for cross calls between win32 and win16"
},
"cross-call-unicode-ascii" => {
default => 0, parent => "cross-call", description => "check for cross calls between Unicode and ASCII"
},
"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" },

View File

@ -14,7 +14,8 @@ sub parse_c_file {
my $return_type;
my $calling_convention;
my $function = "";
my $arguments;
my $argument_types;
my $argument_names;
my $statements;
my $function_begin = sub {
@ -23,13 +24,20 @@ sub parse_c_file {
$return_type= shift;
$calling_convention = shift;
$function = shift;
$arguments = shift;
$argument_types = shift;
$argument_names = shift;
if($#$argument_names == -1) {
foreach my $n (0..$#$argument_types) {
push @$argument_names, "";
}
}
$statements = "";
};
my $function_end = sub {
&$function_found_callback($documentation,$linkage,$return_type,$calling_convention,$function,$arguments,$statements);
&$function_found_callback($documentation,$linkage,$return_type,$calling_convention,
$function,$argument_types,$argument_names,$statements);
$function = "";
};
@ -214,33 +222,48 @@ sub parse_c_file {
$arguments =~ s/^\s*(.*?)\s*$/$1/;
if($arguments eq "") { $arguments = "void" }
my @argument_types;
my @argument_names;
my @arguments = split(/,/, $arguments);
foreach my $n (0..$#arguments) {
my $argument_type = "";
my $argument_name = "";
my $argument = $arguments[$n];
$argument =~ s/^\s*(.*?)\s*$/$1/;
#print " " . ($n + 1) . ": '$argument'\n";
# print " " . ($n + 1) . ": '$argument'\n";
$argument =~ s/^(IN OUT(?=\s)|IN(?=\s)|OUT(?=\s)|\s*)\s*//;
$argument =~ s/^(const(?=\s)|CONST(?=\s)|\s*)\s*//;
if($argument =~ /^\.\.\.$/) {
$argument = "...";
} elsif($argument =~ /^((struct\s+|union\s+|enum\s+)?\w+)\s*((\*\s*?)*)\s*/) {
$argument = "$1";
if($3 ne "") {
$argument .= " $3";
$argument_type = "...";
$argument_name = "...";
} elsif($argument =~ /^((?:struct\s+|union\s+|enum\s+|(?:signed\s+|unsigned\s+)(?:short\s+(?=int)|long\s+(?=int))?)?\w+)\s*((?:const)?\s*(?:\*\s*?)*)\s*(?:WINE_UNUSED\s+)?(\w*)\s*(?:\[\]|\s+OPTIONAL)?/) {
$argument_type = "$1";
if($2 ne "") {
$argument_type .= " $2";
}
$argument_name = $3;
$argument_type =~ s/\s*const\s*/ /;
$argument_type =~ s/^\s*(.*?)\s*$/$1/;
$argument_name =~ s/^\s*(.*?)\s*$/$1/;
} else {
die "$file: $.: syntax error: '$argument'\n";
}
$arguments[$n] = $argument;
#print " " . ($n + 1) . ": '" . $arguments[$n] . "'\n";
$argument_types[$n] = $argument_type;
$argument_names[$n] = $argument_name;
# print " " . ($n + 1) . ": '" . $argument_types[$n] . "', '" . $argument_names[$n] . "'\n";
}
if($#argument_types == 0 && $argument_types[0] =~ /^void$/i) {
$#argument_types = -1;
$#argument_names = -1;
}
if($#arguments == 0 && $arguments[0] =~ /^void$/i) { $#arguments = -1; }
if($options->debug) {
print "$file: $return_type $calling_convention $name(" . join(",", @arguments) . ")\n";
}
&$function_begin($documentation,$linkage,$return_type,$calling_convention,$name,\@arguments);
&$function_begin($documentation,$linkage,$return_type,$calling_convention,$name,\@argument_types,\@argument_names);
if($level == 0) {
&$function_end;
}