- 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:
parent
11353fcb6c
commit
f93f998e8c
|
@ -145,6 +145,10 @@ files
|
|||
|
||||
dlls/ole32
|
||||
|
||||
% dlls/ole32/ole2nls.spec
|
||||
|
||||
dlls/ole32
|
||||
|
||||
% dlls/ole32/ole32.spec
|
||||
|
||||
dlls/ole32
|
||||
|
|
|
@ -7,7 +7,6 @@ LCID
|
|||
%long # --forbidden
|
||||
|
||||
int
|
||||
unsigned
|
||||
|
||||
%ptr
|
||||
|
||||
|
@ -19,6 +18,10 @@ IUnknown *
|
|||
REFCLSID
|
||||
char *
|
||||
|
||||
%ptr # --forbidden
|
||||
|
||||
unsigned long *
|
||||
|
||||
%segstr
|
||||
|
||||
BSTR16
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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 *
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
BOOL
|
||||
BOOLEAN
|
||||
DIGEST_HANDLE
|
||||
DWORD
|
||||
HANDLE
|
||||
HMODULE
|
||||
|
@ -13,6 +12,7 @@ WORD
|
|||
%ptr
|
||||
|
||||
DIGEST_FUNCTION
|
||||
DIGEST_HANDLE
|
||||
LPDWORD
|
||||
LPSYSTEMTIME
|
||||
LPVOID
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,7 +34,7 @@ WORD
|
|||
|
||||
int
|
||||
short
|
||||
unsigned
|
||||
unsigned int
|
||||
|
||||
%ptr
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
%long
|
||||
|
||||
HRESULT
|
||||
|
||||
%ptr
|
||||
|
||||
DLLVERSIONINFO *
|
|
@ -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}};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" },
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue