fpc/rtl/win32/syswin32.pp
1998-06-10 10:39:11 +00:00

626 lines
15 KiB
ObjectPascal

{
$Id$
This file is part of the Free Pascal run time library.
Copyright (c) 1993-98 by Florian Klaempfl and Pavel Ozerski
member of the Free Pascal development team.
FPC Pascal system unit for the Win32 API.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{$S-}
unit syswin32;
{$I os.inc}
interface
{ include system-independent routine headers }
{$I systemh.inc}
const
{ Default filehandles }
UnusedHandle : longint = -1;
StdInputHandle : longint = 0;
StdOutputHandle : longint = 0;
StdErrorHandle : longint = 0;
type
TStartupInfo=packed record
cb : longint;
lpReserved : Pointer;
lpDesktop : Pointer;
lpTitle : Pointer;
dwX : longint;
dwY : longint;
dwXSize : longint;
dwYSize : longint;
dwXCountChars : longint;
dwYCountChars : longint;
dwFillAttribute : longint;
dwFlags : longint;
wShowWindow : Word;
cbReserved2 : Word;
lpReserved2 : Pointer;
hStdInput : longint;
hStdOutput : longint;
hStdError : longint;
end;
var
startupinfo : tstartupinfo;
hprevinst,
hinstance,
cmdshow : longint;
heaperror : pointer;
implementation
{ include system independent routines }
{$I system.inc}
{ some declarations for Win32 API calls }
{$I win32.inc}
type
plongint = ^longint;
{ misc. functions }
function GetLastError : DWORD;
external 'kernel32' name 'GetLastError';
function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
external 'user32' name 'MessageBoxA';
{ command line/enviroment functions }
function GetCommandLine : LPTSTR;
external 'kernel32' name 'GetCommandLineA';
{ time and date functions }
function GetTickCount : longint;
external 'kernel32' name 'GetTickCount';
{ process functions }
procedure ExitProcess(uExitCode : UINT);
external 'kernel32' name 'ExitProcess';
{$ifdef dummy}
procedure int_stackcheck(stack_size:longint);[public,alias: 'STACKCHECK'];
{
called when trying to get local stack if the compiler directive $S
is set this function must preserve esi !!!! because esi is set by
the calling proc for methods it must preserve all registers !!
}
begin
asm
pushl %eax
pushl %ebx
movl stack_size,%ebx
movl %esp,%eax
subl %ebx,%eax
{$ifdef SYSTEMDEBUG}
movl U_SYSTEM_LOWESTSTACK,%ebx
cmpl %eax,%ebx
jb _is_not_lowest
movl %eax,U_SYSTEM_LOWESTSTACK
_is_not_lowest:
{$endif SYSTEMDEBUG}
movl __stkbottom,%ebx
cmpl %eax,%ebx
jae __short_on_stack
popl %ebx
popl %eax
leave
ret $4
__short_on_stack:
{ can be usefull for error recovery !! }
popl %ebx
popl %eax
end['EAX','EBX'];
RunError(202);
end;
{$endif dummy}
procedure halt(errnum : byte);
begin
do_exit;
flush(stderr);
ExitProcess(errnum);
end;
function paramcount : longint;
var
count : longint;
cmdline : pchar;
quote : set of char;
begin
cmdline:=GetCommandLine;
count:=0;
while true do
begin
{ skip leading spaces }
while cmdline^ in [' ',#9] do
cmdline:=cmdline+1;
if cmdline^='"' then
begin
quote:=['"'];
cmdline:=cmdline+1;
end
else
quote:=[' ',#9];
if cmdline^=#0 then
break;
inc(count);
while (cmdline^<>#0) and not(cmdline^ in quote) do
cmdline:=cmdline+1;
{ skip quote }
if cmdline^ in quote then
cmdline:=cmdline+1;
end;
paramcount:=count-1;
end;
function paramstr(l : longint) : string;
var
s : string;
count : longint;
cmdline : pchar;
quote : set of char;
begin
s:='';
if (l>=0) and (l<=paramcount) then
begin
cmdline:=GetCommandLine;
count:=0;
while true do
begin
{ skip leading spaces }
while cmdline^ in [' ',#9] do
cmdline:=cmdline+1;
if cmdline^='"' then
begin
quote:=['"'];
cmdline:=cmdline+1;
end
else
quote:=[' ',#9];
if cmdline^=#0 then
break;
if count=l then
begin
while (cmdline^<>#0) and not(cmdline^ in quote) do
begin
s:=s+cmdline^;
cmdline:=cmdline+1;
end;
break;
end
else
begin
while (cmdline^<>#0) and not(cmdline^ in quote) do
cmdline:=cmdline+1;
end;
{ skip quote }
if cmdline^ in quote then
cmdline:=cmdline+1;
inc(count);
end;
end;
paramstr:=s;
end;
procedure randomize;
begin
randseed:=GetTickCount;
end;
{*****************************************************************************
Heap Management
*****************************************************************************}
{ Include Windows Heap manager }
{$I winheap.inc}
{*****************************************************************************
Low Level File Routines
*****************************************************************************}
function WriteFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
overlap:pointer):longint;
external 'kernel32' name 'WriteFile';
function ReadFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
overlap:pointer):longint;
external 'kernel32' name 'ReadFile';
function CloseHandle(h : longint) : longint;
external 'kernel32' name 'CloseHandle';
function DeleteFile(p : pchar) : longint;
external 'kernel32' name 'DeleteFileA';
function MoveFile(old,_new : pchar) : longint;
external 'kernel32' name 'MoveFileA';
function SetFilePointer(l1,l2 : longint;l3 : pointer;l4 : longint) : longint;
external 'kernel32' name 'SetFilePointer';
function GetFileSize(h:longint;p:pointer) : longint;
external 'kernel32' name 'GetFileSize';
function CreateFile(name : pointer;access,sharing : longint;
security : pointer;how,attr,template : longint) : longint;
external 'kernel32' name 'CreateFileA';
function SetEndOfFile(h : longint) : boolean;
external 'kernel32' name 'SetEndOfFile';
procedure AllowSlash(p:pchar);
var
i : longint;
begin
{ allow slash as backslash }
for i:=0 to strlen(p) do
if p[i]='/' then p[i]:='\';
end;
procedure do_close(h : longint);
begin
closehandle(h);
end;
procedure do_erase(p : pchar);
begin
AllowSlash(p);
if DeleteFile(p)=0 then
inoutres:=GetLastError;
end;
procedure do_rename(p1,p2 : pchar);
begin
AllowSlash(p1);
AllowSlash(p2);
if MoveFile(p1,p2)=0 then
inoutres:=GetLastError;
end;
function do_write(h,addr,len : longint) : longint;
var
size:longint;
begin
if writefile(h,pointer(addr),len,size,nil)=0 then
inoutres:=GetLastError;
do_write:=size;
end;
function do_read(h,addr,len : longint) : longint;
var
result:longint;
begin
if readfile(h,pointer(addr),len,result,nil)=0 then
inoutres:=GetLastError;
do_read:=result;
end;
function do_filepos(handle : longint) : longint;
var
l:longint;
begin
l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
if l=-1 then
begin
l:=0;
inoutres:=GetLastError;
end;
do_filepos:=l;
end;
procedure do_seek(handle,pos : longint);
begin
if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
inoutres:=GetLastError;
end;
function do_seekend(handle:longint):longint;
begin
do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
if do_seekend=-1 then
begin
inoutres:=GetLastError;
do_seekend:=0;
end;
end;
function do_filesize(handle : longint) : longint;
var
aktfilepos : longint;
begin
aktfilepos:=do_filepos(handle);
do_filesize:=do_seekend(handle);
do_seek(handle,aktfilepos);
end;
procedure do_truncate (handle,pos:longint);
begin
do_seek(handle,pos);
if not(SetEndOfFile(handle)) then
inoutres:=GetLastError;
end;
procedure do_open(var f;p : pchar;flags:longint);
{
filerec and textrec have both handle and mode as the first items so
they could use the same routine for opening/creating.
when (flags and $10) the file will be append
when (flags and $100) the file will be truncate/rewritten
when (flags and $1000) there is no check for close (needed for textfiles)
}
var
oflags,cd : longint;
begin
AllowSlash(p);
{ close first if opened }
if ((flags and $1000)=0) then
begin
case filerec(f).mode of
fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
fmclosed : ;
else
begin
{not assigned}
inoutres:=102;
exit;
end;
end;
end;
{ reset file handle }
filerec(f).handle:=UnusedHandle;
{ convert filemode to filerec modes }
case (flags and 3) of
0 : begin
filerec(f).mode:=fminput;
oflags:=GENERIC_READ;
end;
1 : begin
filerec(f).mode:=fmoutput;
oflags:=GENERIC_WRITE;
end;
2 : begin
filerec(f).mode:=fminout;
oflags:=GENERIC_WRITE or GENERIC_READ;
end;
end;
{ standard is opening and existing file }
cd:=OPEN_EXISTING;
{ create it ? }
if (flags and $100)<>0 then
cd:=CREATE_ALWAYS
{ or append ? }
else
if (flags and $10)<>0 then
cd:=OPEN_ALWAYS;
{ empty name is special }
if p[0]=#0 then
begin
case filerec(f).mode of
fminput : filerec(f).handle:=StdInputHandle;
fmappend,
fmoutput : begin
filerec(f).handle:=StdOutputHandle;
filerec(f).mode:=fmoutput; {fool fmappend}
end;
end;
exit;
end;
filerec(f).handle:=CreateFile(p,oflags,0,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
{ append mode }
if (flags and $10)<>0 then
begin
do_seekend(filerec(f).handle);
filerec(f).mode:=fmoutput; {fool fmappend}
end;
{ get errors }
if filerec(f).handle=0 then
inoutres:=GetLastError;
end;
{*****************************************************************************
UnTyped File Handling
*****************************************************************************}
{$i file.inc}
{*****************************************************************************
Typed File Handling
*****************************************************************************}
{$i typefile.inc}
{*****************************************************************************
Text File Handling
*****************************************************************************}
{$DEFINE EOF_CTRLZ}
{$i text.inc}
{*****************************************************************************
Directory Handling
*****************************************************************************}
function CreateDirectory(name : pointer;sec : pointer) : longint;
external 'kernel32' name 'CreateDirectoryA';
function RemoveDirectory(name:pointer):longint;
external 'kernel32' name 'RemoveDirectoryA';
function SetCurrentDirectory(name : pointer) : longint;
external 'kernel32' name 'SetCurrentDirectoryA';
function GetCurrentDirectory(bufsize : longint;name : pchar) : longint;
external 'kernel32' name 'GetCurrentDirectoryA';
type
TDirFnType=function(name:pointer):word;
procedure dirfn(afunc : TDirFnType;const s:string);
var
buffer : array[0..255] of char;
begin
move(s[1],buffer,length(s));
buffer[length(s)]:=#0;
AllowSlash(pchar(@buffer));
if aFunc(@buffer)=0 then
inoutres:=GetLastError;
end;
function CreateDirectoryTrunc(name:pointer):word;
begin
CreateDirectoryTrunc:=CreateDirectory(name,nil);
end;
procedure mkdir(const s:string);[IOCHECK];
begin
dirfn(TDirFnType(@CreateDirectoryTrunc),s);
end;
procedure rmdir(const s:string);[IOCHECK];
begin
dirfn(TDirFnType(@RemoveDirectory),s);
end;
procedure chdir(const s:string);[IOCHECK];
begin
dirfn(TDirFnType(@SetCurrentDirectory),s);
end;
procedure getdir(drivenr:byte;var dir:string);
const
Drive:array[0..3]of char=(#0,':',#0,#0);
var
defaultdrive:boolean;
DirBuf,SaveBuf:array[0..259] of Char;
begin
defaultdrive:=drivenr=0;
if not defaultdrive then
begin
byte(Drive[0]):=Drivenr+64;
GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
SetCurrentDirectory(@Drive);
end;
GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
if not defaultdrive then
SetCurrentDirectory(@SaveBuf);
dir:=strpas(DirBuf);
end;
{*****************************************************************************
SystemUnit Initialization
*****************************************************************************}
{ Startup }
procedure GetStartupInfo(p : pointer);
external 'kernel32' name 'GetStartupInfoA';
function GetStdHandle(nStdHandle:DWORD):THANDLE;
external 'kernel32' name 'GetStdHandle';
{ module functions }
function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
external 'kernel32' name 'GetModuleFileNameA';
function GetModuleHandle(p : pointer) : longint;
external 'kernel32' name 'GetModuleHandleA';
{$ASMMODE DIRECT}
procedure Entry;[public,alias: '_mainCRTStartup'];
begin
{ call to the pascal main }
asm
call PASCALMAIN
end;
{ that's all folks }
ExitProcess(0);
end;
{$ASMMODE ATT}
procedure OpenStdIO(var f:text;mode:word;hdl:longint);
begin
Assign(f,'');
TextRec(f).Handle:=hdl;
TextRec(f).Mode:=mode;
TextRec(f).InOutFunc:=@FileInOutFunc;
TextRec(f).FlushFunc:=@FileInOutFunc;
TextRec(f).Closefunc:=@fileclosefunc;
end;
var
s : string;
begin
{ get some helpful informations }
GetStartupInfo(@startupinfo);
{ Initialize ExitProc }
ExitProc:=Nil;
{ to test stack depth }
loweststack:=maxlongint;
{ Setup heap }
{!!! InitHeap; }
{ Setup stdin, stdout and stderr }
StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
OpenStdIO(Input,fmInput,StdInputHandle);
OpenStdIO(Output,fmOutput,StdOutputHandle);
OpenStdIO(StdErr,fmOutput,StdErrorHandle);
{ Reset IO Error }
InOutRes:=0;
{ some misc Win32 stuff }
hprevinst:=0;
getmodulefilename(0,@s,256);
hinstance:=getmodulehandle(@s);
cmdshow:=startupinfo.wshowwindow;
end.
{
$Log$
Revision 1.9 1998-06-10 10:39:17 peter
* working w32 rtl
Revision 1.8 1998/06/08 23:07:47 peter
* dos interface is now 100% compatible
* fixed call PASCALMAIN which must be direct asm
Revision 1.7 1998/05/06 12:36:51 michael
+ Removed log from before restored version.
Revision 1.6 1998/04/27 18:29:09 florian
+ do_open implemented, the file-I/O should be now complete
Revision 1.5 1998/04/27 13:58:21 florian
+ paramstr/paramcount implemented
Revision 1.4 1998/04/26 22:37:22 florian
* some small extensions
Revision 1.3 1998/04/26 21:49:57 florian
+ more stuff added (??dir procedures etc.)
}