Commit 5b3b6d98 authored by Patrik Stridvall's avatar Patrik Stridvall Committed by Alexandre Julliard

- Fixed the long long problem.

- Added configure include consistancy checking. - Added progress indicator. - Began splitting up the win16api.dat and win32api.dat files. - Added various minor checks. - Minor fixes.
parent d7da486c
......@@ -9,17 +9,59 @@ sub new {
bless ($self, $class);
my $functions = \%{$self->{FUNCTIONS}};
my $conditionals = \%{$self->{CONDITIONALS}};
my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
my $file = shift;
my $api_file = shift;
my $configure_in_file = shift;
my $config_h_in_file = shift;
open(IN, "< $file");
open(IN, "< $api_file");
$/ = "\n";
while(<IN>) {
s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
s/^(.*?)\s*#.*$/$1/; # remove comments
/^$/ && next; # skip empty lines
$$functions{$_} = 1;
$$functions{$_}++;
}
close(IN);
my $again = 0;
open(IN, "< $configure_in_file");
local $/ = "\n";
while($again || (defined($_ = <IN>))) {
$again = 0;
chomp;
if(/(.*)\\$/) {
my $line = <IN>;
if(defined($line)) {
$_ = $1 . " " . $line;
$again = 1;
next;
}
}
# remove leading and trailing whitespace
s/^\s*(.*?)\s*$/$1/;
if(/^AC_CHECK_HEADERS\(\s*(.*?)\)\s*$/) {
my @arguments = split(/,/,$1);
foreach my $header (split(/\s+/, $arguments[0])) {
$$conditional_headers{$header}++;
}
} elsif(/^AC_FUNC_ALLOCA/) {
$$conditional_headers{"alloca.h"}++;
}
}
close(IN);
open(IN, "< $config_h_in_file");
local $/ = "\n";
while(<IN>) {
if(/^\#undef (\S+)$/) {
$$conditionals{$1}++;
}
}
close(IN);
......@@ -35,4 +77,22 @@ sub is_function {
return $$functions{$name};
}
sub is_conditional {
my $self = shift;
my $conditionals = \%{$self->{CONDITIONALS}};
my $name = shift;
return $$conditionals{$name};
}
sub is_conditional_header {
my $self = shift;
my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
my $name = shift;
return $$conditional_headers{$name};
}
1;
package output;
use strict;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
$$progress = "";
$$last_progress = "";
return $self;
}
sub show_progress {
my $self = shift;
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
if($$progress) {
print STDERR $$progress;
$$last_progress = $$progress;
}
}
sub hide_progress {
my $self = shift;
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
if($$last_progress) {
my $message;
for (1..length($$last_progress)) {
$message .= " ";
}
print STDERR $message;
undef $$last_progress;
}
}
sub update_progress {
my $self = shift;
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
my $prefix = "";
for (1..length($$last_progress)) {
$prefix .= "";
}
my $suffix = "";
my $diff = length($$last_progress)-length($$progress);
if($diff > 0) {
for (1..$diff) {
$suffix .= " ";
}
for (1..$diff) {
$suffix .= "";
}
}
print STDERR $prefix . $$progress . $suffix;
$$last_progress = $$progress;
}
sub progress {
my $self = shift;
my $progress = \${$self->{PROGRESS}};
$$progress = shift;
$self->update_progress;
}
sub write {
my $self = shift;
my $last_progress = \${$self->{LAST_PROGRESS}};
my $message = shift;
$self->hide_progress;
print STDERR $message;
$self->show_progress;
}
1;
package preprocessor;
use strict;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $state = \%{$self->{STATE}};
my $stack = \@{$self->{STACK}};
my $include_found = \${$self->{INCLUDE_FOUND}};
my $conditional_found = \${$self->{CONDITIONAL_FOUND}};
$$include_found = shift;
$$conditional_found = shift;
return $self;
}
sub include {
my $self = shift;
my $include_found = \${$self->{INCLUDE_FOUND}};
my $argument = shift;
&$$include_found($argument);
}
sub define {
my $self = shift;
my $state = \%{$self->{STATE}};
my $conditional_found = \${$self->{CONDITIONAL_FOUND}};
my $name = shift;
$$state{$name} = "def";
&$$conditional_found($name);
}
sub undefine {
my $self = shift;
my $state = \%{$self->{STATE}};
my $conditional_found = \${$self->{CONDITIONAL_FOUND}};
my $name = shift;
$$state{$name} = "undef";
&$$conditional_found($name);
}
sub begin_if {
my $self = shift;
my $state = \%{$self->{STATE}};
my $stack = \@{$self->{STACK}};
my $directive = shift;
local $_ = shift;
while(!/^$/) {
if(/^0\s*\&\&/) {
$_ = "0";
} elsif(/^1\s*\|\|/) {
$_ = "1";
}
if(/^(!)?defined\s*\(\s*(.+?)\s*\)\s*((\&\&|\|\|)\s*)?/){
$_ = $';
if(defined($1) && $1 eq "!") {
$self->undefine($2);
push @$stack, $2;
} else {
$self->define($2);
push @$stack, $2;
}
} elsif(/^(\w+)\s*(<|<=|==|!=|>=|>)\s*(\w+)\s*((\&\&|\|\|)\s*)?/) {
$_ = $';
} elsif(/^(\w+)\s*$/) {
$_ = $';
} elsif(/^\(|\)/) {
$_ = $';
} else {
print "*** Can't parse '#$directive $_' ***\n";
$_ = "";
}
}
}
sub else_if {
my $self = shift;
my $state = \%{$self->{STATE}};
my $stack = \@{$self->{STACK}};
my $argument = shift;
$self->end_if;
if(defined($argument)) {
$self->begin_if("elif", $argument);
}
}
sub end_if {
my $self = shift;
my $state = \%{$self->{STATE}};
my $stack = \@{$self->{STACK}};
my $macro = pop @$stack;
delete $$state{$macro} if defined($macro);
}
sub directive {
my $self = shift;
my $state = \%{$self->{STATE}};
my $stack = \@{$self->{STACK}};
my $directive = shift;
my $argument = shift;
local $_ = $directive;
if(/^if$/) {
$self->begin_if("if",$argument);
} elsif(/^ifdef$/) {
$self->begin_if("if", "defined($argument)");
} elsif(/^ifndef$/) {
$self->begin_if("if", "!defined($argument)");
push @$stack, $argument;
} elsif(/^elif$/) {
$self->else_if($argument);
} elsif(/^else$/) {
$self->else_if;
} elsif(/^endif$/) {
$self->end_if;
} elsif(/^include/) {
$self->include($argument);
}
}
sub is_def {
my $self = shift;
my $state = \%{$self->{STATE}};
my $name = shift;
my $status = $$state{$name};
return defined($status) && $status eq "def";
}
sub is_undef {
my $self = shift;
my $state = \%{$self->{STATE}};
my $name = shift;
my $status = $$state{$name};
return defined($status) && $status eq "undef";
}
sub is_unknown {
my $self = shift;
my $state = \%{$self->{STATE}};
my $name = shift;
my $status = $$state{$name};
return !defined($status);
}
1;
......@@ -24,6 +24,7 @@ ULONG
%longlong
LARGE_INTEGER
ULARGE_INTEGER
%ptr
......@@ -157,6 +158,7 @@ LPPAINTSTRUCT16
LPPALETTEENTRY
LPPDEVICE
LPPOINT16
LPPRINTDLG16
LPQUEUESTRUCT16 *
LPRASTERIZER_STATUS
LPRECT16
......@@ -290,7 +292,6 @@ HANDLE16
HBITMAP16
HBRUSH16
HCURSOR16
HDC16
HDROP16
HDRVR16
HDWP16
......@@ -330,7 +331,7 @@ WING_DITHER_TYPE
WORD
WPARAM16
%unknown --forbidden
%unknown # --forbidden
BOOL
FARPROC
......
%ptr
AVICOMPRESSOPTIONS *
AVISTREAMINFOA *
AVISTREAMINFOW *
IAVIFile *
LPAVIFILEINFOA
LPAVIFILEINFOW
PAVIFILE
PAVIFILE *
PAVISTREAM
PAVISTREAM *
%long
COLORREF
HBITMAP
HDC
HICON
HWND
\ No newline at end of file
%long
HWND
\ No newline at end of file
%long
COLORREF
HBITMAP
HBRUSH
HCOLORSPACE
HDC
HENHMETAFILE
HFONT
HGDIOBJ
HMETAFILE
HPALETTE
HPEN
HRGN
HWND
%ptr
BITMAP *
BITMAPINFO *
BITMAPINFOHEADER *
%long
HWND
\ No newline at end of file
%long
HACMDRIVER
HACMDRIVERID
HACMOBJ
HACMSTREAM
%ptr
ACMDRIVERENUMCB
ACMFILTERENUMCBA
ACMFILTERENUMCBW
ACMFILTERTAGENUMCBA
ACMFILTERTAGENUMCBW
ACMFORMATENUMCBA
ACMFORMATENUMCBW
ACMFORMATTAGENUMCBA
ACMFORMATTAGENUMCBW
PACMDRIVERDETAILSA
PACMDRIVERDETAILSW
PACMFILTERCHOOSEA
PACMFILTERCHOOSEW
PACMFILTERDETAILSA
PACMFILTERDETAILSW
PACMFILTERTAGDETAILSA
PACMFILTERTAGDETAILSW
PACMFORMATCHOOSEA
PACMFORMATCHOOSEW
PACMFORMATDETAILSA
PACMFORMATDETAILSW
PACMFORMATTAGDETAILSA
PACMFORMATTAGDETAILSW
PACMSTREAMHEADER
PHACMDRIVER
PHACMDRIVERID
PHACMSTREAM
%long
HDC
HIC
HPALETTE
HWND
%long
CLIPFORMAT
HACCEL
HMENU
HWND
%ptr
CLIPFORMAT *
%long
HPALETTE
%ptr
COLORREF *
%long
HDC
\ No newline at end of file
%long
COLORREF
HBITMAP
HMENU
HICON
HWND
%long
HWND
\ No newline at end of file
%long
COLORREF
HACCEL
HBITMAP
HBRUSH
HCURSOR
HDC
HDESK
HFONT
HICON
HMENU
HMONITOR
HRGN
HWND
%ptr
COLORREF *
%long
HWND
\ No newline at end of file
%long
HWND
\ No newline at end of file
......@@ -13,8 +13,6 @@ BYTE
CALID
CALTYPE
CHAR
CLIPFORMAT
COLORREF
COORD
DATE
DIGEST_HANDLE
......@@ -25,44 +23,25 @@ FLOAT
FOURCC
FS_INFORMATION_CLASS
GET_FILEEX_INFO_LEVELS
HACCEL
HACMDRIVER
HACMDRIVERID
HACMOBJ
HACMSTREAM
HANDLE
HBITMAP
HBRUSH
HCALL
HCOLORSPACE
HCONV
HCONVLIST
HCURSOR
HCRYPTKEY
HDC
HDDEDATA
HDESK
HDROP
HDRVR
HDSA
HDWP
HENHMETAFILE
HFILE
HFONT
HGDIOBJ
HGLOBAL
HHOOK
HIC
HICON
HIMC
HINSTANCE
HKEY
HKL
HLINE
HLINEAPP
HLOCAL
HMENU
HMETAFILE
HMIDIIN
HMIDIOUT
HMIDISTRM
......@@ -70,23 +49,18 @@ HMIXER
HMIXEROBJ
HMMIO
HMODULE
HMONITOR
HOLEMENU
HPALETTE
HPEN
HPHONE
HPHONEAPP
HPROPSHEETPAGE
HPROVIDER
HRESULT
HRGN
HRSRC
HSZ
HTASK
HWAVEIN
HWAVEOUT
HWINSTA
HWND
INT
KEY_INFORMATION_CLASS
KEY_VALUE_INFORMATION_CLASS
......@@ -106,7 +80,6 @@ OLECLIPFORMAT
OLEOPT_RENDER
OLESTATUS
OLE_SERVER_USE
OUT
PHANDLE
PHPROVIDER
PIO_APC_ROUTINE
......@@ -117,6 +90,7 @@ POBJDIR_INFORMATION
PROCESSINFOCLASS
PTIME_FIELDS
PTOKEN_PRIVILEGES
REGKIND
REGSAM
SC_HANDLE
SECTION_INHERIT
......@@ -150,37 +124,21 @@ time_t
LARGE_INTEGER
POINT
ULARGE_INTEGER
%ptr
ABORTPROC
ACMDRIVERENUMCB
ACMFILTERENUMCBA
ACMFILTERENUMCBW
ACMFILTERTAGENUMCBA
ACMFILTERTAGENUMCBW
ACMFORMATENUMCBA
ACMFORMATENUMCBW
ACMFORMATTAGENUMCBA
ACMFORMATTAGENUMCBW
AVICOMPRESSOPTIONS *
AVISTREAMINFOA *
AVISTREAMINFOW *
BITMAP *
BITMAPINFO *
BITMAPINFOHEADER *
BOOL *
BSTR *
BYTE *
BY_HANDLE_FILE_INFORMATION *
CALINFO_ENUMPROCA
CHAR *
CLIPFORMAT *
CLSID *
CODEPAGE_ENUMPROCA
CODEPAGE_ENUMPROCW
COLORADJUSTMENT *
COLORREF *
CONST
CONTEXT *
COSERVERINFO *
......@@ -238,6 +196,7 @@ HMENU *
HMIDIIN *
HMIDIOUT *
HMIDISTRM *
HMODULE *
HMRU
HOOKPROC
HPCSTR
......@@ -254,6 +213,8 @@ IDropTarget *
ILockBytes *
IMAGEINFO *
IMAGELISTDRAWPARAMS *
IMoniker *
IMoniker **
INPUT_RECORD *
INT *
IPersistStream *
......@@ -283,8 +244,6 @@ LPACCEL
LPAUTHDLGSTRUCTA
LPAUXCAPSA
LPAUXCAPSW
LPAVIFILEINFOA
LPAVIFILEINFOW
LPBC *
LPBITMAPINFOHEADER
LPBOOL
......@@ -327,6 +286,7 @@ LPCWSTR *
LPDATAADVISEHOLDER *
LPDATAOBJECT
LPDCB
LPDCB *
LPDDENUMCALLBACKA
LPDDENUMCALLBACKEXA
LPDDENUMCALLBACKEXW
......@@ -434,8 +394,10 @@ LPMIXERLINECONTROLSW
LPMIXERLINEW
LPMMCKINFO
LPMMIOPROC
LPMMIOPROC16
LPMMTIME
LPMODULEENTRY
LPMODULEINFO
LPMONIKER
LPMONIKER *
LPMONITORINFO
......@@ -579,31 +541,12 @@ PACE_HEADER
PACE_HEADER *
PACL
PACL *
PACMDRIVERDETAILSA
PACMDRIVERDETAILSW
PACMFILTERCHOOSEA
PACMFILTERCHOOSEW
PACMFILTERDETAILSA
PACMFILTERDETAILSW
PACMFILTERTAGDETAILSA
PACMFILTERTAGDETAILSW
PACMFORMATCHOOSEA
PACMFORMATCHOOSEW
PACMFORMATDETAILSA
PACMFORMATDETAILSW
PACMFORMATTAGDETAILSA
PACMFORMATTAGDETAILSW
PACMSTREAMHEADER
PAINTSTRUCT *
PALETTEENTRY *
PANSI_STRING
PAPCFUNC
PAPI_VERSION
PAPPBARDATA
PAVIFILE
PAVIFILE *
PAVISTREAM
PAVISTREAM *
PBOOLEAN
PBYTE
PCHAR
......@@ -623,9 +566,6 @@ PFUNCTION_TABLE_ACCESS_ROUTINE
PGENERIC_MAPPING
PGETFRAME
PGET_MODULE_BASE_ROUTINE
PHACMDRIVER
PHACMDRIVERID
PHACMSTREAM
PHONECALLBACK
PIMAGEHLP_MODULE
PIMAGEHLP_STATUS_ROUTINE
......@@ -646,7 +586,9 @@ POBJECT_ATTRIBUTES
POINT *
PPOLYTEXTA
PPOLYTEXTW
PPSAPI_WS_WATCH_INFORMATION
PPRIVILEGE_SET
PPROCESS_MEMORY_COUNTERS
PREAD_PROCESS_MEMORY_ROUTINE
PRTL_HEAP_DEFINITION
PROPENUMPROCA
......
......@@ -8,18 +8,48 @@ sub new {
my $self = {};
bless ($self, $class);
my $output = \${$self->{OUTPUT}};
my $name = \${$self->{NAME}};
$$output = shift;
$$name = shift;
my $file = shift;
my $path = shift;
$file =~ s/^.\/(.*)$/$1/;
$self->parse_api_file($file);
my @files = map {
s/^.\/(.*)$/$1/;
$_;
} split(/\n/, `find $path -name \\*.api`);
foreach my $file (@files) {
my $module = $file;
$module =~ s/.*?\/([^\/]*?)\.api$/$1/;
$self->parse_api_file($file,$module);
}
return $self;
}
sub parse_api_file {
my $self = shift;
my $output = \${$self->{OUTPUT}};
my $allowed_kind = \%{$self->{ALLOWED_KIND}};
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
$self->{NAME} = shift;
my $file = shift;
my $module = shift;
my @modules;
my $kind;
my $forbidden = 0;
$$output->progress("$file");
open(IN, "< $file") || die "$file: $!\n";
$/ = "\n";
while(<IN>) {
......@@ -29,34 +59,41 @@ sub new {
if(s/^%(\S+)\s*//) {
$kind = $1;
@modules = ();
$forbidden = 0;
$$allowed_kind{$kind} = 1;
if(/^--module=(\S*)/) {
@modules = split(/,/, $1);
} elsif(/^--forbidden/) {
if(/^--forbidden/) {
$forbidden = 1;
}
} elsif(defined($kind)) {
my $type = $_;
if(!$forbidden) {
for my $module (@modules) {
$$allowed_modules_limited{$type} = 1;
$$allowed_modules{$type}{$module} = 1;
if(defined($module)) {
if($$allowed_modules_unlimited{$type}) {
print "$file: type ($type) already specificed as an unlimited type\n";
} elsif(!$$allowed_modules{$type}{$module}) {
$$allowed_modules{$type}{$module} = 1;
$$allowed_modules_limited{$type} = 1;
} else {
print "$file: type ($type) already specificed\n";
}
} else {
$$allowed_modules_unlimited{$type} = 1;
}
} else {
$$allowed_modules_limited{$type} = 1;
}
$$translate_argument{$type} = $kind;
if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
print "$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n";
} else {
$$translate_argument{$type} = $kind;
}
} else {
print "$file: file must begin with %<type> statement\n";
exit 1;
}
}
close(IN);
return $self;
}
sub get_spec_file_type {
......@@ -88,7 +125,12 @@ sub read_spec_files {
my $win16api = shift;
my $win32api = shift;
foreach my $file (split(/\n/, `find $path -name \\*.spec`)) {
my @files = map {
s/^.\/(.*)$/$1/;
$_;
} split(/\n/, `find $path -name \\*.spec`);
foreach my $file (@files) {
my $type = 'winapi'->get_spec_file_type($file);
if($type eq "win16") {
$win16api->parse_spec_file($file);
......@@ -100,16 +142,22 @@ sub read_spec_files {
sub parse_spec_file {
my $self = shift;
my $output = \${$self->{OUTPUT}};
my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
my $function_stub = \%{$self->{FUNCTION_STUB}};
my $function_module = \%{$self->{FUNCTION_MODULE}};
my $file = shift;
my %ordinals;
my $type;
my $module;
$$output->progress("$file");
open(IN, "< $file") || die "$file: $!\n";
$/ = "\n";
my $header = 1;
......@@ -126,18 +174,24 @@ sub parse_spec_file {
next;
}
if(/^\d+\s+(pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/) {
my $calling_convention = $1;
my $external_name = $2;
my $arguments = $3;
my $internal_name = $4;
my $ordinal;
if(/^(\d+)\s+(pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/) {
my $calling_convention = $2;
my $external_name = $3;
my $arguments = $4;
my $internal_name = $5;
$ordinal = $1;
# FIXME: Internal name existing more than once not handled properly
$$function_arguments{$internal_name} = $arguments;
$$function_calling_convention{$internal_name} = $calling_convention;
$$function_module{$internal_name} = $module;
} elsif(/^\d+\s+stub\s+(\S+)$/) {
my $external_name = $1;
$$function_module{$internal_name} = "$module";
} elsif(/^(\d+)\s+stub\s+(\S+)$/) {
my $external_name = $2;
$ordinal = $1;
$$function_stub{$external_name} = 1;
$$function_module{$external_name} = $module;
} elsif(/^\d+\s+(equate|long|word|extern|forward)/) {
......@@ -151,13 +205,22 @@ sub parse_spec_file {
$lookahead = 1;
}
}
if(defined($ordinal)) {
if($ordinals{$ordinal}) {
print "$file: ordinal redefined: $_\n";
}
$ordinals{$ordinal}++;
}
}
close(IN);
}
sub name {
my $self = shift;
return $self->{NAME};
my $name = \${$self->{NAME}};
return $$name;
}
sub is_allowed_kind {
......@@ -172,6 +235,15 @@ sub is_allowed_kind {
}
}
sub is_limited_type {
my $self = shift;
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
my $type = shift;
return $$allowed_modules_limited{$type};
}
sub allowed_type_in_module {
my $self = shift;
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
......@@ -183,6 +255,34 @@ sub allowed_type_in_module {
return !$$allowed_modules_limited{$type} || $$allowed_modules{$type}{$module};
}
sub type_used_in_module {
my $self = shift;
my $used_modules = \%{$self->{USED_MODULES}};
my $type = shift;
my $module = shift;
$$used_modules{$type}{$module} = 1;
return ();
}
sub types_not_used {
my $self = shift;
my $used_modules = \%{$self->{USED_MODULES}};
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $not_used;
foreach my $type (sort(keys(%$allowed_modules))) {
foreach my $module (sort(keys(%{$$allowed_modules{$type}}))) {
if(!$$used_modules{$type}{$module}) {
$$not_used{$module}{$type} = 1;
}
}
}
return $not_used;
}
sub translate_argument {
my $self = shift;
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
......@@ -226,7 +326,7 @@ sub all_functions {
sub all_functions_found {
my $self = shift;
my $function_found = \$self->{FUNCTION_FOUND};
my $function_found = \%{$self->{FUNCTION_FOUND}};
return sort(keys(%$function_found));
}
......@@ -282,11 +382,7 @@ sub function_module {
my $name = shift;
if($self->is_function($name)) {
return $$function_module{$name};
} else {
return undef;
}
return $$function_module{$name};
}
sub function_stub {
......
......@@ -20,15 +20,19 @@ BEGIN {
}
@INC = ($winapi_check_dir);
require "winapi.pm";
require "nativeapi.pm";
require "output.pm";
require "preprocessor.pm";
require "winapi.pm";
require "winapi_local.pm";
require "winapi_global.pm";
require "winapi_options.pm";
require "winapi_parser.pm";
import winapi;
import nativeapi;
import output;
import preprocessor;
import winapi;
import winapi_local;
import winapi_global;
import winapi_options;
......@@ -41,11 +45,13 @@ if($options->help) {
exit;
}
my $win16api = 'winapi'->new("win16", "$winapi_check_dir/win16api.dat");
my $win32api = 'winapi'->new("win32", "$winapi_check_dir/win32api.dat");
my $output = 'output'->new;
my $win16api = 'winapi'->new($output, "win16", "$winapi_check_dir/win16api.dat", "$winapi_check_dir/win16");
my $win32api = 'winapi'->new($output, "win32", "$winapi_check_dir/win32api.dat", "$winapi_check_dir/win32");
'winapi'->read_spec_files($wine_dir, $win16api, $win32api);
my $nativeapi = 'nativeapi'->new("$winapi_check_dir/nativeapi.dat");
my $nativeapi = 'nativeapi'->new("$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);
......@@ -61,13 +67,57 @@ for my $name ($win32api->all_functions) {
}
}
my %includes;
{
my @files = map {
s/^.\/(.*)$/$1/;
$_;
} split(/\n/, `find . -name \\*.h`);
foreach my $file (@files) {
$includes{$file} = { name => $file };
open(IN, "< $file");
while(<IN>) {
if(/^\s*\#\s*include\s*\"(.*?)\"/) {
$includes{$file}{includes}{"include/$1"}++;
}
}
close(IN);
}
}
my %functions;
my $progress_output;
my $progress_current=0;
my $progress_max=scalar($options->files);
foreach my $file ($options->files) {
$progress_current++;
if($options->progress) {
$output->progress("$file: file $progress_current of $progress_max");
}
my $file_dir = $file;
$file_dir =~ s/(.*?)\/[^\/]*$/$1/;
my $file_type;
if($file_dir =~ /^(libtest|program|rc)/) {
$file_type = "application";
} elsif($file_dir =~ /^(debug|miscemu)/) {
$file_type = "emulator";
} elsif($file_dir =~ /^(tools)/) {
$file_type = "tool";
} else {
$file_type = "library";
}
my $found_function = sub {
my $return_type = shift;
my $calling_convention = shift;
my $name = shift;
my $refarguments = shift;
my @arguments = @$refarguments;
my $statements = shift;
if($options->global) {
$win16api->found_type($return_type) if $options->win16;
......@@ -84,16 +134,38 @@ foreach my $file ($options->files) {
if($options->local) {
my $module16 = $win16api->function_module($name);
my $module32 = $win32api->function_module($name);
my $output = sub {
my $module;
if(defined($module16) && defined($module32)) {
$module = "$module16 & $module32";
} elsif(defined($module16)) {
$module = $module16;
} elsif(defined($module32)) {
$module = $module32;
} else {
$module = "";
}
my $output_module = sub {
my $module = shift;
return sub {
my $msg = shift;
print "$file: $module: $return_type $calling_convention $name(" . join(",", @arguments) . "): $msg\n";
$output->write("$file: $module: $return_type ");
$output->write("$calling_convention ") if $calling_convention;
$output->write("$name(" . join(",", @arguments) . "): $msg\n");
}
};
my $output16 = &$output($module16);
my $output32 = &$output($module32);
my $output16 = &$output_module($module16);
my $output32 = &$output_module($module32);
my $function = $functions{$name};
$$function{file} = $file;
$$function{return_type} = $return_type;
$$function{calling_convention} = $calling_convention;
$$function{arguments} = [@arguments];
$$function{module} = $module;
$$function{module16} = $module16;
$$function{module32} = $module32;
if($options->argument) {
if($options->win16 && $options->report_module($module16)) {
winapi_local::check_arguments $options, $output16,
......@@ -122,12 +194,145 @@ foreach my $file ($options->files) {
}
}
}
if($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{$name}{called_function_names}{$called_name}++;
$functions{$called_name}{called_by_function_names}{$name}++;
}
} else {
undef $_
}
}
}
}
};
my $config = 0;
my $conditional = 0;
my $found_include = sub {
local $_ = shift;
if(/^\"config.h\"/) {
$config++;
}
};
my $found_conditional = sub {
local $_ = shift;
if(!$nativeapi->is_conditional($_)) {
if(/^HAVE_/ && !/^HAVE_(IPX|MESAGL|BUGGY_MESAGL|WINE_CONSTRUCTOR)$/)
{
$output->write("$file: $_ is not a declared as a conditional\n");
}
} else {
$conditional++;
if(!$config) {
$output->write("$file: conditional $_ used but config.h is not included\n");
}
}
};
winapi_parser::parse_c_file $options, $file, $found_function;
};
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") {
if($argument =~ /^<(.*?)>$/) {
my $header = $1;
if((-e "$wine_dir/include/$header" || -e "$file_dir/$header") && $file_type ne "application") {
$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/) {
if(!$preprocessor->is_undef("X_DISPLAY_MISSING")) {
$output->write("$file: #$directive $argument: is a conditional include, but is not protected\n");
}
} 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");
}
} elsif($argument =~ /^"(.*?)"$/) {
my $header = $1;
if(-e "$file_dir/$header") {
$includes{"$file_dir/$header"}{used}++;
foreach my $name (keys(%{$includes{"$file_dir/$header"}{includes}})) {
$includes{$name}{used}++;
}
} elsif(-e "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, $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");
}
}
if($options->cross_call) {
my @names = sort(keys(%functions));
for my $name (@names) {
my @called_names = sort(keys(%{$functions{$name}{called_function_names}}));
my @called_by_names = sort(keys(%{$functions{$name}{called_by_function_names}}));
my $module = $functions{$name}{module};
my $module16 = $functions{$name}{module16};
my $module32 = $functions{$name}{module32};
if($#called_names >= 0 && (defined($module16) || defined($module32)) ) {
$output->write("$file: $module: $name: \\\n");
for my $called_name (@called_names) {
my $function;
if($function = $functions{$called_name}) {
$output->write(" $called_name\n");
}
}
}
}
}
}
$output->hide_progress;
if($options->global) {
foreach my $name (sort(keys(%includes))) {
if(!$includes{$name}{used}) {
if($options->include) {
print "$name: include file is never used\n";
}
}
}
winapi_global::check $options, $win16api, $nativeapi if $options->win16;
winapi_global::check $options, $win32api, $nativeapi if $options->win32;
}
......@@ -11,9 +11,9 @@ sub check {
if($options->argument) {
foreach my $type ($winapi->all_declared_types) {
if(!$winapi->type_found($type) && $type ne "CONTEXT86 *") {
print "*.c: $winver: $type: ";
print "type not used\n";
if(!$winapi->type_found($type) && !$winapi->is_type_limited($type) && $type ne "CONTEXT86 *") {
print "*.c: $winver: ";
print "type ($type) not used\n";
}
}
}
......@@ -21,19 +21,22 @@ sub check {
if($options->declared) {
foreach my $name ($winapi->all_functions) {
if(!$winapi->function_found($name) && !$nativeapi->is_function($name)) {
print "*.c: $winver: $name: ";
my $module = $winapi->function_module($name);
print "*.c: $module: $name: ";
print "function declared but not implemented: " . $winapi->function_arguments($name) . "\n";
}
}
}
if($options->implemented) {
foreach my $name ($winapi->all_functions_found) {
if($winapi->function_stub($name)) {
print "*.c: $winver: $name: ";
print "function implemented but not declared\n";
if($options->argument_forbidden) {
my $not_used = $winapi->types_not_used;
foreach my $module (sort(keys(%$not_used))) {
foreach my $type (sort(keys(%{$$not_used{$module}}))) {
print "*.c: $module: type $type not used\n";
}
}
}
}
......
......@@ -14,8 +14,30 @@ sub check_arguments {
my $module = $winapi->function_module($name);
if($winapi->name eq "win16") {
my $name16 = $name;
$name16 =~ s/16$//;
if($name16 ne $name && $winapi->function_stub($name16)) {
if($options->implemented) {
&$output("function implemented but declared as stub in .spec file");
}
return;
} elsif($winapi->function_stub($name)) {
if($options->implemented_win32) {
&$output("32-bit variant of function implemented but declared as stub in .spec file");
}
return;
}
} elsif($winapi->function_stub($name)) {
if($options->implemented) {
&$output("function implemented but declared as stub in .spec file");
}
return;
}
my $forbidden_return_type = 0;
my $implemented_return_kind;
$winapi->type_used_in_module($return_type,$module);
if(!defined($implemented_return_kind = $winapi->translate_argument($return_type))) {
if($return_type ne "") {
&$output("no translation defined: " . $return_type);
......@@ -48,8 +70,10 @@ sub check_arguments {
$implemented_calling_convention = "cdecl";
} elsif($calling_convention =~ /^VFWAPIV|WINAPIV$/) {
$implemented_calling_convention = "varargs";
} elsif($calling_convention = ~ /^__stdcall|VFWAPI|WINAPI$/) {
} elsif($calling_convention =~ /^__stdcall|VFWAPI|WINAPI$/) {
$implemented_calling_convention = "stdcall";
} else {
$implemented_calling_convention = "<default>";
}
}
......@@ -85,15 +109,12 @@ sub check_arguments {
if($name =~ /^CRTDLL__ftol|CRTDLL__CIpow$/) {
# ignore
} elsif($#argument_types != $#declared_argument_kinds) {
if($options->argument_count) {
&$output("argument count differs: " . ($#argument_types + 1) . " != " . ($#declared_argument_kinds + 1));
}
} else {
my $n = 0;
my @argument_kinds = map {
my $type = $_;
my $kind = "unknown";
$winapi->type_used_in_module($type,$module);
if(!defined($kind = $winapi->translate_argument($type))) {
&$output("no translation defined: " . $type);
} elsif(!$winapi->is_allowed_kind($kind) ||
......@@ -102,8 +123,13 @@ sub check_arguments {
&$output("forbidden argument " . ($n + 1) . " type (" . $type . ")");
}
}
$n++;
$kind;
if(defined($kind) && $kind eq "longlong") {
$n+=2;
("long", "long");
} else {
$n++;
$kind;
}
} @argument_types;
for my $n (0..$#argument_kinds) {
......@@ -123,8 +149,13 @@ sub check_arguments {
$argument_types[$n] . " ($argument_kinds[$n]) != " . $declared_argument_kinds[$n]);
}
}
}
if($#argument_kinds != $#declared_argument_kinds) {
if($options->argument_count) {
&$output("argument count differs: " . ($#argument_types + 1) . " != " . ($#declared_argument_kinds + 1));
}
}
}
if($segmented && $options->shared_segmented && $winapi->is_shared_function($name)) {
......
......@@ -23,12 +23,17 @@ my %options = (
"help" => { default => 0, description => "help mode" },
"verbose" => { default => 0, description => "verbose mode" },
"progress" => { default => 1, description => "show progress" },
"win16" => { default => 1, description => "Win16 checking" },
"win32" => { default => 1, description => "Win32 checking" },
"shared" => { default => 0, description => "show shared functions between Win16 and Win32" },
"shared-segmented" => { default => 0, description => "segmented shared functions between Win16 and Win32 checking" },
"config" => { default => 1, description => "check configuration include consistancy" },
"config-unnessary" => { default => 0, parent => "config", description => "check for unnessary #include \"config.h\"" },
"local" => { default => 1, description => "local checking" },
"module" => {
default => { active => 1, filter => 0, hash => {} },
......@@ -40,7 +45,7 @@ my %options = (
"argument" => { default => 1, parent => "local", description => "argument checking" },
"argument-count" => { default => 1, parent => "argument", description => "argument count checking" },
"argument-forbidden" => {
default => { active => 0, filter => 0, hash => {} },
default => { active => 1, filter => 0, hash => {} },
parent => "argument",
parser => \&parser_comma_list,
description => "argument forbidden checking"
......@@ -52,12 +57,14 @@ my %options = (
description => "argument kind checking"
},
"calling-convention" => { default => 0, parent => "local", description => "calling convention checking" },
"misplaced" => { default => 0, parent => "local", description => "checking for misplaced functions" },
"misplaced" => { default => 0, parent => "local", description => "check for misplaced functions" },
"cross-call" => { default => 0, parent => "local", description => "check for cross calling functions" },
"global" => { default => 1, description => "global checking" },
"declared" => { default => 1, parent => "global", description => "declared checking" },
"implemented" => { default => 0, parent => "global", description => "implemented checking" }
"implemented" => { default => 1, parent => "global", description => "implemented checking" },
"implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" },
"include" => { default => 0, parent => "global", description => "include checking" }
);
my %short_options = (
......
......@@ -6,6 +6,27 @@ sub parse_c_file {
my $options = shift;
my $file = shift;
my $function_found_callback = shift;
my $preprocessor_found_callback = shift;
my $return_type;
my $calling_convention;
my $function = "";
my $arguments;
my $statements;
my $function_begin = sub {
$return_type= shift;
$calling_convention = shift;
$function = shift;
$arguments = shift;
$statements = "";
};
my $function_end = sub {
&$function_found_callback($return_type,$calling_convention,$function,$arguments,$statements);
$function = "";
};
my $level = 0;
my $again = 0;
......@@ -44,34 +65,61 @@ sub parse_c_file {
if(/^\s*$/) { next; }
# remove preprocessor directives
if(s/^\s*\#.*$//m) { $again = 1; next; }
if(s/^\s*\#/\#/m) {
if(/^\\#.*?\\$/m) {
$lookahead = 1;
next;
} elsif(s/^\#\s*(.*?)(\s+(.*?))?\s*$//m) {
if(defined($3)) {
&$preprocessor_found_callback($1, $3);
} else {
&$preprocessor_found_callback($1, "");
}
$again = 1;
next;
}
}
if($level > 0)
{
s/^[^\{\}]*//s;
if(/^\{/) {
my $line;
s/^([^\{\}]*)//s;
$line = $1;
if(/^(\{)/) {
$_ = $'; $again = 1;
$line .= $1;
print "+1: $_\n" if $options->debug >= 2;
$level++;
} elsif(/^\}/) {
} elsif(/^(\})/) {
$_ = $'; $again = 1;
$line .= $1 if $level > 1;
print "-1: $_\n" if $options->debug >= 2;
$level--;
}
if($line !~ /^\s*$/) {
$statements .= "$line\n";
}
if($function && $level == 0) {
&$function_end;
}
next;
} elsif(/((struct\s+|union\s+|enum\s+)?\w+((\s*\*)+\s*|\s+))(__cdecl|__stdcall|VFWAPIV|VFWAPI|WINAPIV|WINAPI)\s+(\w+(\(\w+\))?)\s*\(([^\)]*)\)\s*(\{|\;)/s) {
} elsif(/((struct\s+|union\s+|enum\s+)?\w+((\s*\*)+\s*|\s+))((__cdecl|__stdcall|VFWAPIV|VFWAPI|WINAPIV|WINAPI)\s+)?(\w+(\(\w+\))?)\s*\(([^\)]*)\)\s*(\{|\;)/s) {
$_ = $'; $again = 1;
if($9 eq ";") {
if($10 eq ";") {
next;
} elsif($9 eq "{") {
} elsif($10 eq "{") {
$level++;
}
my $return_type = $1;
my $calling_convention = $5;
my $name = $6;
my $arguments = $8;
my $calling_convention = $6;
my $name = $7;
my $arguments = $9;
if(!defined($calling_convention)) {
$calling_convention = "";
}
$return_type =~ s/\s*$//;
$return_type =~ s/\s*\*\s*/*/g;
......@@ -88,7 +136,8 @@ sub parse_c_file {
my $argument = $arguments[$n];
$argument =~ s/^\s*(.*?)\s*$/$1/;
#print " " . ($n + 1) . ": '$argument'\n";
$argument =~ s/^(const(?=\s)|IN(?=\s)|OUT(?=\s)|(\s*))\s*//;
$argument =~ s/^(IN OUT(?=\s)|IN(?=\s)|OUT(?=\s)|\s*)\s*//;
$argument =~ s/^(const(?=\s)|\s*)\s*//;
if($argument =~ /^...$/) {
$argument = "...";
} elsif($argument =~ /^((struct\s+|union\s+|enum\s+)?\w+)\s*((\*\s*?)*)\s*/) {
......@@ -107,52 +156,66 @@ sub parse_c_file {
if($options->debug) {
print "$file: $return_type $calling_convention $name(" . join(",", @arguments) . ")\n";
}
&$function_found_callback($return_type,$calling_convention,$name,\@arguments);
&$function_begin($return_type,$calling_convention,$name,\@arguments);
} elsif(/DC_(GET_X_Y|GET_VAL_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
my @arguments = ("HDC16");
&$function_found_callback($2, "WINAPI", $3, \@arguments);
&$function_begin($2, "WINAPI", $3, \@arguments);
&$function_end;
} elsif(/DC_(GET_VAL_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,.*?\)/s) {
$_ = $'; $again = 1;
my @arguments = ("HDC");
&$function_found_callback($2, "WINAPI", $3, \@arguments);
&$function_begin($2, "WINAPI", $3, \@arguments);
&$function_end;
} elsif(/DC_(GET_VAL_EX)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
my @arguments16 = ("HDC16", "LP" . $5 . "16");
my @arguments32 = ("HDC", "LP" . $5);
&$function_found_callback("BOOL16", "WINAPI", $2 . "16", \@arguments16);
&$function_found_callback("BOOL", "WINAPI", $2, \@arguments32);
&$function_begin("BOOL16", "WINAPI", $2 . "16", \@arguments16);
&$function_end;
&$function_begin("BOOL", "WINAPI", $2, \@arguments32);
&$function_end;
} elsif(/DC_(SET_MODE)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
my @arguments16 = ("HDC16", "INT16");
my @arguments32 = ("HDC", "INT");
&$function_found_callback("INT16", "WINAPI", $2 . "16", \@arguments16);
&$function_found_callback("INT", "WINAPI", $2, \@arguments32);
&$function_begin("INT16", "WINAPI", $2 . "16", \@arguments16);
&$function_end;
&$function_begin("INT", "WINAPI", $2, \@arguments32);
&$function_end;
} elsif(/WAVEIN_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
my @arguments16 = ("HWAVEIN16");
my @arguments32 = ("HWAVEIN");
&$function_found_callback("UINT16", "WINAPI", "waveIn" . $1 . "16", \@arguments16);
&$function_found_callback("UINT", "WINAPI", "waveIn" . $1, \@arguments32);
&$function_begin("UINT16", "WINAPI", "waveIn" . $1 . "16", \@arguments16);
&$function_end;
&$function_begin("UINT", "WINAPI", "waveIn" . $1, \@arguments32);
&$function_end;
} elsif(/WAVEOUT_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
my @arguments16 = ("HWAVEOUT16");
my @arguments32 = ("HWAVEOUT");
&$function_found_callback("UINT16", "WINAPI", "waveOut" . $1 . "16", \@arguments16);
&$function_found_callback("UINT", "WINAPI", "waveOut" . $1, \@arguments32);
&$function_begin("UINT16", "WINAPI", "waveOut" . $1 . "16", \@arguments16);
&$function_end;
&$function_begin("UINT", "WINAPI", "waveOut" . $1, \@arguments32);
&$function_end;
} elsif(/WAVEOUT_SHORTCUT_(1|2)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
if($1 eq "1") {
my @arguments16 = ("HWAVEOUT16", $4);
my @arguments32 = ("HWAVEOUT", $4);
&$function_found_callback("UINT16", "WINAPI", "waveOut" . $2 . "16", \@arguments16);
&$function_found_callback("UINT", "WINAPI", "waveOut" . $2, \@arguments32);
&$function_begin("UINT16", "WINAPI", "waveOut" . $2 . "16", \@arguments16);
&$function_end;
&$function_begin("UINT", "WINAPI", "waveOut" . $2, \@arguments32);
&$function_end;
} elsif($1 eq 2) {
my @arguments16 = ("UINT16", $4);
my @arguments32 = ("UINT", $4);
&$function_found_callback("UINT16", "WINAPI", "waveOut". $2 . "16", \@arguments16);
&$function_found_callback("UINT", "WINAPI", "waveOut" . $2, \@arguments32)
&$function_begin("UINT16", "WINAPI", "waveOut". $2 . "16", \@arguments16);
&$function_end;
&$function_begin("UINT", "WINAPI", "waveOut" . $2, \@arguments32);
&$function_end;
}
} elsif(/;/s) {
$_ = $'; $again = 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment