Made a new improved version of winapi-check in perl.

This commit is contained in:
Patrik Stridvall 1999-09-23 15:14:20 +00:00 committed by Alexandre Julliard
parent 26e1653017
commit 37fd2d1c85
12 changed files with 2618 additions and 49 deletions

View File

@ -1,49 +0,0 @@
#!/bin/sh
# This quick and dirty script prints the names of functions that don't have a
# WINAPI in its header declaration or don't appear in any .c file at all.
# I don't think it's very intelligent to use it when having < 64 MB ;)
# FIXME: This script skips .spec function entries that occupy two or more
# .spec lines !
if [ ! -e ./ChangeLog ] ; then
echo You are not in Wine main directory !
exit
fi
echo crtdll.spec, ntdll.spec and wsock32.spec will be mentioned many times,
echo as they use original UNIX functions that don\'t exist in Wine .c code.
echo
FIND_LIST="`find . -name "*.c"`"
for i in if1632/*.spec relay32/*.spec
do
# skip wprocs.spec, as it contains many funcs that don't need a WINAPI
if [ $i = "if1632/wprocs.spec" ] ; then
continue
fi
LINE="`egrep "stdcall|cdecl|pascal|register" $i|grep -v "^#"|tr -d " "|tr "\n" " "`"
for j in $LINE
do
if [ -n "`echo "$j"|grep \)`" ] ; then
FUNC="`echo $j|cut -f2 -d\)|cut -f1 -d'#'`"
if [ -n "$FUNC" ] ; then
if [ -z "`grep -B 1 $FUNC $FIND_LIST|egrep "WINAPI|__cdecl|VFWAPI|DC_GET_VAL|DC_SET_MODE|REGS_ENTRYPOINT"`" ] ; then
case $FUNC in # "black list"
"GetBrushOrgEx16" ) ;;
"GetCurrentPositionEx16" ) ;;
"GetViewportExtEx16" ) ;;
"GetViewportOrgEx16" ) ;;
"GetWindowExtEx16" ) ;;
"GetWindowOrgEx16" ) ;;
"GetBrushOrgEx32" ) ;;
"GetCurrentPositionEx32" ) ;;
"GetViewportExtEx32" ) ;;
"GetViewportOrgEx32" ) ;;
"GetWindowExtEx32" ) ;;
"GetWindowOrgEx32" ) ;;
* ) echo "$i: $FUNC" ;;
esac
fi
fi
fi
done
done

View File

@ -0,0 +1,217 @@
__ctype
__divdi3
__eprintf
__fixunsdfdi
__flsbuf
__iob
__moddi3
_environ
_exit
_fxstat
_lwp_create
_lwp_exit
_lwp_makecontext
_lxstat
_sysconf
_xmknod
_xstat
abs
access
acos
asctime
asin
atan
atan2
atexit
atof
atoi
atol
bsearch
bzero
calloc
ceil
cfgetospeed
chmod
close
closedir
cos
cosh
ctime
div
dup
dup2
environ
errno
execlp
execvp
exit
exp
fabs
fclose
fcntl
fdopen
feof
fflush
ffs
fgetc
fgetpos
fgets
floor
fmod
fopen
fork
fprintf
fputc
fputs
fread
free
frexp
fseek
fsetpos
fsync
ftruncate
fwrite
getcwd
getenv
getlogin
getnetbyname
getpid
getpwuid
gettimeofday
getuid
gmtime
hypot
inet_network
ioctl
isalnum
isalpha
isatty
iscntrl
isdigit
isgraph
islower
isprint
ispunct
isspace
isupper
isxdigit
j0
j1
jn
kill
labs
ldexp
ldiv
localtime
log
log10
longjmp
lseek
malloc
mblen
memchr
memcmp
memcpy
memmove
memset
mkdir
mktime
mmap
modf
mprotect
msync
munmap
open
opendir
perror
pipe
poll
pow
printf
putchar
putenv
puts
qsort
raise
rand
read
readdir
realloc
remove
rename
rmdir
select
setbuf
setlocale
setsid
settimeofday
setvbuf
shmat
shmctl
shmdt
shmget
sigaction
sigaddset
sigaltstack
sigemptyset
signal
sigprocmask
sin
sin
sinh
sleep
snprintf
sprintf
sqrt
srand
sscanf
statfs
strcasecmp
strcat
strchr
strcmp
strcoll
strcpy
strcspn
strdup
strerror
strftime
strlen
strncasecmp
strncat
strncmp
strncpy
strpbrk
strrchr
strspn
strstr
strtod
strtok
strtol
strtoul
strxfrm
sysi86
system
tan
tanh
tcflush
tcgetattr
tcsetattr
tempnam
time
times
tmpnam
tolower
toupper
towlower
towupper
unlink
usleep
utime
vfprintf
vsprintf
wait4
write
y0
y1
yn

View File

@ -0,0 +1,38 @@
package nativeapi;
use strict;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $functions = \%{$self->{FUNCTIONS}};
my $file = shift;
open(IN, "< $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;
}
close(IN);
return $self;
}
sub is_function {
my $self = shift;
my $functions = \%{$self->{FUNCTIONS}};
my $name = shift;
return $$functions{$name};
}
1;

View File

@ -0,0 +1,184 @@
package parser;
BEGIN {
use Exporter ();
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(&init
&transact &commit &rollback &token
&dump_state
&either &filter &many &many1 &separate &separate1 &sequence);
}
my @stack;
my $current;
my $next;
sub init {
@stack = ();
$current = [];
$next = shift;
@$next = grep {
$_->{type} !~ /^comment|preprocessor$/;
} @$next;
}
sub dump_state {
print "stack: [\n";
for my $tokens (@stack) {
print " [\n";
for my $token (@$tokens) {
print " " . $token->{type} . ": " . $token->{data} . "\n";
}
print " ]\n";
}
print "]\n";
print "current: [\n";
for my $token (@$current) {
print " " . $token->{type} . ": " . $token->{data} . "\n";
}
print "]\n";
print "next: [\n";
for my $token (@$next) {
print " " . $token->{type} . ": " . $token->{data} . "\n";
}
print "]\n";
}
sub token {
my $token = shift @$next;
push @$current, $token;
return $token;
};
sub transact {
push @stack, $current;
$current = [];
}
sub commit {
my $oldcurrent = $current;
$current = pop @stack;
push @$current, @$oldcurrent;
}
sub rollback {
unshift @$next, @$current;
$current = pop @stack;
}
sub filter {
my $parser = shift;
my $filter = shift;
transact;
my $r1 = &$parser;
if(defined($r1)) {
my $r2 = &$filter($r1);
if($r2) {
commit;
return $r1;
} else {
rollback;
return undef;
}
} else {
rollback;
return undef;
}
}
sub either {
for my $parser (@_) {
transact;
my $r = &$parser;
if(defined($r)) {
commit;
return $r;
} else {
rollback;
}
}
return undef;
}
sub sequence {
transact;
my $rs = [];
for my $parser (@_) {
my $r = &$parser;
if(defined($r)) {
push @$rs, $r;
} else {
rollback;
return undef;
}
}
commit;
return $rs;
}
sub separate {
my $parser = shift;
my $separator = shift;
my $rs = [];
while(1) {
my $r = &$parser;
if(defined($r)) {
push @$rs, $r;
} else {
last;
}
my $s = &$separator;
if(!defined($r)) {
last;
}
}
return $rs;
}
sub separate1 {
my $parser = shift;
my $separator = shift;
transact;
my $rs = separate($parser,$separator);
if($#$rs != -1) {
commit;
return $rs;
} else {
rollback;
return undef;
}
}
sub many {
my $parser = shift;
my $rs = [];
while(1) {
my $r = &$parser;
if(defined($r)) {
push @$rs, $r;
} else {
last;
}
}
return $rs;
}
sub many1 {
my $parser = shift;
transact;
my $rs = many($parser);
if($#$rs != -1) {
commit;
return $rs;
} else {
rollback;
return undef;
}
}
1;

View File

@ -0,0 +1,348 @@
%long
COLORREF
DWORD
FOURCC
HCONV
HCONVLIST
HDDEDATA
HHOOK
HKEY
HRESULT
HSZ
LCID
LCTYPE
LHCLIENTDOC
LHSERVER
LHSERVERDOC
LONG
LPARAM
LRESULT
POINT16
ULONG
%longlong
LARGE_INTEGER
%ptr
ACMDRIVERENUMCB16
ACMFILTERENUMCB16
ACMFILTERTAGENUMCB16
ACMFORMATENUMCB16
ACMFORMATTAGENUMCB16
BITMAP16 *
BITMAPINFO *
BITMAPINFOHEADER *
BOOL16 *
BSTR16 *
CLASSENTRY *
CLSID *
COLORREF *
CONTEXT86 *
CURSORICONINFO *
DEVMODEA *
DOCINFO16 *
DWORD *
FARPROC *
FARPROC16 *
FILETIME *
GLOBALENTRY *
GLOBALINFO *
GUID *
HANDLE *
HANDLETABLE16 *
HHOOK *
HICON16 *
HINSTANCE16 *
HMIDIIN16 *
HMIDIOUT16 *
HMIDISTRM16 *
HPCSTR
HPSTR
HTASK16 *
HWAVEIN16 *
HWAVEOUT16 *
IID *
IMalloc16 *
INT16 *
INTERFACEDATA *
IStorage16 *
IStorage16 **
IStream16 *
IStream16 **
ITypeInfo **
IUnknown *
LHCLIENTDOC *
LHSERVERDOC *
LOCAL32ENTRY *
LOCAL32INFO *
LOCALENTRY *
LOCALINFO *
LOGBRUSH16 *
LOGFONT16 *
LOGPALETTE *
LOGPEN16 *
LPABC16
LPACMDRIVERDETAILS16
LPACMFILTERCHOOSE16
LPACMFILTERDETAILS16
LPACMFILTERTAGDETAILS16
LPACMFORMATCHOOSE16
LPACMFORMATDETAILS16
LPACMFORMATTAGDETAILS16
LPACMSTREAMHEADER16
LPAUXCAPS16
LPBSTR16
LPBYTE
LPCATCHBUF
LPCHOOSECOLOR16
LPCHOOSEFONT16
LPCLSID
LPCOMSTAT16
LPCONVCONTEXT16
LPCONVINFO16
LPCURSORINFO
LPCVOID
LPDCB16
LPDEVMODEA
LPDRIVERINFOSTRUCT16
LPDWORD
LPENUMLOGFONT16
LPFILETIME
LPFONTINFO16
LPGLYPHMETRICS16
LPHACMDRIVER16
LPHACMDRIVERID16
LPHACMSTREAM16
LPHANDLE
LPHKEY
LPHMIXER16
LPICONINFO16
LPINT16
LPJOYCAPS16
LPJOYINFO16
LPKERNINGPAIR16
LPLOGFONT16
LPMALLOC16 *
LPMEMORY_BASIC_INFORMATION
LPMESSAGEFILTER
LPMESSAGEFILTER *
LPMIDIHDR16
LPMIDIINCAPS16
LPMIDIOUTCAPS16
LPMIXERCAPS16
LPMIXERCONTROLDETAILS16
LPMIXERLINE16
LPMIXERLINECONTROLS16
LPMMCKINFO
LPMMIOPROC16
LPMMTIME16
LPMONIKER *
LPMSG16
LPMSG16_32
LPMSGBOXPARAMS16
LPNEWTEXTMETRIC16
LPOFSTRUCT
LPOLECLIENT
LPOLEOBJECT
LPOLEOBJECT *
LPOLESERVERDOC
LPOLESTR16 *
LPDROPTARGET
LPOUTLINETEXTMETRIC16
LPPAINTSTRUCT16
LPPALETTEENTRY
LPPDEVICE
LPPOINT16
LPQUEUESTRUCT16 *
LPRASTERIZER_STATUS
LPRECT16
LPRGNDATA
LPRUNNINGOBJECTTABLE *
LPSCROLLINFO
LPSIZE16
LPSTORAGE16
LPTEXTXFORM16
LPTIMECAPS16
LPUINT16
LPUNKNOWN
LPVOID
LPVOID *
LPWAVEFILTER
LPWAVEFORMATEX
LPWAVEINCAPS16
LPWAVEOUTCAPS16
LPWIN32SINFO
LPWORD
LPWSADATA
MAT2 *
MEMMANINFO *
MENUITEMINFO16 *
METARECORD *
MIDIHDR16 *
MMCKINFO *
MMIOINFO16 *
MODULEENTRY *
MSG16 *
MSG32_16 *
OFSTRUCT *
OSVERSIONINFO16 *
PAINTSTRUCT16 *
PALETTEENTRY *
POINT16 *
RECT16 *
REFCLSID
REFGUID
REFIID
RGBQUAD *
SCROLLINFO *
SECURITY_ATTRIBUTES *
SEGINFO *
SEGPTR *
SNB16
STACKTRACEENTRY *
STATSTG16 *
SYSHEAPINFO *
SYSLEVEL *
TASKENTRY *
TEXTMETRIC16 *
THUNKLET *
TIMERINFO *
UINT16 *
ULARGE_INTEGER *
ULONG *
VOID *
WAVEHDR *
WIN32_FIND_DATAA *
WINDEBUGINFO *
WINDOWPLACEMENT16 *
WNDCLASS16 *
WNDCLASSEX16 *
WORD *
char *
struct ThunkDataCommon *
struct Win87EmInfoStruct *
struct sockaddr *
struct tagCURSORICONINFO *
struct timeval *
void *
ws_fd_set16 *
%s_word
INT16
%segptr
DLGPROC16
FARPROC16
FONTENUMPROC16
FONTENUMPROCEX16
GOBJENUMPROC16
GRAYSTRINGPROC16
HOOKPROC16
LINEDDAPROC16
LPTIMECALLBACK16
MFENUMPROC16
PROPENUMPROC16
SEGPTR
TIMERPROC16
WNDENUMPROC16
WNDPROC16
%segstr
BSTR16
%str
LPCOLESTR16
LPCSTR
LPCWSTR
LPSTR
LPOLESTR16
%unknown
struct in_addr
%void
void
VOID
%word
ATOM
BOOL16
BYTE
CHAR
HACCEL16
HACMDRIVER16
HACMDRIVERID16
HACMOBJ16
HACMSTREAM16
HANDLE16
HBITMAP16
HBRUSH16
HCURSOR16
HDC16
HDROP16
HDRVR16
HDWP16
HFILE16
HFONT16
HGDIOBJ16
HGLOBAL16
HICON16
HINSTANCE16
HLOCAL16
HMENU16
HMETAFILE16
HMIDIIN16
HMIDIOUT16
HMIDISTRM16
HMIXER16
HMIXEROBJ16
HMMIO16
HMODULE16
HPALETTE16
HPEN16
HPJOB16
HPQ16
HQUEUE16
HRGN16
HRSRC16
HTASK16
HWAVEIN16
HWAVEOUT16
HWND16
LANGID
MMRESULT16
OLESTATUS
SOCKET16
UINT16
WING_DITHER_TYPE
WORD
WPARAM16
%unknown --forbidden
BOOL
FARPROC
HANDLE
HINSTANCE
HMODULE
HWND
INT
LPOLESTR
UINT
YIELDPROC
int
long
short
u_long
u_short
unsigned

View File

@ -0,0 +1,785 @@
%double
CY
double
%long
ACCESS_MASK
ATOM
BOOL
BOOLEAN
BYTE
CALID
CALTYPE
CHAR
CLIPFORMAT
COLORREF
COORD
DATE
DIGEST_HANDLE
DPAENUMPROC
DWORD
FILE_INFORMATION_CLASS
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
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
LANGID
LCID
LCTYPE
LHCLIENTDOC
LHSERVER
LHSERVERDOC
LONG
LPARAM
LRESULT
MMRESULT
NTSTATUS
OBJECT_INFORMATION_CLASS
OLECLIPFORMAT
OLEOPT_RENDER
OLESTATUS
OLE_SERVER_USE
OUT
PHANDLE
PHPROVIDER
PIO_APC_ROUTINE
PLSA_HANDLE
PLSA_OBJECT_ATTRIBUTES
PLSA_UNICODE_STRING
POBJDIR_INFORMATION
PROCESSINFOCLASS
PTIME_FIELDS
PTOKEN_PRIVILEGES
REGSAM
SC_HANDLE
SECTION_INHERIT
SECURITY_IMPERSONATION_LEVEL
SECURITY_INFORMATION
SEGPTR
SERVICE_STATUS_HANDLE
SHORT
SOCKET
SYSKIND
SYSTEM_INFORMATION_CLASS
THREADINFOCLASS
TIMER_TYPE
TOKEN_INFORMATION_CLASS
TOKEN_TYPE
UINT
ULONG
ULONG_PTR
USHORT
VARIANT_BOOL
VARTYPE
WCHAR
WORD
WOW_HANDLE_TYPE
WPARAM
clock_t
enum NOTIFYTYPE
time_t
%longlong
LARGE_INTEGER
POINT
%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 *
CRITICAL_SECTION *
CRTDLL_FILE *
CY *
DATE *
DATEFMT_ENUMPROCA
DATEFMT_ENUMPROCW
DEVMODEA *
DEVMODEW *
DIGEST_FUNCTION
DLGPROC
DLLVERSIONINFO *
DOCINFOA *
DOCINFOW *
DPALOADPROC
DRAWSTATEPROC
DSAENUMPROC
DWORD *
ENHMETARECORD *
ENHMFENUMPROC
ENUMRESLANGPROCA
ENUMRESLANGPROCW
ENUMRESNAMEPROCA
ENUMRESNAMEPROCW
ENUMRESTYPEPROCA
ENUMRESTYPEPROCW
EXCEPTION_RECORD *
FARPROC
FARPROC *
FILETIME *
FLOAT *
FONTENUMPROCA
FONTENUMPROCEXA
FONTENUMPROCEXW
FONTENUMPROCW
GCP_RESULTSA *
GCP_RESULTSW *
GOBJENUMPROC
GRAYSTRINGPROC
GUID *
HANDLE *
HANDLER_ROUTINE *
HANDLETABLE *
HCRYPTPROV *
HDPA
HDPA *
HGLOBAL *
HICON *
HIMAGELIST
HIMAGELIST *
HKL *
HMENU *
HMIDIIN *
HMIDIOUT *
HMIDISTRM *
HMRU
HOOKPROC
HPCSTR
HPSTR
HWAVEIN *
HWAVEOUT *
HWND *
ICINFO *
IDSTRUCT *
IDataObject *
IDataObject **
IDropSource *
IDropTarget *
ILockBytes *
IMAGEINFO *
IMAGELISTDRAWPARAMS *
INPUT_RECORD *
INT *
IPersistStream *
IShellFolder **
IStorage *
IStorage **
IStream *
ITypeLib *
ITypeLib **
IUnknown *
LHCLIENTDOC *
LHSERVER *
LHSERVERDOC *
LINECALLBACK
LINEDDAPROC
LOCALE_ENUMPROCA
LOCALE_ENUMPROCW
LOGBRUSH *
LOGFONTA *
LOGFONTW *
LOGPALETTE *
LOGPEN *
LONG *
LPABC
LPABCFLOAT
LPACCEL
LPAUTHDLGSTRUCTA
LPAUXCAPSA
LPAUXCAPSW
LPAVIFILEINFOA
LPAVIFILEINFOW
LPBC *
LPBITMAPINFOHEADER
LPBOOL
LPBROWSEINFOA
LPBSTR
LPBYTE
LPCANDIDATEFORM
LPCANDIDATELIST
LPCHARSETINFO
LPCHAR_INFO
LPCHOOSECOLORA
LPCHOOSECOLORW
LPCHOOSEFONTA
LPCHOOSEFONTW
LPCITEMIDLIST
LPCITEMIDLIST *
LPCLSID
LPCMENUINFO
LPCOLDTBBUTTON
LPCOLORADJUSTMENT
LPCOLORMAP
LPCOMMTIMEOUTS
LPCOMPOSITIONFORM
LPCOMSTAT
LPCONNECTDLGSTRUCTA
LPCONNECTDLGSTRUCTW
LPCONSOLE_CURSOR_INFO
LPCONSOLE_SCREEN_BUFFER_INFO
LPCONVCONTEXT
LPCONVINFO
LPCPINFO
LPCPROPSHEETHEADERA
LPCPROPSHEETHEADERW
LPCPROPSHEETPAGEA
LPCPROPSHEETPAGEW
LPCSTR *
LPCTBBUTTON
LPCVOID
LPCWSTR *
LPDATAADVISEHOLDER *
LPDATAOBJECT
LPDCB
LPDDENUMCALLBACKA
LPDDENUMCALLBACKEXA
LPDDENUMCALLBACKEXW
LPDDENUMCALLBACKW
LPDEBUG_EVENT
LPDEVMODEA
LPDEVMODEW
LPDIRECTDRAW *
LPDIRECTDRAWCLIPPER *
LPDIRECTPLAYLOBBY *
LPDIRECTPLAYLOBBYA *
LPDIRECTSOUND *
LPDISCDLGSTRUCTA
LPDISCDLGSTRUCTW
LPDPENUMDPCALLBACKA
LPDPENUMDPCALLBACKW
LPDRAWITEMSTRUCT
LPDRAWTEXTPARAMS
LPDROPTARGET
LPDSENUMCALLBACKA
LPDWORD
LPENHMETAHEADER
LPENUMFORMATETC *
LPENUMOLEVERB *
LPENUM_SERVICE_STATUSA
LPFILETIME
LPFINDREPLACEA
LPFINDREPLACEW
LPFNCREATEINSTANCE
LPFNFMCALLBACK
LPFONTDESC
LPFONTSIGNATURE
LPFORMATETC
LPGLYPHMETRICS
LPGUID
LPHANDLE
LPHANDLER_FUNCTION
LPHANDLETABLE
LPHCALL
LPHKEY
LPHLINE
LPHLINEAPP
LPHMIXER
LPHPHONE
LPHPHONEAPP
LPICONINFO
LPINITCOMMONCONTROLSEX
LPINPUT_RECORD
LPINT
LPITEMIDLIST *
LPITEMIDLIST
LPJOYCAPSA
LPJOYCAPSW
LPJOYINFO
LPJOYINFOEX
LPKERNINGPAIR
LPLDT_ENTRY
LPLINEADDRESSCAPS
LPLINEADDRESSSTATUS
LPLINECALLINFO
LPLINECALLLIST
LPLINECALLPARAMS
LPLINECALLSTATUS
LPLINECOUNTRYLIST
LPLINEDEVCAPS
LPLINEDEVSTATUS
LPLINEDIALPARAMS
LPLINEEXTENSIONID
LPLINEFORWARDLIST
LPLINEGENERATETONE
LPLINEMEDIACONTROLCALLSTATE
LPLINEMEDIACONTROLDIGIT
LPLINEMEDIACONTROLMEDIA
LPLINEMEDIACONTROLTONE
LPLINEMONITORTONE
LPLINEPROVIDERLIST
LPLINETRANSLATECAPS
LPLINETRANSLATEOUTPUT
LPLOCKBYTES *
LPLOGFONTA
LPLOGFONTW
LPLONG
LPMALLOC *
LPMEASUREITEMSTRUCT
LPMEMORYSTATUS
LPMEMORY_BASIC_INFORMATION
LPMENUINFO
LPMENUITEMINFOA
LPMENUITEMINFOW
LPMESSAGEFILTER
LPMESSAGEFILTER *
LPMIDIHDR
LPMIDIINCAPSA
LPMIDIINCAPSW
LPMIDIOUTCAPSA
LPMIDIOUTCAPSW
LPMIXERCAPSA
LPMIXERCAPSW
LPMIXERCONTROLDETAILS
LPMIXERLINEA
LPMIXERLINECONTROLSA
LPMIXERLINECONTROLSW
LPMIXERLINEW
LPMMCKINFO
LPMMIOPROC
LPMMTIME
LPMODULEENTRY
LPMONIKER
LPMONIKER *
LPMONITORINFO
LPMRUINFO
LPMSG
LPMSGBOXPARAMSA
LPMSGBOXPARAMSW
LPNETCONNECTINFOSTRUCT
LPNETINFOSTRUCT
LPNETRESOURCEA
LPNETRESOURCEW
LPNMHDR
LPOFSTRUCT
LPOLEADVISEHOLDER *
LPOLECLIENT
LPOLECLIENTSITE
LPOLEINPLACEACTIVEOBJECT
LPOLEINPLACEFRAME
LPOLEINPLACEFRAMEINFO
LPOLEMENUGROUPWIDTHS
LPOLEOBJECT
LPOLEOBJECT *
LPOLESERVER
LPOLESERVERDOC
LPOLESTR
LPOLESTR *
LPOLEUIBUSYA
LPOLEUIBUSYW
LPOLEUICHANGEICONA
LPOLEUICHANGEICONW
LPOLEUICHANGESOURCEA
LPOLEUICHANGESOURCEW
LPOLEUICONVERTA
LPOLEUICONVERTW
LPOLEUIEDITLINKSA
LPOLEUIEDITLINKSW
LPOLEUIINSERTOBJECTA
LPOLEUIINSERTOBJECTW
LPOLEUILINKCONTAINERA
LPOLEUIOBJECTPROPSA
LPOLEUIOBJECTPROPSW
LPOLEUIPASTESPECIALA
LPOLEUIPASTESPECIALW
LPOPENFILENAMEA
LPOPENFILENAMEW
LPOUTLINETEXTMETRICA
LPOUTLINETEXTMETRICW
LPOVERLAPPED
LPOVERLAPPED_COMPLETION_ROUTINE
LPPAGESETUPDLGA
LPPALETTEENTRY
LPPERSISTSTORAGE
LPPHONEBUTTONINFO
LPPHONECAPS
LPPHONEEXTENSIONID
LPPHONESTATUS
LPPIXELFORMATDESCRIPTOR
LPPOINT
LPPRINTDLGA
LPPRINTDLGW
LPPRINTER_DEFAULTSA
LPPRINTER_DEFAULTSW
LPPROCESSENTRY
LPPROCESS_HEAP_ENTRY *
LPPROCESS_INFORMATION
LPPROGRESS_ROUTINE
LPRASCONNA
LPRASTERIZER_STATUS
LPRECT
LPRGNDATA
LPRTL_RWLOCK
LPRUNNINGOBJECTTABLE *
LPSCROLLINFO
LPSECURITY_ATTRIBUTES
LPSERVICE_STATUS
LPSERVICE_TABLE_ENTRYA
LPSERVICE_TABLE_ENTRYW
LPSHELLEXECUTEINFOA
LPSHELLEXECUTEINFOW
LPSHELLFLAGSTATE
LPSHELLFOLDER
LPSHELLVIEWDATA
LPSHFILEOPSTRUCTA
LPSHFILEOPSTRUCTW
LPSIZE
LPSMALL_RECT
LPSRB
LPSTARTUPINFOA
LPSTARTUPINFOW
LPSTORAGE
LPSTR *
LPSTR **
LPSTREAM
LPSTREAM *
LPSTRRET
LPSTYLEBUFA
LPSTYLEBUFW
LPSYSTEMTIME
LPSYSTEM_INFO
LPSYSTEM_POWER_STATUS
LPTHREAD_START_ROUTINE
LPTIMECALLBACK
LPTIMECAPS
LPTIME_ZONE_INFORMATION
LPTOP_LEVEL_EXCEPTION_FILTER
LPTPMPARAMS
LPUINT
LPUNKNOWN
LPUNKNOWN *
LPVARSTRING
LPVOID
LPVOID *
LPWAVEFORMATEX
LPWAVEINCAPSA
LPWAVEINCAPSW
LPWAVEOUTCAPSA
LPWAVEOUTCAPSW
LPWORD
LPWSADATA
LPWSTR *
LPXFORM
MAT2 *
MENUITEMINFOA *
MENUITEMINFOW *
METARECORD *
MFENUMPROC
MIDIHDR *
MMCKINFO *
MMIOINFO *
MONITORENUMPROC
MSG *
MULTI_QI *
NOTIFYCALLBACK
NUMBERFMTA *
NUMBERFMTW *
OFSTRUCT *
OSVERSIONINFOA *
OSVERSIONINFOW *
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
PCHAR *
PCONTEXT
PDWORD
PENUMLOADED_MODULES_CALLBACK
PEXCEPTION_FRAME
PEXCEPTION_FRAME *
PEXCEPTION_POINTERS
PEXCEPTION_RECORD
PFLOAT
PFNCALLBACK
PFNDPACOMPARE
PFNDPAMERGE
PFUNCTION_TABLE_ACCESS_ROUTINE
PGENERIC_MAPPING
PGETFRAME
PGET_MODULE_BASE_ROUTINE
PHACMDRIVER
PHACMDRIVERID
PHACMSTREAM
PHONECALLBACK
PIMAGEHLP_MODULE
PIMAGEHLP_STATUS_ROUTINE
PIMAGEHLP_SYMBOL
PIMAGE_DEBUG_INFORMATION
PIMAGE_LOAD_CONFIG_DIRECTORY
PIMAGE_NT_HEADERS
PIMAGE_SECTION_HEADER
PIMAGE_SECTION_HEADER *
PIO_STATUS_BLOCK
PIXELFORMATDESCRIPTOR *
PLARGE_INTEGER
PLOADED_IMAGE
PLONG
PLUID
PNOTIFYICONDATAA
POBJECT_ATTRIBUTES
POINT *
PPRIVILEGE_SET
PREAD_PROCESS_MEMORY_ROUTINE
PRTL_HEAP_DEFINITION
PROPENUMPROCA
PROPENUMPROCEXA
PROPENUMPROCEXW
PROPENUMPROCW
PSECURITY_DESCRIPTOR
PSECURITY_DESCRIPTOR_CONTROL
PSECURITY_QUALITY_OF_SERVICE
PSID
PSID *
PSID_IDENTIFIER_AUTHORITY
PSID_NAME_USE
PSTACKFRAME
PSTRING
PSYMBOL_REGISTERED_CALLBACK
PSYM_ENUMMODULES_CALLBACK
PSYM_ENUMSYMBOLS_CALLBACK
PTIMERAPCROUTINE
PTRANSLATE_ADDRESS_ROUTINE
PUCHAR
PULARGE_INTEGER
PULONG
PUNICODE_STRING
PVOID
PVOID *
PWAVEFILTER
PWAVEFORMATEX
PWIN_CERTIFICATE
RECT *
REFCLSID
REFGUID
REFIID
REGISTERWORDENUMPROCA
REGISTERWORDENUMPROCW
RGBQUAD *
RGNDATA *
SAFEARRAY *
SAFEARRAY **
SAFEARRAYBOUND *
SCROLLINFO *
SECURITY_ATTRIBUTES *
SECURITY_DESCRIPTOR *
SECURITY_INFORMATION *
SHFILEINFOA *
SHFILEINFOW *
SNB
STGMEDIUM *
SYSLEVEL *
SYSLEVEL **
SYSTEMTIME *
TEXTMETRICA *
TEXTMETRICW *
TIMEFMT_ENUMPROCA
TIMEFMT_ENUMPROCW
TIMERPROC
UINT *
ULONG *
USHORT *
VARIANT *
VARIANTARG *
VARIANT_BOOL *
VOID *
VOID **
WAVEHDR *
WCHAR *
WIN32_FIND_DATAA *
WIN32_FIND_DATAW *
WINDOWPLACEMENT *
WNDCLASSA *
WNDCLASSEXA *
WNDCLASSEXW *
WNDCLASSW *
WNDENUMPROC
WNDPROC
WORD *
XFORM *
YIELDPROC
_INITTERMFUN *
char *
double *
jmp_buf
short *
struct _TEB *
struct ThunkDataCommon *
struct find_t *
struct sockaddr *
struct stat *
struct timeval *
struct win_stat *
struct WIN_hostent *
struct WIN_protoent *
struct WIN_servent *
time_t *
va_list
void *
void **
ws_fd_set32 *
%str
LPCSTR
LPSTR
OLECHAR *
%unknown
new_handler_type
sig_handler_type
struct in_addr
%void
void
VOID
%wstr
BSTR
LPCOLESTR
LPCWSTR
LPWSTR
%long # --forbidden
BOOL16
FARPROC16
HTASK16
HGLOBAL16
HINSTANCE16
HMMIO16
HMODULE16
LPOLESTR16
UINT16
SOCKET16
int
long
short
u_long
u_short
unsigned

View File

@ -0,0 +1,318 @@
package winapi;
use strict;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $allowed_kind = \%{$self->{ALLOWED_KIND}};
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
$self->{NAME} = shift;
my $file = shift;
my @modules;
my $kind;
my $forbidden = 0;
open(IN, "< $file") || die "$file: $!\n";
$/ = "\n";
while(<IN>) {
s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
s/^(.*?)\s*#.*$/$1/; # remove comments
/^$/ && next; # skip empty lines
if(s/^%(\S+)\s*//) {
$kind = $1;
@modules = ();
$forbidden = 0;
$$allowed_kind{$kind} = 1;
if(/^--module=(\S*)/) {
@modules = split(/,/, $1);
} elsif(/^--forbidden/) {
$forbidden = 1;
}
} elsif(defined($kind)) {
my $type = $_;
if(!$forbidden) {
for my $module (@modules) {
$$allowed_modules_limited{$type} = 1;
$$allowed_modules{$type}{$module} = 1;
}
} else {
$$allowed_modules_limited{$type} = 1;
}
$$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 {
my $proto = shift;
my $class = ref($proto) || $proto;
my $file = shift;
my $type;
open(IN, "< $file") || die "$file: $!\n";
$/ = "\n";
while(<IN>) {
if(/^type\s*(\w+)/) {
$type = $1;
last;
}
}
close(IN);
return $type;
}
sub read_spec_files {
my $proto = shift;
my $class = ref($proto) || $proto;
my $win16api = shift;
my $win32api = shift;
foreach my $file (split(/\n/, `find . -name \\*.spec`)) {
my $type = 'winapi'->get_spec_file_type($file);
if($type eq "win16") {
$win16api->parse_spec_file($file);
} elsif($type eq "win32") {
$win32api->parse_spec_file($file);
}
}
}
sub parse_spec_file {
my $self = shift;
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 $type;
my $module;
open(IN, "< $file") || die "$file: $!\n";
$/ = "\n";
my $header = 1;
my $lookahead = 0;
while($lookahead || defined($_ = <IN>)) {
$lookahead = 0;
s/^\s*(.*?)\s*$/$1/;
s/^(.*?)\s*#.*$/$1/;
/^$/ && next;
if($header) {
if(/^name\s*(\S*)/) { $module = $1; }
if(/^\d+/) { $header = 0 };
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;
# 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_stub{$external_name} = 1;
$$function_module{$external_name} = $module;
} elsif(/^\d+\s+(equate|long|word|extern|forward)/) {
# ignore
} else {
my $next_line = <IN>;
if($next_line =~ /^\d/) {
die "$file: $.: syntax error: '$_'\n";
} else {
$_ .= $next_line;
$lookahead = 1;
}
}
}
close(IN);
}
sub name {
my $self = shift;
return $self->{NAME};
}
sub is_allowed_kind {
my $self = shift;
my $allowed_kind = \%{$self->{ALLOWED_KIND}};
my $kind = shift;
if(defined($kind)) {
return $$allowed_kind{$kind};
} else {
return 0;
}
}
sub allowed_type_in_module {
my $self = shift;
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
my $type = shift;
my $module = shift;
return !$$allowed_modules_limited{$type} || $$allowed_modules{$type}{$module};
}
sub translate_argument {
my $self = shift;
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
my $argument = shift;
return $$translate_argument{$argument};
}
sub all_declared_types {
my $self = shift;
my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
return sort(keys(%$translate_argument));
}
sub found_type {
my $self = shift;
my $type_found = \%{$self->{TYPE_FOUND}};
my $name = shift;
$$type_found{$name}++;
}
sub type_found {
my $self = shift;
my $type_found= \%{$self->{TYPE_FOUND}};
my $name = shift;
return $$type_found{$name};
}
sub all_functions {
my $self = shift;
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
return sort(keys(%$function_calling_convention));
}
sub all_functions_found {
my $self = shift;
my $function_found = \$self->{FUNCTION_FOUND};
return sort(keys(%$function_found));
}
sub function_calling_convention {
my $self = shift;
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
my $name = shift;
return $$function_calling_convention{$name};
}
sub is_function {
my $self = shift;
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
my $name = shift;
return $$function_calling_convention{$name};
}
sub is_shared_function {
my $self = shift;
my $function_shared = \%{$self->{FUNCTION_SHARED}};
my $name = shift;
return $$function_shared{$name};
}
sub found_shared_function {
my $self = shift;
my $function_shared = \%{$self->{FUNCTION_SHARED}};
my $name = shift;
$$function_shared{$name} = 1;
}
sub function_arguments {
my $self = shift;
my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
my $name = shift;
return $$function_arguments{$name};
}
sub function_module {
my $self = shift;
my $function_module = \%{$self->{FUNCTION_MODULE}};
my $name = shift;
if($self->is_function($name)) {
return $$function_module{$name};
} else {
return undef;
}
}
sub function_stub {
my $self = shift;
my $function_stub = \%{$self->{FUNCTION_STUB}};
my $name = shift;
return $$function_stub{$name};
}
sub found_function {
my $self = shift;
my $function_found = \%{$self->{FUNCTION_FOUND}};
my $name = shift;
$$function_found{$name}++;
}
sub function_found {
my $self = shift;
my $function_found = \%{$self->{FUNCTION_FOUND}};
my $name = shift;
return $$function_found{$name};
}
1;

118
tools/winapi_check/winapi_check Executable file
View File

@ -0,0 +1,118 @@
#!/usr/bin/perl -w
# Copyright 1999 Patrik Stridvall
use strict;
BEGIN {
require "tools/winapi_check/winapi.pm";
require "tools/winapi_check/nativeapi.pm";
require "tools/winapi_check/winapi_local.pm";
require "tools/winapi_check/winapi_global.pm";
require "tools/winapi_check/winapi_options.pm";
require "tools/winapi_check/winapi_parser.pm";
import winapi;
import nativeapi;
import winapi_local;
import winapi_global;
import winapi_options;
import winapi_parser;
}
my $options = winapi_options->new(\@ARGV);
if($options->help) {
$options->show_help;
exit;
}
my $win16api = 'winapi'->new("win16", "tools/winapi_check/win16api.dat");
my $win32api = 'winapi'->new("win32", "tools/winapi_check/win32api.dat");
'winapi'->read_spec_files($win16api, $win32api);
my $nativeapi = 'nativeapi'->new("tools/winapi_check/nativeapi.dat");
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) {
print "*.spec: $name: is shared between $module16 (Win16) and $module32 (Win32)\n";
}
}
}
foreach my $file ($options->files) {
my $found_function = sub {
my $return_type = shift;
my $calling_convention = shift;
my $name = shift;
my $refarguments = shift;
my @arguments = @$refarguments;
if($options->global) {
$win16api->found_type($return_type) if $options->win16;
$win32api->found_type($return_type) if $options->win32;
for my $argument (@arguments) {
$win16api->found_type($argument) if $options->win16;
$win32api->found_type($argument) if $options->win32;
}
$win16api->found_function($name) if $options->win16;
$win32api->found_function($name) if $options->win32;
}
if($options->local) {
my $module16 = $win16api->function_module($name);
my $module32 = $win32api->function_module($name);
my $output = sub {
my $module = shift;
return sub {
my $msg = shift;
print "$file: $module: $return_type $calling_convention $name(" . join(",", @arguments) . "): $msg\n";
}
};
my $output16 = &$output($module16);
my $output32 = &$output($module32);
if($options->argument) {
if($options->win16 && $options->report_module($module16)) {
winapi_local::check_arguments $options, $output16,
$return_type, $calling_convention, $name, [@arguments], $win16api;
}
if($options->win32 && $options->report_module($module32)) {
winapi_local::check_arguments $options, $output32,
$return_type, $calling_convention, $name, [@arguments], $win32api;
}
}
if($options->misplaced) {
my $module;
if($file =~ m'^dlls/(.*)/') {
$module = $1;
}
if($options->win16 && $options->report_module($module16)) {
if(!defined($module) || $module ne $module16) {
&$output16("function misplaced");
}
}
if($options->win32 && $options->report_module($module32)) {
if(!defined($module) || $module ne $module32) {
&$output32("function misplaced");
}
}
}
}
};
winapi_parser::parse_c_file $options, $file, $found_function;
}
if($options->global) {
winapi_global::check $options, $win16api, $nativeapi if $options->win16;
winapi_global::check $options, $win32api, $nativeapi if $options->win32;
}

