mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-12 19:09:35 +02:00
1334 lines
35 KiB
ObjectPascal
1334 lines
35 KiB
ObjectPascal
{
|
|
$Id$
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 1999-2000 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.
|
|
|
|
**********************************************************************}
|
|
unit syswin32;
|
|
interface
|
|
|
|
{$ifdef i386}
|
|
{$define Set_i386_Exception_handler}
|
|
{$endif i386}
|
|
|
|
{ include system-independent routine headers }
|
|
{$I systemh.inc}
|
|
|
|
{ include heap support headers }
|
|
{$I heaph.inc}
|
|
|
|
const
|
|
{ Default filehandles }
|
|
UnusedHandle : longint = -1;
|
|
StdInputHandle : longint = 0;
|
|
StdOutputHandle : longint = 0;
|
|
StdErrorHandle : longint = 0;
|
|
|
|
FileNameCaseSensitive : boolean = true;
|
|
|
|
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
|
|
{ C compatible arguments }
|
|
argc : longint;
|
|
argv : ppchar;
|
|
{ Win32 Info }
|
|
startupinfo : tstartupinfo;
|
|
hprevinst,
|
|
HInstance,
|
|
MainInstance,
|
|
cmdshow : longint;
|
|
IsLibrary,IsMultiThreaded,IsConsole : boolean;
|
|
DLLreason,DLLparam:longint;
|
|
Win32StackTop : Dword;
|
|
{ Thread count for DLL }
|
|
const
|
|
Thread_count : longint = 0;
|
|
type
|
|
TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
|
|
TDLL_Entry_Hook = procedure (dllparam : longint);
|
|
|
|
const
|
|
Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
|
|
Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
|
|
Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
|
|
Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
|
|
|
|
implementation
|
|
|
|
{ include system independent routines }
|
|
{$I system.inc}
|
|
|
|
{ some declarations for Win32 API calls }
|
|
{$I win32.inc}
|
|
|
|
|
|
CONST
|
|
{ These constants are used for conversion of error codes }
|
|
{ from win32 i/o errors to tp i/o errors }
|
|
{ errors 1 to 18 are the same as in Turbo Pascal }
|
|
{ DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING! }
|
|
|
|
{ The media is write protected. }
|
|
ERROR_WRITE_PROTECT = 19;
|
|
{ The system cannot find the device specified. }
|
|
ERROR_BAD_UNIT = 20;
|
|
{ The device is not ready. }
|
|
ERROR_NOT_READY = 21;
|
|
{ The device does not recognize the command. }
|
|
ERROR_BAD_COMMAND = 22;
|
|
{ Data error (cyclic redundancy check) }
|
|
ERROR_CRC = 23;
|
|
{ The program issued a command but the }
|
|
{ command length is incorrect. }
|
|
ERROR_BAD_LENGTH = 24;
|
|
{ The drive cannot locate a specific }
|
|
{ area or track on the disk. }
|
|
ERROR_SEEK = 25;
|
|
{ The specified disk or diskette cannot be accessed. }
|
|
ERROR_NOT_DOS_DISK = 26;
|
|
{ The drive cannot find the sector requested. }
|
|
ERROR_SECTOR_NOT_FOUND = 27;
|
|
{ The printer is out of paper. }
|
|
ERROR_OUT_OF_PAPER = 28;
|
|
{ The system cannot write to the specified device. }
|
|
ERROR_WRITE_FAULT = 29;
|
|
{ The system cannot read from the specified device. }
|
|
ERROR_READ_FAULT = 30;
|
|
{ A device attached to the system is not functioning.}
|
|
ERROR_GEN_FAILURE = 31;
|
|
{ The process cannot access the file because }
|
|
{ it is being used by another process. }
|
|
ERROR_SHARING_VIOLATION = 32;
|
|
|
|
var
|
|
errno : longint;
|
|
|
|
{$ASMMODE ATT}
|
|
|
|
|
|
{ misc. functions }
|
|
function GetLastError : DWORD;
|
|
external 'kernel32' name 'GetLastError';
|
|
|
|
{ time and date functions }
|
|
function GetTickCount : longint;
|
|
external 'kernel32' name 'GetTickCount';
|
|
|
|
{ process functions }
|
|
procedure ExitProcess(uExitCode : UINT);
|
|
external 'kernel32' name 'ExitProcess';
|
|
|
|
|
|
Procedure Errno2InOutRes;
|
|
Begin
|
|
{ DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING }
|
|
if (errno >= ERROR_WRITE_PROTECT) and (errno <= ERROR_GEN_FAILURE) THEN
|
|
BEGIN
|
|
{ This is the offset to the Win32 to add to directly map }
|
|
{ to the DOS/TP compatible error codes when in this range }
|
|
InOutRes := word(errno)+131;
|
|
END
|
|
else
|
|
{ This case is special }
|
|
if errno=ERROR_SHARING_VIOLATION THEN
|
|
BEGIN
|
|
InOutRes :=5;
|
|
END
|
|
else
|
|
{ other error codes can directly be mapped }
|
|
InOutRes := Word(errno);
|
|
errno:=0;
|
|
end;
|
|
|
|
|
|
{$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 !!
|
|
|
|
With a 2048 byte safe area used to write to StdIo without crossing
|
|
the stack boundary
|
|
|
|
}
|
|
begin
|
|
asm
|
|
pushl %eax
|
|
pushl %ebx
|
|
movl stack_size,%ebx
|
|
addl $2048,%ebx
|
|
movl %esp,%eax
|
|
subl %ebx,%eax
|
|
movl stacklimit,%ebx
|
|
cmpl %eax,%ebx
|
|
jae .L__short_on_stack
|
|
popl %ebx
|
|
popl %eax
|
|
leave
|
|
ret $4
|
|
.L__short_on_stack:
|
|
{ can be usefull for error recovery !! }
|
|
popl %ebx
|
|
popl %eax
|
|
end['EAX','EBX'];
|
|
HandleError(202);
|
|
end;
|
|
{$endif dummy}
|
|
|
|
|
|
procedure halt(errnum : byte);
|
|
begin
|
|
ExitCode:=errnum;
|
|
do_exit;
|
|
system_exit;
|
|
end;
|
|
|
|
|
|
function paramcount : longint;
|
|
begin
|
|
paramcount := argc - 1;
|
|
end;
|
|
|
|
{ module functions }
|
|
function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
|
|
external 'kernel32' name 'GetModuleFileNameA';
|
|
function GetModuleHandle(p : pointer) : longint;
|
|
external 'kernel32' name 'GetModuleHandleA';
|
|
function GetCommandFile:pchar;forward;
|
|
|
|
function paramstr(l : longint) : string;
|
|
|
|
begin
|
|
if (l>=0) and (l<argc) then
|
|
paramstr:=strpas(argv[l])
|
|
else
|
|
paramstr:='';
|
|
end;
|
|
|
|
|
|
procedure randomize;
|
|
begin
|
|
randseed:=GetTickCount;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Heap Management
|
|
*****************************************************************************}
|
|
|
|
{ memory functions }
|
|
function GlobalAlloc(mode,size:longint):longint;
|
|
external 'kernel32' name 'GlobalAlloc';
|
|
function GlobalLock(handle:longint):pointer;
|
|
external 'kernel32' name 'GlobalLock';
|
|
{$ifdef SYSTEMDEBUG}
|
|
function GlobalSize(h:longint):longint;
|
|
external 'kernel32' name 'GlobalSize';
|
|
{$endif}
|
|
|
|
var
|
|
heap : longint;external name 'HEAP';
|
|
intern_heapsize : longint;external name 'HEAPSIZE';
|
|
|
|
function getheapstart:pointer;assembler;
|
|
asm
|
|
leal HEAP,%eax
|
|
end ['EAX'];
|
|
|
|
|
|
function getheapsize:longint;assembler;
|
|
asm
|
|
movl intern_HEAPSIZE,%eax
|
|
end ['EAX'];
|
|
|
|
|
|
function Sbrk(size : longint):longint;
|
|
var
|
|
h,l : longint;
|
|
begin
|
|
h:=GlobalAlloc(258,size);
|
|
l:=longint(GlobalLock(h));
|
|
if l=0 then
|
|
l:=-1;
|
|
{$ifdef SYSTEMDEBUG}
|
|
Writeln('new heap part at $',hexstr(l,8), ' size = ',GlobalSize(h));
|
|
{$endif}
|
|
sbrk:=l;
|
|
end;
|
|
|
|
{ include standard heap management }
|
|
{$I heap.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) : longbool;
|
|
external 'kernel32' name 'SetEndOfFile';
|
|
function GetFileType(Handle:DWORD):DWord;
|
|
external 'kernel32' name 'GetFileType';
|
|
|
|
|
|
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
|
|
if Handle<=4 then
|
|
exit;
|
|
CloseHandle(h);
|
|
end;
|
|
|
|
|
|
procedure do_erase(p : pchar);
|
|
begin
|
|
AllowSlash(p);
|
|
if DeleteFile(p)=0 then
|
|
Begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure do_rename(p1,p2 : pchar);
|
|
begin
|
|
AllowSlash(p1);
|
|
AllowSlash(p2);
|
|
if MoveFile(p1,p2)=0 then
|
|
Begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
end;
|
|
|
|
|
|
function do_write(h,addr,len : longint) : longint;
|
|
var
|
|
size:longint;
|
|
begin
|
|
if writefile(h,pointer(addr),len,size,nil)=0 then
|
|
Begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
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
|
|
Begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
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;
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
do_filepos:=l;
|
|
end;
|
|
|
|
|
|
procedure do_seek(handle,pos : longint);
|
|
begin
|
|
if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
|
|
Begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
end;
|
|
|
|
|
|
function do_seekend(handle:longint):longint;
|
|
begin
|
|
do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
|
|
if do_seekend=-1 then
|
|
begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
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
|
|
begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
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 $100) the file will be append
|
|
when (flags and $1000) the file will be truncate/rewritten
|
|
when (flags and $10000) there is no check for close (needed for textfiles)
|
|
}
|
|
Const
|
|
file_Share_Read = $00000001;
|
|
file_Share_Write = $00000002;
|
|
fmShareCompat = $00000000;
|
|
fmShareExclusive = $10;
|
|
fmShareDenyWrite = $20;
|
|
fmShareDenyRead = $30;
|
|
fmShareDenyNone = $40;
|
|
Var
|
|
shflags,
|
|
oflags,cd : longint;
|
|
begin
|
|
AllowSlash(p);
|
|
{ close first if opened }
|
|
if ((flags and $10000)=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 filesharing }
|
|
shflags:=0;
|
|
if ((filemode and fmshareExclusive) = fmshareExclusive) then
|
|
{ no sharing }
|
|
else
|
|
if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
|
|
shflags := file_Share_Read
|
|
else
|
|
if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
|
|
shflags := file_Share_Write
|
|
else
|
|
if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
|
|
shflags := file_Share_Read + file_Share_Write;
|
|
{ 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 $1000)<>0 then
|
|
cd:=CREATE_ALWAYS
|
|
{ or append ? }
|
|
else
|
|
if (flags and $100)<>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,shflags,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
|
|
{ append mode }
|
|
if (flags and $100)<>0 then
|
|
begin
|
|
do_seekend(filerec(f).handle);
|
|
filerec(f).mode:=fmoutput; {fool fmappend}
|
|
end;
|
|
{ get errors }
|
|
{ handle -1 is returned sometimes !! (PM) }
|
|
if (filerec(f).handle=0) or (filerec(f).handle=-1) then
|
|
begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
end;
|
|
|
|
|
|
function do_isdevice(handle:longint):boolean;
|
|
begin
|
|
do_isdevice:=(getfiletype(handle)=2);
|
|
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
|
|
begin
|
|
errno:=GetLastError;
|
|
Errno2InoutRes;
|
|
end;
|
|
end;
|
|
|
|
function CreateDirectoryTrunc(name:pointer):word;
|
|
begin
|
|
CreateDirectoryTrunc:=CreateDirectory(name,nil);
|
|
end;
|
|
|
|
procedure mkdir(const s:string);[IOCHECK];
|
|
begin
|
|
If InOutRes <> 0 then exit;
|
|
dirfn(TDirFnType(@CreateDirectoryTrunc),s);
|
|
end;
|
|
|
|
procedure rmdir(const s:string);[IOCHECK];
|
|
begin
|
|
If InOutRes <> 0 then exit;
|
|
dirfn(TDirFnType(@RemoveDirectory),s);
|
|
end;
|
|
|
|
procedure chdir(const s:string);[IOCHECK];
|
|
begin
|
|
If InOutRes <> 0 then exit;
|
|
dirfn(TDirFnType(@SetCurrentDirectory),s);
|
|
end;
|
|
|
|
procedure getdir(drivenr:byte;var dir:shortstring);
|
|
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);
|
|
if not FileNameCaseSensitive then
|
|
dir:=upcase(dir);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
SystemUnit Initialization
|
|
*****************************************************************************}
|
|
|
|
{ Startup }
|
|
procedure GetStartupInfo(p : pointer);
|
|
external 'kernel32' name 'GetStartupInfoA';
|
|
function GetStdHandle(nStdHandle:DWORD):THANDLE;
|
|
external 'kernel32' name 'GetStdHandle';
|
|
|
|
{ command line/enviroment functions }
|
|
function GetCommandLine : pchar;
|
|
external 'kernel32' name 'GetCommandLineA';
|
|
|
|
|
|
var
|
|
ModuleName : array[0..255] of char;
|
|
|
|
function GetCommandFile:pchar;
|
|
begin
|
|
GetModuleFileName(0,@ModuleName,255);
|
|
GetCommandFile:=@ModuleName;
|
|
end;
|
|
|
|
|
|
procedure setup_arguments;
|
|
var
|
|
arglen,
|
|
count : longint;
|
|
argstart,
|
|
pc : pchar;
|
|
quote : set of char;
|
|
argsbuf : array[0..127] of pchar;
|
|
begin
|
|
{ create commandline, it starts with the executed filename which is argv[0] }
|
|
{ Win32 passes the command NOT via the args, but via getmodulefilename}
|
|
count:=0;
|
|
pc:=getcommandfile;
|
|
Arglen:=0;
|
|
repeat
|
|
Inc(Arglen);
|
|
until (pc[Arglen]=#0);
|
|
getmem(argsbuf[count],arglen+1);
|
|
move(pc^,argsbuf[count]^,arglen);
|
|
{ Now skip the first one }
|
|
pc:=GetCommandLine;
|
|
repeat
|
|
{ skip leading spaces }
|
|
while pc^ in [' ',#9,#13] do
|
|
inc(pc);
|
|
case pc^ of
|
|
#0 : break;
|
|
'"' : begin
|
|
quote:=['"'];
|
|
inc(pc);
|
|
end;
|
|
'''' : begin
|
|
quote:=[''''];
|
|
inc(pc);
|
|
end;
|
|
else
|
|
quote:=[' ',#9,#13];
|
|
end;
|
|
{ scan until the end of the argument }
|
|
argstart:=pc;
|
|
while (pc^<>#0) and not(pc^ in quote) do
|
|
inc(pc);
|
|
{ Don't copy the first one, it is already there.}
|
|
If Count<>0 then
|
|
begin
|
|
{ reserve some memory }
|
|
arglen:=pc-argstart;
|
|
getmem(argsbuf[count],arglen+1);
|
|
move(argstart^,argsbuf[count]^,arglen);
|
|
argsbuf[count][arglen]:=#0;
|
|
end;
|
|
{ skip quote }
|
|
if pc^ in quote then
|
|
inc(pc);
|
|
inc(count);
|
|
until false;
|
|
{ create argc }
|
|
argc:=count;
|
|
{ create an nil entry }
|
|
argsbuf[count]:=nil;
|
|
inc(count);
|
|
{ create the argv }
|
|
getmem(argv,count shl 2);
|
|
move(argsbuf,argv^,count shl 2);
|
|
{ Setup cmdline variable }
|
|
cmdline:=GetCommandLine;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
System Dependent Exit code
|
|
*****************************************************************************}
|
|
Procedure system_exit;
|
|
begin
|
|
if not IsConsole then
|
|
begin
|
|
Close(stderr);
|
|
Close(stdout);
|
|
{ what about Input and Output ?? PM }
|
|
end;
|
|
ExitProcess(ExitCode);
|
|
end;
|
|
|
|
{$ifdef dummy}
|
|
Function SetUpStack : longint;
|
|
{ This routine does the following : }
|
|
{ returns the value of the initial SP - __stklen }
|
|
begin
|
|
asm
|
|
pushl %ebx
|
|
pushl %eax
|
|
movl __stklen,%ebx
|
|
movl %esp,%eax
|
|
subl %ebx,%eax
|
|
movl %eax,__RESULT
|
|
popl %eax
|
|
popl %ebx
|
|
end;
|
|
end;
|
|
{$endif}
|
|
|
|
procedure install_exception_handlers;forward;
|
|
procedure PascalMain;external name 'PASCALMAIN';
|
|
procedure fpc_do_exit;external name 'FPC_DO_EXIT';
|
|
|
|
|
|
var
|
|
{ value of the stack segment
|
|
to check if the call stack can be written on exceptions }
|
|
_SS : longint;
|
|
|
|
procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
|
|
begin
|
|
IsLibrary:=false;
|
|
{ install the handlers for exe only ?
|
|
or should we install them for DLL also ? (PM) }
|
|
install_exception_handlers;
|
|
{ This strange construction is needed to solve the _SS problem
|
|
with a smartlinked syswin32 (PFV) }
|
|
asm
|
|
pushl %ebp
|
|
xorl %ebp,%ebp
|
|
movl %esp,%eax
|
|
movl %eax,Win32StackTop
|
|
movw %ss,%bp
|
|
movl %ebp,_SS
|
|
xorl %ebp,%ebp
|
|
call PASCALMAIN
|
|
popl %ebp
|
|
end;
|
|
{ if we pass here there was no error ! }
|
|
system_exit;
|
|
end;
|
|
|
|
Const
|
|
{ DllEntryPoint }
|
|
DLL_PROCESS_ATTACH = 1;
|
|
DLL_THREAD_ATTACH = 2;
|
|
DLL_PROCESS_DETACH = 0;
|
|
DLL_THREAD_DETACH = 3;
|
|
|
|
function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
|
|
var
|
|
res : longbool;
|
|
begin
|
|
IsLibrary:=true;
|
|
case DLLreason of
|
|
DLL_PROCESS_ATTACH :
|
|
begin
|
|
asm
|
|
movl %esp,%eax
|
|
movl %eax,Win32StackTop
|
|
xorl %edi,%edi
|
|
movw %ss,%di
|
|
movl %edi,_SS
|
|
end;
|
|
if assigned(Dll_Process_Attach_Hook) then
|
|
begin
|
|
res:=Dll_Process_Attach_Hook(DllParam);
|
|
if not res then
|
|
begin
|
|
Dll_entry:=false;
|
|
exit;
|
|
end;
|
|
end;
|
|
PASCALMAIN;
|
|
Dll_entry:=true;
|
|
end;
|
|
DLL_THREAD_ATTACH :
|
|
begin
|
|
inc(Thread_count);
|
|
if assigned(Dll_Thread_Attach_Hook) then
|
|
Dll_Thread_Attach_Hook(DllParam);
|
|
Dll_entry:=true; { return value is ignored }
|
|
end;
|
|
DLL_THREAD_DETACH :
|
|
begin
|
|
dec(Thread_count);
|
|
if assigned(Dll_Thread_Detach_Hook) then
|
|
Dll_Thread_Detach_Hook(DllParam);
|
|
Dll_entry:=true; { return value is ignored }
|
|
end;
|
|
DLL_PROCESS_DETACH :
|
|
begin
|
|
inc(Thread_count);
|
|
Dll_entry:=true; { return value is ignored }
|
|
FPC_DO_EXIT;
|
|
if assigned(Dll_Process_Detach_Hook) then
|
|
Dll_Process_Detach_Hook(DllParam);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{$ifdef Set_i386_Exception_handler}
|
|
|
|
const
|
|
EXCEPTION_MAXIMUM_PARAMETERS = 15;
|
|
EXCEPTION_ACCESS_VIOLATION = $c0000005;
|
|
EXCEPTION_BREAKPOINT = $80000003;
|
|
EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
|
|
EXCEPTION_SINGLE_STEP = $80000004;
|
|
EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
|
|
EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
|
|
EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
|
|
EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
|
|
EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
|
|
EXCEPTION_FLT_OVERFLOW = $c0000091;
|
|
EXCEPTION_FLT_STACK_CHECK = $c0000092;
|
|
EXCEPTION_FLT_UNDERFLOW = $c0000093;
|
|
EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
|
|
EXCEPTION_INT_OVERFLOW = $c0000095;
|
|
EXCEPTION_INVALID_HANDLE = $c0000008;
|
|
EXCEPTION_PRIV_INSTRUCTION = $c0000096;
|
|
EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
|
|
EXCEPTION_NONCONTINUABLE = $1;
|
|
EXCEPTION_STACK_OVERFLOW = $c00000fd;
|
|
EXCEPTION_INVALID_DISPOSITION = $c0000026;
|
|
ExceptionContinueExecution = 0;
|
|
ExceptionContinueSearch = 1;
|
|
type
|
|
|
|
FLOATING_SAVE_AREA = record
|
|
ControlWord : DWORD;
|
|
StatusWord : DWORD;
|
|
TagWord : DWORD;
|
|
ErrorOffset : DWORD;
|
|
ErrorSelector : DWORD;
|
|
DataOffset : DWORD;
|
|
DataSelector : DWORD;
|
|
RegisterArea : array[0..79] of BYTE;
|
|
Cr0NpxState : DWORD;
|
|
end;
|
|
_FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
|
|
TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
|
|
PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
|
|
|
|
CONTEXT = record
|
|
ContextFlags : DWORD;
|
|
Dr0 : DWORD;
|
|
Dr1 : DWORD;
|
|
Dr2 : DWORD;
|
|
Dr3 : DWORD;
|
|
Dr6 : DWORD;
|
|
Dr7 : DWORD;
|
|
FloatSave : FLOATING_SAVE_AREA;
|
|
SegGs : DWORD;
|
|
SegFs : DWORD;
|
|
SegEs : DWORD;
|
|
SegDs : DWORD;
|
|
Edi : DWORD;
|
|
Esi : DWORD;
|
|
Ebx : DWORD;
|
|
Edx : DWORD;
|
|
Ecx : DWORD;
|
|
Eax : DWORD;
|
|
Ebp : DWORD;
|
|
Eip : DWORD;
|
|
SegCs : DWORD;
|
|
EFlags : DWORD;
|
|
Esp : DWORD;
|
|
SegSs : DWORD;
|
|
end;
|
|
LPCONTEXT = ^CONTEXT;
|
|
_CONTEXT = CONTEXT;
|
|
TCONTEXT = CONTEXT;
|
|
PCONTEXT = ^CONTEXT;
|
|
|
|
|
|
type pexception_record = ^exception_record;
|
|
EXCEPTION_RECORD = record
|
|
ExceptionCode : longint;
|
|
ExceptionFlags : longint;
|
|
ExceptionRecord : pexception_record;
|
|
ExceptionAddress : pointer;
|
|
NumberParameters : longint;
|
|
ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
|
|
end;
|
|
|
|
PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
|
|
EXCEPTION_POINTERS = record
|
|
ExceptionRecord : PEXCEPTION_RECORD ;
|
|
ContextRecord : PCONTEXT ;
|
|
end;
|
|
|
|
{ type of functions that should be used for exception handling }
|
|
LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;
|
|
|
|
function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
|
|
: LPTOP_LEVEL_EXCEPTION_FILTER;
|
|
external 'kernel32' name 'SetUnhandledExceptionFilter';
|
|
|
|
function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
|
|
var frame : longint;
|
|
begin
|
|
{ default : unhandled !}
|
|
if excep^.ContextRecord^.SegSs=_SS then
|
|
frame:=excep^.ContextRecord^.Ebp
|
|
else
|
|
frame:=0;
|
|
syswin32_i386_exception_handler:=ExceptionContinueSearch;
|
|
case excep^.ExceptionRecord^.ExceptionCode of
|
|
EXCEPTION_ACCESS_VIOLATION :
|
|
HandleErrorFrame(216,frame);
|
|
{ EXCEPTION_BREAKPOINT = $80000003;
|
|
EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
|
|
EXCEPTION_SINGLE_STEP = $80000004; }
|
|
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
|
|
HandleErrorFrame(201,frame);
|
|
{ EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
|
|
EXCEPTION_FLT_DIVIDE_BY_ZERO :
|
|
HandleErrorFrame(200,frame);
|
|
{EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
|
|
EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
|
|
EXCEPTION_FLT_OVERFLOW :
|
|
HandleErrorFrame(205,frame);
|
|
EXCEPTION_FLT_STACK_CHECK :
|
|
HandleErrorFrame(207,frame);
|
|
{ EXCEPTION_FLT_UNDERFLOW :
|
|
HandleErrorFrame(206,frame); should be accepted as zero !! }
|
|
EXCEPTION_INT_DIVIDE_BY_ZERO :
|
|
HandleErrorFrame(200,frame);
|
|
EXCEPTION_INT_OVERFLOW :
|
|
HandleErrorFrame(215,frame);
|
|
{EXCEPTION_INVALID_HANDLE = $c0000008;
|
|
EXCEPTION_PRIV_INSTRUCTION = $c0000096;
|
|
EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
|
|
EXCEPTION_NONCONTINUABLE = $1;}
|
|
EXCEPTION_STACK_OVERFLOW :
|
|
HandleErrorFrame(202,frame);
|
|
{EXCEPTION_INVALID_DISPOSITION = $c0000026;}
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure install_exception_handlers;
|
|
begin
|
|
SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
|
|
end;
|
|
|
|
|
|
{$else not i386 (Processor specific !!)}
|
|
procedure install_exception_handlers;
|
|
begin
|
|
end;
|
|
|
|
|
|
{$endif Set_i386_Exception_handler}
|
|
|
|
|
|
{****************************************************************************
|
|
Error Message writing using messageboxes
|
|
****************************************************************************}
|
|
|
|
function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
|
|
external 'user32' name 'MessageBoxA';
|
|
|
|
const
|
|
ErrorBufferLength = 1024;
|
|
var
|
|
ErrorBuf : array[0..ErrorBufferLength] of char;
|
|
ErrorLen : longint;
|
|
|
|
Function ErrorWrite(Var F: TextRec): Integer;
|
|
{
|
|
An error message should always end with #13#10#13#10
|
|
}
|
|
var
|
|
p : pchar;
|
|
i : longint;
|
|
Begin
|
|
if F.BufPos>0 then
|
|
begin
|
|
if F.BufPos+ErrorLen>ErrorBufferLength then
|
|
i:=ErrorBufferLength-ErrorLen
|
|
else
|
|
i:=F.BufPos;
|
|
Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
|
|
inc(ErrorLen,i);
|
|
ErrorBuf[ErrorLen]:=#0;
|
|
end;
|
|
if ErrorLen>3 then
|
|
begin
|
|
p:=@ErrorBuf[ErrorLen];
|
|
for i:=1 to 4 do
|
|
begin
|
|
dec(p);
|
|
if not(p^ in [#10,#13]) then
|
|
break;
|
|
end;
|
|
end;
|
|
if ErrorLen=ErrorBufferLength then
|
|
i:=4;
|
|
if (i=4) then
|
|
begin
|
|
MessageBox(0,@ErrorBuf,pchar('Error'),0);
|
|
ErrorLen:=0;
|
|
end;
|
|
F.BufPos:=0;
|
|
ErrorWrite:=0;
|
|
End;
|
|
|
|
|
|
Function ErrorClose(Var F: TextRec): Integer;
|
|
begin
|
|
if ErrorLen>0 then
|
|
begin
|
|
MessageBox(0,@ErrorBuf,pchar('Error'),0);
|
|
ErrorLen:=0;
|
|
end;
|
|
ErrorLen:=0;
|
|
ErrorClose:=0;
|
|
end;
|
|
|
|
|
|
Function ErrorOpen(Var F: TextRec): Integer;
|
|
Begin
|
|
TextRec(F).InOutFunc:=@ErrorWrite;
|
|
TextRec(F).FlushFunc:=@ErrorWrite;
|
|
TextRec(F).CloseFunc:=@ErrorClose;
|
|
ErrorOpen:=0;
|
|
End;
|
|
|
|
|
|
procedure AssignError(Var T: Text);
|
|
begin
|
|
Assign(T,'');
|
|
TextRec(T).OpenFunc:=@ErrorOpen;
|
|
Rewrite(T);
|
|
end;
|
|
|
|
|
|
|
|
const
|
|
Exe_entry_code : pointer = @Exe_entry;
|
|
Dll_entry_code : pointer = @Dll_entry;
|
|
|
|
begin
|
|
{ get some helpful informations }
|
|
GetStartupInfo(@startupinfo);
|
|
{ some misc Win32 stuff }
|
|
hprevinst:=0;
|
|
if not IsLibrary then
|
|
HInstance:=getmodulehandle(GetCommandFile);
|
|
MainInstance:=HInstance;
|
|
{ No idea how to know this issue !! }
|
|
IsMultithreaded:=false;
|
|
cmdshow:=startupinfo.wshowwindow;
|
|
{ to test stack depth }
|
|
loweststack:=maxlongint;
|
|
{ real test stack depth }
|
|
{ stacklimit := setupstack; }
|
|
{ Setup heap }
|
|
InitHeap;
|
|
InitExceptions;
|
|
{ Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
|
|
displayed in and messagebox }
|
|
StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
|
|
StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
|
|
StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
|
|
if not IsConsole then
|
|
begin
|
|
AssignError(stderr);
|
|
AssignError(stdout);
|
|
Assign(Output,'');
|
|
Assign(Input,'');
|
|
end
|
|
else
|
|
begin
|
|
OpenStdIO(Input,fmInput,StdInputHandle);
|
|
OpenStdIO(Output,fmOutput,StdOutputHandle);
|
|
OpenStdIO(StdOut,fmOutput,StdOutputHandle);
|
|
OpenStdIO(StdErr,fmOutput,StdErrorHandle);
|
|
end;
|
|
{ Arguments }
|
|
setup_arguments;
|
|
{ Reset IO Error }
|
|
InOutRes:=0;
|
|
{ Reset internal error variable }
|
|
errno:=0;
|
|
end.
|
|
|
|
{
|
|
$Log$
|
|
Revision 1.55 2000-01-16 22:25:38 peter
|
|
* check handle for file closing
|
|
|
|
Revision 1.54 2000/01/07 16:41:52 daniel
|
|
* copyright 2000
|
|
|
|
Revision 1.53 2000/01/07 16:32:34 daniel
|
|
* copyright 2000 added
|
|
|
|
Revision 1.52 2000/01/06 23:40:36 peter
|
|
* fixed exitprocess call, it's now in system_exit and uses exitcode
|
|
|
|
Revision 1.51 1999/12/01 22:57:31 peter
|
|
* cmdline support
|
|
|
|
Revision 1.50 1999/11/20 00:16:44 pierre
|
|
+ DLL Hooks for the four callings added
|
|
|
|
Revision 1.49 1999/11/18 22:19:57 pierre
|
|
* bug fix for web bug703 and 704
|
|
|
|
Revision 1.48 1999/11/09 22:34:00 pierre
|
|
* Check ErrorBuf at exit
|
|
+ Win32StackTop
|
|
|
|
Revision 1.47 1999/10/26 12:25:51 peter
|
|
* report stderr,stdout to message box for errors
|
|
* close input,output when GUI app is made
|
|
|
|
Revision 1.46 1999/10/22 14:47:19 peter
|
|
* allocate an extra byte for argv[0]
|
|
|
|
Revision 1.45 1999/10/03 19:39:05 peter
|
|
* fixed argv[0] length
|
|
|
|
Revision 1.44 1999/09/10 15:40:35 peter
|
|
* fixed do_open flags to be > $100, becuase filemode can be upto 255
|
|
|
|
Revision 1.43 1999/07/07 10:04:43 michael
|
|
+ Small edit in paramstr
|
|
|
|
Revision 1.42 1999/07/07 09:43:16 michael
|
|
Better construction of commandline argv
|
|
|
|
Revision 1.41 1999/07/05 20:04:30 peter
|
|
* removed temp defines
|
|
|
|
Revision 1.40 1999/06/11 16:26:40 michael
|
|
+ Fixed paramstr(0)
|
|
|
|
Revision 1.39 1999/05/17 21:52:47 florian
|
|
* most of the Object Pascal stuff moved to the system unit
|
|
|
|
Revision 1.38 1999/04/28 11:42:53 peter
|
|
+ FileNameCaseSensetive boolean
|
|
|
|
Revision 1.37 1999/04/08 12:23:11 peter
|
|
* removed os.inc
|
|
|
|
Revision 1.36 1999/03/24 23:25:59 peter
|
|
* fixed file sharing
|
|
|
|
Revision 1.35 1999/03/12 00:07:48 pierre
|
|
+ code for coff writer
|
|
|
|
Revision 1.34 1999/03/10 22:15:31 florian
|
|
+ system.cmdline variable for go32v2 and win32 added
|
|
|
|
Revision 1.33 1999/01/18 10:05:57 pierre
|
|
+ system_exit procedure added
|
|
|
|
Revision 1.32 1998/12/28 23:30:11 peter
|
|
* fixes for smartlinking
|
|
|
|
Revision 1.31 1998/12/28 15:50:51 peter
|
|
+ stdout, which is needed when you write something in the system unit
|
|
to the screen. Like the runtime error
|
|
|
|
Revision 1.30 1998/12/21 14:28:23 pierre
|
|
* HandleError -> HandleErrorFrame to avoid problem in
|
|
assembler code in i386.inc
|
|
(call to overloaded function in assembler block !)
|
|
|
|
Revision 1.29 1998/12/15 22:43:14 peter
|
|
* removed temp symbols
|
|
|
|
Revision 1.28 1998/12/09 17:57:33 pierre
|
|
+ exception handling by default
|
|
|
|
Revision 1.27 1998/12/01 14:00:08 pierre
|
|
+ added conversion from exceptions into run time error
|
|
(only if syswin32 compiled with -ddebug for now !)
|
|
* added HandleErrorFrame(errno,frame)
|
|
where you specify the frame
|
|
needed for win32 exception handling
|
|
|
|
Revision 1.26 1998/11/30 13:13:41 pierre
|
|
* needs asw to link correctly wprt0 or wdllprt0 file
|
|
|
|
Revision 1.25 1998/11/30 09:16:58 pierre
|
|
+ added the changes from Pavel Ozerski after several modifications
|
|
to be able to create DLLs
|
|
|
|
Revision 1.24 1998/11/16 15:48:54 peter
|
|
* fixed longbool returns for api calls
|
|
|
|
Revision 1.23 1998/11/16 14:14:58 pierre
|
|
* changed getdir(byte,string) to getdir(byte,shortstring)
|
|
|
|
Revision 1.22 1998/10/27 15:07:16 florian
|
|
+ Is* flags added
|
|
+ IsLibrary works also
|
|
|
|
Revision 1.21 1998/10/15 16:26:19 peter
|
|
+ fpuinit
|
|
+ end of backtrace indicator
|
|
|
|
Revision 1.20 1998/09/14 10:48:33 peter
|
|
* FPC_ names
|
|
* Heap manager is now system independent
|
|
|
|
Revision 1.19 1998/09/02 09:03:46 pierre
|
|
* do_open sometimes returns -1 as handle on fail
|
|
was not checked correctly
|
|
|
|
Revision 1.16 1998/08/24 14:45:22 pierre
|
|
* sbrk was wrong
|
|
heap growing now works for win32
|
|
|
|
Revision 1.15 1998/08/21 10:10:16 peter
|
|
* winheap turned off by default
|
|
|
|
Revision 1.14 1998/07/30 13:27:19 michael
|
|
+ Added support for errorproc. Changed runerror to HandleError
|
|
|
|
Revision 1.13 1998/07/13 21:19:15 florian
|
|
* some problems with ansi string support fixed
|
|
|
|
Revision 1.12 1998/07/07 12:37:28 carl
|
|
* correct mapping of error codes for TP compatibility
|
|
+ implemented stack checking in ifdef dummy
|
|
|
|
Revision 1.11 1998/07/02 12:33:18 carl
|
|
* IOCheck/InOutRes check for mkdir,rmdir and chdir like in TP
|
|
|
|
Revision 1.10 1998/07/01 15:30:02 peter
|
|
* better readln/writeln
|
|
|
|
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.)
|
|
}
|