View File

@ -0,0 +1,41 @@
package winapi_global;
use strict;
sub check {
my $options = shift;
my $winapi = shift;
my $nativeapi = shift;
my $winver = $winapi->name;
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($options->declared) {
foreach my $name ($winapi->all_functions) {
if(!$winapi->function_found($name) && !$nativeapi->is_function($name)) {
print "*.c: $winver: $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";
}
}
}
}
1;

View File

@ -0,0 +1,136 @@
package winapi_local;
use strict;
sub check_arguments {
my $options = shift;
my $output = shift;
my $return_type = shift;
my $calling_convention = shift;
my $name = shift;
my $refargument_types = shift;
my @argument_types = @$refargument_types;
my $winapi = shift;
my $module = $winapi->function_module($name);
my $forbidden_return_type = 0;
my $implemented_return_kind;
if(!defined($implemented_return_kind = $winapi->translate_argument($return_type))) {
if($return_type ne "") {
&$output("no translation defined: " . $return_type);
}
} elsif(!$winapi->is_allowed_kind($implemented_return_kind) || !$winapi->allowed_type_in_module($return_type,$module)) {
$forbidden_return_type = 1;
if($options->report_argument_forbidden($return_type)) {
&$output("forbidden return type: $return_type ($implemented_return_kind)");
}
}
my $segmented = 0;
if($implemented_return_kind =~ /^segptr|segstr$/) {
$segmented = 1;
}
my $implemented_calling_convention;
if($winapi->name eq "win16") {
if($calling_convention =~ /^__cdecl$/) {
$implemented_calling_convention = "cdecl";
} elsif($calling_convention = ~ /^__stdcall|VFWAPI|WINAPI$/) {
if($implemented_return_kind =~ /^s_word|word|void$/) {
$implemented_calling_convention = "pascal16";
} else {
$implemented_calling_convention = "pascal";
}
}
} elsif($winapi->name eq "win32") {
if($calling_convention =~ /^__cdecl$/) {
$implemented_calling_convention = "cdecl";
} elsif($calling_convention =~ /^VFWAPIV|WINAPIV$/) {
$implemented_calling_convention = "varargs";
} elsif($calling_convention = ~ /^__stdcall|VFWAPI|WINAPI$/) {
$implemented_calling_convention = "stdcall";
}
}
my $declared_calling_convention = $winapi->function_calling_convention($name);
my @declared_argument_kinds = split(/\s+/, $winapi->function_arguments($name));
if($declared_calling_convention =~ /^register|interrupt$/) {
push @declared_argument_kinds, "ptr";
}
if($declared_calling_convention =~ /^register|interupt$/ &&
(($winapi->name eq "win32" && $implemented_calling_convention eq "stdcall") ||
(($winapi->name eq "win16" && $implemented_calling_convention =~ /^pascal/))))
{
# correct
} elsif($implemented_calling_convention ne $declared_calling_convention &&
!($declared_calling_convention =~ /^pascal/ && $forbidden_return_type))
{
if($options->calling_convention) {
&$output("calling convention mismatch: $implemented_calling_convention != $declared_calling_convention");
}
}
if($declared_calling_convention eq "varargs") {
if($#argument_types != -1 && $argument_types[$#argument_types] eq "...") {
pop @argument_types;
} else {
&$output("function not implemented as vararg");
}
} elsif($#argument_types != -1 && $argument_types[$#argument_types] eq "...") {
&$output("function not declared as vararg");
}
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";
if(!defined($kind = $winapi->translate_argument($type))) {
&$output("no translation defined: " . $type);
} elsif(!$winapi->is_allowed_kind($kind) ||
!$winapi->allowed_type_in_module($type, $module)) {
if($options->report_argument_forbidden($type)) {
&$output("forbidden argument " . ($n + 1) . " type (" . $type . ")");
}
}
$n++;
$kind;
} @argument_types;
for my $n (0..$#argument_kinds) {
if(!defined($argument_kinds[$n]) || !defined($declared_argument_kinds[$n])) { next; }
if($argument_kinds[$n] =~ /^segptr|segstr$/ ||
$declared_argument_kinds[$n] =~ /^segptr|segstr$/)
{
$segmented = 1;
}
if($argument_kinds[$n] ne $declared_argument_kinds[$n]) {
if($options->report_argument_kind($argument_kinds[$n]) ||
$options->report_argument_kind($declared_argument_kinds[$n]))
{
&$output("argument " . ($n + 1) . " type mismatch: " .
$argument_types[$n] . " ($argument_kinds[$n]) != " . $declared_argument_kinds[$n]);
}
}
}
}
if($segmented && $options->shared_segmented && $winapi->is_shared_function($name)) {
&$output("function using segmented pointers shared between Win16 och Win32");
}
}
1;

View File

@ -0,0 +1,272 @@
package winapi_options;
use strict;
sub parser_comma_list {
my $prefix = shift;
my $value = shift;
if(defined($prefix) && $prefix eq "no") {
return { active => 0, filter => 0, hash => {} };
} elsif(defined($value)) {
my %names;
for my $name (split /,/, $value) {
$names{$name} = 1;
}
return { active => 1, filter => 1, hash => \%names };
} else {
return { active => 1, filter => 0, hash => {} };
}
}
my %options = (
"debug" => { default => 0, description => "debug mode" },
"help" => { default => 0, description => "help mode" },
"verbose" => { default => 0, description => "verbose mode" },
"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" },
"local" => { default => 1, description => "local checking" },
"module" => {
default => { active => 1, filter => 0, hash => {} },
parent => "local",
parser => \&parser_comma_list,
description => "module filter"
},
"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 => {} },
parent => "argument",
parser => \&parser_comma_list,
description => "argument forbidden checking"
},
"argument-kind" => {
default => { active => 0, filter => 0, hash => {} },
parent => "argument",
parser => \&parser_comma_list,
description => "argument kind checking"
},
"calling-convention" => { default => 0, parent => "local", description => "calling convention checking" },
"misplaced" => { default => 0, parent => "local", description => "checking for misplaced functions" },
"global" => { default => 1, description => "global checking" },
"declared" => { default => 1, parent => "global", description => "declared checking" },
"implemented" => { default => 0, parent => "global", description => "implemented checking" }
);
my %short_options = (
"d" => "debug",
"?" => "help",
"v" => "verbose"
);
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $refarguments = shift;
my @ARGV = @$refarguments;
for my $name (sort(keys(%options))) {
my $option = $options{$name};
my $key = uc($name);
$key =~ tr/-/_/;
$$option{key} = $key;
my $refvalue = \${$self->{$key}};
$$refvalue = $$option{default};
}
my $files = \@{$self->{FILES}};
my $module = \${$self->{MODULE}};
my $global = \${$self->{GLOBAL}};
while(defined($_ = shift @ARGV)) {
if(/^-([^=]*)(=(.*))?$/) {
my $name;
my $value;
if(defined($2)) {
$name = $1;
$value = $3;
} else {
$name = $1;
}
if($name =~ /^([^-].*)$/) {
$name = $short_options{$1};
} else {
$name =~ s/^-(.*)$/$1/;
}
my $prefix;
if($name =~ /^no-(.*)$/) {
$name = $1;
$prefix = "no";
if(defined($value)) {
print STDERR "<internal>: options with prefix 'no' can't take parameters\n";
exit 1;
}
}
my $option = $options{$name};
if(defined($option)) {
my $key = $$option{key};
my $parser = $$option{parser};
my $refvalue = \${$self->{$key}};
if(defined($parser)) {
$$refvalue = &$parser($prefix,$value);
} else {
if(defined($value)) {
$$refvalue = $value;
} elsif(!defined($prefix)) {
$$refvalue = 1;
} else {
$$refvalue = 0;
}
}
next;
}
}
if(/^--module-dlls$/) {
my @dirs = `cd dlls && find ./ -type d ! -name CVS`;
my %names;
for my $dir (@dirs) {
chomp $dir;
$dir =~ s/^\.\/(.*)$/$1/;
next if $dir eq "";
$names{$dir} = 1;
}
$$module = { active => 1, filter => 1, hash => \%names };
}
elsif(/^-(.*)$/) {
print STDERR "<internal>: unknown option: $&\n";
print STDERR "<internal>: usage: winapi-check [--help] [<files>]\n";
exit 1;
} else {
push @$files, $_;
}
}
if($#$files == -1) {
@$files = map {
s/^.\/(.*)$/$1/;
$_;
} split(/\n/, `find . -name \\*.c`);
} else {
$$global = 0
}
return $self;
}
sub show_help {
my $self = shift;
my $maxname = 0;
for my $name (sort(keys(%options))) {
if(length($name) > $maxname) {
$maxname = length($name);
}
}
print "usage: winapi-check [--help] [<files>]\n";
print "\n";
for my $name (sort(keys(%options))) {
my $option = $options{$name};
my $description = $$option{description};
my $default = $$option{default};
my $output;
if(ref($default) ne "HASH") {
if($default) {
$output = "--no-$name";
} else {
$output = "--$name";
}
} else {
if($default->{active}) {
$output = "--[no-]$name\[=<value>]";
} else {
$output = "--$name\[=<value>]";
}
}
print "$output";
for (0..(($maxname - length($name) + 14) - (length($output) - length($name) + 1))) { print " "; }
if(ref($default) ne "HASH") {
if($default) {
print "Disable $description\n";
} else {
print "Enable $description\n";
}
} else {
if($default->{active}) {
print "(Disable) $description\n";
} else {
print "Enable $description\n";
}
}
}
}
sub AUTOLOAD {
my $self = shift;
my $name = $winapi_options::AUTOLOAD;
$name =~ s/^.*::(.[^:]*)$/\U$1/;
my $refvalue = $self->{$name};
if(!defined($refvalue)) {
die "<internal>: winapi_options.pm: member $name does not exists\n";
}
return $$refvalue;
}
sub files { my $self = shift; return @{$self->{FILES}}; }
sub report_module {
my $self = shift;
my $module = $self->module;
my $name = shift;
if(defined($name)) {
return $module->{active} && (!$module->{filter} || $module->{hash}->{$name});
} else {
return 0;
}
}
sub report_argument_forbidden {
my $self = shift;
my $argument_forbidden = $self->argument_forbidden;
my $type = shift;
return $argument_forbidden->{active} && (!$argument_forbidden->{filter} || $argument_forbidden->{hash}->{$type});
}
sub report_argument_kind {
my $self = shift;
my $argument_kind = $self->argument_kind;
my $kind = shift;
return $argument_kind->{active} && (!$argument_kind->{filter} || $argument_kind->{hash}->{$kind});
}
1;

View File

@ -0,0 +1,161 @@
package winapi_parser;
use strict;
sub parse_c_file {
my $options = shift;
my $file = shift;
my $function_found_callback = shift;
my $level = 0;
my $again = 0;
my $lookahead = 0;
my $lookahead_count = 0;
print STDERR "Processing file '$file' ... " if $options->verbose;
open(IN, "< $file") || die "<internal>: $file: $!\n";
$/ = "\n";
while($again || defined(my $line = <IN>)) {
if(!$again) {
chomp $line;
if($lookahead) {
$lookahead = 0;
$_ .= "\n" . $line;
} else {
$_ = $line;
$lookahead_count = 0;
}
$lookahead_count++;
print "$level: $line\n" if $options->debug >= 2;
} else {
$lookahead_count = 0;
$again = 0;
}
# remove comments
if(s/^(.*?)\/\*.*?\*\/(.*)$/$1 $2/s) { $again = 1; next };
if(/^(.*?)\/\*/s) {
$lookahead = 1;
next;
}
# remove empty rows
if(/^\s*$/) { next; }
# remove preprocessor directives
if(s/^\s*\#.*$//m) { $again = 1; next; }
if($level > 0)
{
s/^[^\{\}]*//s;
if(/^\{/) {
$_ = $'; $again = 1;
print "+1: $_\n" if $options->debug >= 2;
$level++;
} elsif(/^\}/) {
$_ = $'; $again = 1;
print "-1: $_\n" if $options->debug >= 2;
$level--;
}
next;
} 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 ";") {
next;
} elsif($9 eq "{") {
$level++;
}
my $return_type = $1;
my $calling_convention = $5;
my $name = $6;
my $arguments = $8;
$return_type =~ s/\s*$//;
$return_type =~ s/\s*\*\s*/*/g;
$return_type =~ s/(\*+)/ $1/g;
$name =~ s/^REGS_FUNC\((.*?)\)/$1/;
$arguments =~ y/\t\n/ /;
$arguments =~ s/^\s*(.*?)\s*$/$1/;
if($arguments eq "") { $arguments = "void" }
my @arguments = split(/,/, $arguments);
foreach my $n (0..$#arguments) {
my $argument = $arguments[$n];
$argument =~ s/^\s*(.*?)\s*$/$1/;
#print " " . ($n + 1) . ": '$argument'\n";
$argument =~ s/^(const(?=\s)|IN(?=\s)|OUT(?=\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";
}
} else {
die "$file: $.: syntax error: '$argument'\n";
}
$arguments[$n] = $argument;
#print " " . ($n + 1) . ": '" . $arguments[$n] . "'\n";
}
if($#arguments == 0 && $arguments[0] =~ /^void$/i) { $#arguments = -1; }
if($options->debug) {
print "$file: $return_type $calling_convention $name(" . join(",", @arguments) . ")\n";
}
&$function_found_callback($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);
} elsif(/DC_(GET_VAL_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,.*?\)/s) {
$_ = $'; $again = 1;
my @arguments = ("HDC");
&$function_found_callback($2, "WINAPI", $3, \@arguments);
} 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);
} 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);
} elsif(/WAVEOUT_SHORTCUT_(1|2)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
$_ = $'; $again = 1;
print "$_";
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);
} 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)
}
} elsif(/;/s) {
$_ = $'; $again = 1;
} elsif(/\{/s) {
$_ = $'; $again = 1;
print "+1: $_\n" if $options->debug >= 2;
$level++;
} else {
$lookahead = 1;
}
}
close(IN);
print STDERR "done\n" if $options->verbose;
print "$file: <>: not at toplevel at end of file\n" unless $level == 0;
}
1;