home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sp15demo.zip
/
libsrc.zip
/
LIBSRC
/
SYSTEM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-02-23
|
466KB
|
18,767 lines
UNIT System;
{$S-,I-,Q-,R-}
{$IFDEF OS2}
{***************************************************************************
* *
* SPEED PASCAL for OS/2 V 2.0 *
* (C) 1992..95 SpeedSoft Software *
* *
* Unit SYSTEM : Low level basic functions *
* *
* Note: Compile with DWORD align !! *
* *
***************************************************************************}
INTERFACE
//General functions
FUNCTION Swap(i:INTEGER):INTEGER;
//General constants
CONST
MINSHORTINT = -128;
MAXSHORTINT = 127;
MAXINT = 32767;
MININT =-32768;
MAXLONGINT = 2147483647;
{$IFDEF DOSOS2} //BP doesn't accept this
MINLONGINT =-2147483647;
{$ELSE}
MINLONGINT =-2147483648;
{$ENDIF}
MINBYTE = 0;
MAXBYTE = 255;
MINWORD = 0;
MAXWORD = 65535;
MAXLONGWORD = $ffffffff;
MINLONGWORD = 0;
NULLHANDLE = 0;
SCUPointer:POINTER=NIL;
PROCEDURE Beep(Freq,duration:LONGWORD);
//General types
TYPE
PChar =^CSTRING;
PString =^STRING;
PDATETIME=^DATETIME;
DATETIME=RECORD
CASE INTEGER OF
1: ( hour:BYTE;
min:BYTE;
sec:BYTE;
hundredths:BYTE;
day:BYTE;
month:BYTE;
year:WORD;
timezone:INTEGER;
weekday:BYTE;
);
2: ( hours:BYTE;
minutes:BYTE;
seconds:BYTE;
);
END;
{Generic procedure pointer}
TProcedure = procedure;
// Memory management functions
TYPE
HeapFunc=FUNCTION(size:LONGWORD):Integer;
VAR
HeapOrg:Pointer; {Bottom of heap}
HeapEnd:Pointer; {End of heap}
HeapPtr:Pointer; {Actual heap position}
FreeList:Pointer; {List of free blocks}
HeapTop:POINTER; {Highest heap adress that has been commited}
HeapSize:LONGWORD; {Size of heap}
HeapError:HeapFunc; {Heap Error Function}
HeapResult:LONGWORD; {Result from last heap function}
{MemAvailBytes:LONGWORD;}
CONST
FillMemoryWithZero:BOOLEAN=FALSE;
FUNCTION MaxAvail:LongWord;
FUNCTION MemAvail:LongWord;
PROCEDURE GetMem(VAR p:Pointer;size:LongWord);
PROCEDURE GetSharedMem(VAR pp:Pointer;size:LongWord);
PROCEDURE Mark(VAR p:POINTER);
PROCEDURE Release(VAR p:POINTER);
PROCEDURE FreeMem(p:pointer;size:LongWord);
PROCEDURE FreeSharedMem(p:pointer;size:LongWord);
PROCEDURE GetAPIMem(VAR p:POINTER;size:LONGWORD);
PROCEDURE FreeAPIMem(p:POINTER;size:LONGWORD);
PROCEDURE NewSystemHeap;
FUNCTION CreateSystemHeap(Size:LONGWORD):BOOLEAN;
PROCEDURE DestroySystemHeap;
PROCEDURE DestroyHeap(Heap:POINTER);
{Use this rotines to synchronize heap access when a thread is killed and
you don't know the state of the thread. This prevents heap corruption}
PROCEDURE RequestHeapMutex;
PROCEDURE ReleaseHeapMutex;
// Error functions
VAR
ExitCode:LONGWORD;
ErrorAdr:POINTER;
ExitProc:POINTER;
PROCEDURE RunError(Code:LONGWORD);
PROCEDURE Halt(Code:LONGWORD);
// Random numbers support
VAR
RandSeed:LONGWORD;
PROCEDURE Randomize;
FUNCTION Random(value:word):word;
//Direct memory access
PROCEDURE MOVE(CONST source;VAR dest;size:LongWord);
PROCEDURE FILLCHAR(VAR dest;size:LongWord;value:byte);
//LongJmp support
TYPE Jmp_Buf=ARRAY[0..8] OF LONGWORD;
FUNCTION SetJmp(VAR JmpBuf:Jmp_Buf):LONGWORD;
PROCEDURE LongJmp(VAR JmpBuf:Jmp_Buf;RetVal:LONGWORD);
//String functions
PROCEDURE UpcaseStr(VAR s:STRING);
FUNCTION POS(CONST item,source:STRING):BYTE;
FUNCTION Copy(CONST Source:STRING; Index,Count:INTEGER):STRING;
PROCEDURE SubStr(VAR source:STRING;start,ende:Byte);
PROCEDURE Insert(CONST Source:STRING; VAR S:STRING; Index:INTEGER);
PROCEDURE Delete(VAR S:STRING; Index,Count:INTEGER);
FUNCTION ToHex(l:LONGWORD):STRING;
//Floating point support
CONST
rad=1;
deg=2;
gra=3;
VAR
IsNotRad:BOOLEAN;
ToRad,FromRad:EXTENDED;
FPUResult:WORD;
PROCEDURE SetTrigMode(mode:BYTE);
CONST
PI=3.141592653589793240;
//CLASS support
{TYPE
(* Class structures layout, particulary also valid for objects *)
PClassInfoLayout=^TClassInfoLayout;
TClassInfoLayout=RECORD
ClassSize:LONGWORD;
ParentObjectAddr:POINTER;
FieldAdress:POINTER;
(*Class Info following here*)
END;
PDmtLayout=^TDmtLayout;
TDmtLayout=RECORD
NumDmts:LONGWORD; (*Number of entries*)
(*entries follow here
each entry is 8 byte long
the first DWord contains the message id,
the second DWord contains the VMT index*)
END;
PVmtLayOut=^TVmtLayOut;
TVmtLayOut=RECORD
Dmt:PDmtLayout; (*Pointer to DMT*)
ClassInfo:PClassInfoLayout;
ClassSize:LONGWORD;
VmtSize:LONGWORD; (*Number of entries*)
(*entries follow here
each entry is 4 byte long and contains
the address for that VMT index*)
END;
TClassLayout=RECORD
Vmt:PVmtLayout;
(*Object variables follow here*)
END;}
TYPE
TObject = CLASS;
TClass = CLASS OF TObject;
TObject = CLASS
CONSTRUCTOR Create;
DESTRUCTOR Destroy; VIRTUAL;
PROCEDURE Free;VIRTUAL;
CLASS FUNCTION NewInstance: TObject; VIRTUAL;
PROCEDURE FreeInstance; virtual;
CLASS FUNCTION InitInstance(Instance: Pointer): TObject;
CLASS FUNCTION ClassType: TClass;
CLASS FUNCTION ClassName: STRING;
CLASS FUNCTION ClassUnit: STRING;
CLASS FUNCTION ClassParent: TClass;
CLASS FUNCTION GetClassInfo: POINTER; //conflicts with PMWIN CLASSINFO
CLASS FUNCTION InstanceSize: LONGWORD;
CLASS FUNCTION InheritsFrom(AClass: TClass): BOOLEAN;
PROCEDURE DefaultHandler(VAR Message); VIRTUAL;
PROCEDURE DefaultFrameHandler(VAR Message); VIRTUAL;
PROCEDURE Dispatch(VAR Message);
PROCEDURE DispatchCommand(VAR Message;Command:LONGWORD);
PROCEDURE FrameDispatch(VAR Message);
CLASS FUNCTION MethodAddress(CONST Name: STRING): POINTER;
CLASS FUNCTION MethodName(Address: POINTER): STRING;
FUNCTION FieldAddress(Name: STRING): POINTER;
END;
//TextScreen IO support
VAR
Input,Output:TEXT;
CONST
{ CRT modes }
BW40 = 0; { 40x25 B/W on Color Adapter }
CO40 = 1; { 40x25 Color on Color Adapter }
BW80 = 2; { 80x25 B/W on Color Adapter }
CO80 = 3; { 80x25 Color on Color Adapter }
Mono = 7; { 80x25 on Monochrome Adapter }
Font8x8 = 256; { Add-in for 8x8 font }
VAR
WindMin: WORD; { Window upper left coordinates }
WindMax: WORD; { Window lower right coordinates }
LastMode: Word; { Current text mode }
TextAttr: BYTE; { Current text attribute }
ApplicationType:BYTE;
CONST
DirectVideo: BOOLEAN = False; { Enable direct video addressing }
CheckSnow: BOOLEAN = True; { Enable snow filtering }
TYPE TScreenInOutClass=CLASS
PROCEDURE WriteStr(CONST s:STRING);VIRTUAL;
PROCEDURE WriteCStr(CONST s:CSTRING);VIRTUAL;
PROCEDURE WriteLF;VIRTUAL;
PROCEDURE ReadLF(VAR s:STRING);VIRTUAL;
PROCEDURE GotoXY(x,y:BYTE);VIRTUAL;
END;
TPMScreenInOutClass=CLASS
PROCEDURE WriteStr(CONST s:STRING);VIRTUAL;
PROCEDURE WriteCStr(CONST s:CSTRING);VIRTUAL;
PROCEDURE WriteLF;VIRTUAL;
PROCEDURE ReadLF(VAR s:STRING);VIRTUAL;
PROCEDURE GotoXY(x,y:BYTE);VIRTUAL;
PROCEDURE Error;
END;
IMPORTS
FUNCTION WinInitializeAPI(flOptions:LONGWORD):LONGWORD;
APIENTRY; PMWIN index 763;
FUNCTION WinTerminateAPI(ahab:LONGWORD):BOOLEAN;
APIENTRY; PMWIN index 888;
FUNCTION WinCreateMsgQueueAPI(ahab:LONGWORD;cmsg:LONGINT):LONGWORD;
APIENTRY; PMWIN index 716;
FUNCTION WinDestroyMsgQueueAPI(ahmq:LONGWORD):BOOLEAN;
APIENTRY; PMWIN index 726;
END;
VAR ScreenInOut:TScreenInOutClass;
VAR
VioScrollDnProc:FUNCTION (usTopRow,usLeftCol,usBotRow,usRightCol,
cbLines:LONGWORD;VAR pCell;ahvio:LONGWORD):WORD;CDECL;
VioScrollUpProc:FUNCTION (usTopRow,usLeftCol,usBotRow,usRightCol,
cbLines:LONGWORD;VAR pCell;ahvio:LONGWORD):WORD;CDECL;
VioGetModeProc:FUNCTION (VAR apvioModeInfo;ahvio:LONGWORD):WORD;CDECL;
VioSetModeProc:FUNCTION (VAR apvioModeInfo;ahvio:LONGWORD):WORD;CDECL;
VioWhereXProc:FUNCTION:BYTE;CDECL;
VioWhereYProc:FUNCTION:BYTE;CDECL;
VioSetCurPosProc:FUNCTION (usRow,usColumn:LONGWORD;ahvio:LONGWORD):WORD;CDECL;
VioReadCellStrProc:FUNCTION (VAR pchCellStr;VAR pcb:WORD;usRow,
usColumn:LONGWORD;ahvio:LONGWORD):WORD;CDECL;
VioGetConfigProc:FUNCTION (usConfigId:LONGWORD;VAR pvioin;
ahvio:LONGWORD):WORD;CDECL;
KbdStringInProc: FUNCTION (VAR apch;VAR pchIn;fsWait:LONGWORD;
ahkbd:LONGWORD):WORD;CDECL;
ReadKeyProc:FUNCTION:CHAR;CDECL;
KeyPressedProc:FUNCTION:BOOLEAN;CDECL;
//File I/O support
TYPE
{Extended attributes information returned by GetEAInfo}
PFEADATA=^TFEADATA;
TFEADATA=ARRAY[0..65535] OF BYTE;
PHOLDFEA=^THOLDFEA;
THOLDFEA=RECORD
{oNextEntryOffset:LONGWORD; // new field}
fEA:BYTE; // Flag byte
cbName:BYTE;
cbValue:WORD;
szName:CSTRING;
aValue:PFEADATA;
Deleted:BOOLEAN; //true to delete EA on write
next:PHOLDFEA;
END;
P_FileBuffer=^T_FileBuffer;
T_FileBuffer=ARRAY[0..MaxLongInt-1] OF BYTE; {handled dynamically}
FileRec = RECORD
Handle : LongWord; {FileHandle }
RecSize : LongWord; {Record size }
Name : STRING; {(Long) file name }
EAS : PHOLDFEA; {extended attributes }
Mode : LONGWORD; {Current file mode }
Reserved : POINTER; {for private extensions}
Block : LONGWORD; {current block in file }
LBlock : LONGWORD; {Last block in file }
Offset : LONGWORD; {Current offset in Block}
LOffset : LONGWORD; {Last Offset in LBlock }
Changed : LONGBOOL; {TRUE if Block has changed}
Buffer : P_FileBuffer; {I/O Buffer }
MaxCacheMem : LONGWORD; {Size of I/O Buffer }
Flags : LONGWORD; {Assign flags $6666 }
Reserved1 : WORD; {dont use }
BufferBytes : WORD; {dont use }
{312 byte til here}
END;
VAR
IOResult:LONGWORD;
CONST
//Sharing options - use this way: FileMode:=(FileMode AND 15) OR Value;
fmDenyRead = $30; {deny read access by other processes }
fmDenyWrite = $20; {deny write access by other processes }
fmDenyNone = $40; {deny neither read nor write }
fmDenyBoth = $10; {deny both read and write access (standard) }
{FileMode values}
fmClosed = 0;
fmInput = 0 OR fmDenyWrite; {Read only }
fmOutput = 1 OR fmDenyRead; {Write only }
fmInOut = 2 OR fmDenyNone; {allow both read and write access (standard) }
CONST
{Seek Origin Constants}
Seek_Begin = 0; //Seek from beginning of file
Seek_Current = 1; //Seek from current position of file
Seek_End = 2; //Seek from end of file
VAR
FileMode:LONGWORD; {file mode for both reset and rewrite}
SeekMode:LONGWORD; {seek mode for seek }
PROCEDURE Assign(VAR f:FILE;CONST s:STRING);
PROCEDURE Rewrite(VAR f:FILE;recsize:LONGWORD);
PROCEDURE Reset(VAR f:FILE;recsize:LONGWORD);
PROCEDURE Close(VAR f:FILE);
PROCEDURE BlockRead(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
PROCEDURE BlockWrite(VAR f:file;VAR Buf;Count:LongWord;VAR result:LONGWORD);
PROCEDURE Rename(VAR f:file;NewName:String);
PROCEDURE Truncate(VAR f:FILE);
PROCEDURE Append(VAR f:Text);
PROCEDURE Seek(VAR f:FILE;n:LONGINT);
FUNCTION SeekEof(VAR F :Text):Boolean;
FUNCTION SeekEoln(VAR F:Text):Boolean;
FUNCTION FilePos(VAR f:FILE):LONGWORD;
FUNCTION FileSize(VAR f:FILE):LONGWORD;
FUNCTION Eof(VAR f:FILE):BOOLEAN;
FUNCTION Eoln(VAR F:Text):Boolean;
PROCEDURE Erase(VAR f:FILE);
PROCEDURE SetFileBuf(VAR f:FILE;VAR Buf;BufSize:LONGWORD);
PROCEDURE SetTextBuf(VAR f:TEXT;VAR Buf;BufSize:LONGWORD);
//Funtions for manipulating EAS
//EAS will be written with a DosClose call, but the file should then
//not be occupied by another process or thread, Close must have
//exclusive access to the file or EA setting will fail ! When using
//the standard filemode with fmdenyBoth this is save
FUNCTION GetEAData(VAR f:FILE):PHOLDFEA;
PROCEDURE SetEAData(VAR f:FILE;EAData:PHOLDFEA);
PROCEDURE DeleteEAData(VAR f:FILE);
//Functions for manipulating directories
PROCEDURE ChDir(CONST path:STRING);
PROCEDURE GetDir(drive:byte;VAR path:STRING);
PROCEDURE RmDir(CONST dir:STRING);
PROCEDURE MkDir(CONST dir:STRING);
FUNCTION PARAMSTR(item:Byte):STRING;
FUNCTION PARAMCOUNT:Byte;
//Exception Management
TYPE
{
* ExceptionReportRecord
*
* This structure contains machine independant information about an
* exception/unwind. No system exception will ever have more than
* EXCEPTION_MAXIMUM_PARAMETERS parameters. User exceptions are not
* bound to this limit.
}
CONST
EXCEPTION_MAXIMUM_PARAMETERS =4; { Enough for all system exceptions. }
TYPE
PEXCEPTIONREPORTRECORD=^EXCEPTIONREPORTRECORD;
EXCEPTIONREPORTRECORD=RECORD
ExceptionNum:LONGWORD; { exception number }
fHandlerFlags:LONGWORD;
NestedExceptionReportRecord:PEXCEPTIONREPORTRECORD;
ExceptionAddress:POINTER;
cParameters:LONGWORD; { Size of Exception Specific Info }
ExceptionInfo:ARRAY[0..EXCEPTION_MAXIMUM_PARAMETERS] OF LONGWORD;
END;
{
* ExceptionRegistrationRecord
*
* These are linked together to form a chain of exception handlers that
* will be dispatched to upon receipt of an exception.
}
_ERR=POINTER; {Exception handler entry address}
Exception=Class; {forward definition}
PEXCEPTIONREGISTRATIONRECORD=^EXCEPTIONREGISTRATIONRECORD;
EXCEPTIONREGISTRATIONRECORD=RECORD
prev_structure:PEXCEPTIONREGISTRATIONRECORD;
ExceptionHandler:_ERR;
{this fields are new !!}
ObjectType:Exception;
jmpWorker:jmp_buf;
END;
PFPEG=^FPREG;
FPREG=RECORD {pack 1}
losig:LONGWORD;
hisig:LONGWORD;
signexp:WORD;
END;
PCONTEXTRECORD=^CONTEXTRECORD;
CONTEXTRECORD=RECORD
ContextFlags:LONGWORD;
ctx_env:ARRAY[0..6] OF LONGWORD;
ctx_stack:ARRAY[0..7] OF FPREG;
ctx_SegGs:LONGWORD;
ctx_SegFs:LONGWORD;
ctx_SegEs:LONGWORD;
ctx_SegDs:LONGWORD;
ctx_RegEdi:LONGWORD;
ctx_RegEsi:LONGWORD;
ctx_RegEax:LONGWORD;
ctx_RegEbx:LONGWORD;
ctx_RegEcx:LONGWORD;
ctx_RegEdx:LONGWORD;
ctx_RegEbp:LONGWORD;
ctx_RegEip:LONGWORD;
ctx_SegCs:LONGWORD;
ctx_EFlags:LONGWORD;
ctx_RegEsp:LONGWORD;
ctx_SegSs:LONGWORD;
END;
{ Exceptions }
//base exception record - derive all new exceptions from that !
Exception = CLASS(TObject)
PRIVATE
FMessage: PString;
FUNCTION GetMessage: STRING;
PROCEDURE SetMessage(CONST Value: STRING);
PUBLIC
ReportRecord:EXCEPTIONREPORTRECORD;
ExcptNum:LONGWORD;
CameFromRTL:BOOLEAN;
Nested:BOOLEAN;
ExcptAddr:POINTER;
RTLExcptAddr:POINTER;
RegistrationRecord:EXCEPTIONREGISTRATIONRECORD;
ContextRecord:CONTEXTRECORD;
CONSTRUCTOR Create(CONST Msg: STRING);
DESTRUCTOR Destroy;OVERRIDE;
PROPERTY
Message:STRING read GetMessage write SetMessage;
PROPERTY
MessagePtr: PString read FMessage;
END;
//General exception class
ExceptClass = class OF Exception;
//Software generated excpetions
EProcessTerm = CLASS(Exception);
//Hardware generated exceptions
EProcessorException = CLASS(Exception);
EFault = CLASS(EProcessorException);
EGPFault = CLASS(EFault);
EStackFault = CLASS(EFault);
EPageFault = CLASS(EFault);
EInvalidOpCode = CLASS(EFault);
EBreakpoint = CLASS(EProcessorException);
ESingleStep = CLASS(EProcessorException);
//Memory exceptions
EOutOfMemory = CLASS(Exception);
EInvalidPointer = CLASS(Exception);
EInvalidHeap = CLASS(Exception);
//Input/Output exceptions
EInOutError = CLASS(Exception)
PUBLIC
ErrorCode: Integer;
END;
EFileNotFound=CLASS(EInOutError);
EInvalidFileName=CLASS(EInOutError);
ETooManyOpenFiles=CLASS(EInOutError);
EAccessDenied=CLASS(EInOutError);
EEndOfFile=CLASS(EInOutError);
EDiskFull=CLASS(EInOutError);
EInvalidInput=CLASS(EInOutError);
//Integer math exceptions
EIntError = CLASS(Exception);
EDivByZero = CLASS(EIntError);
ERangeError = CLASS(EIntError);
EIntOverflow = CLASS(EIntError);
//Floating point math exceptions
EMathError = CLASS(Exception);
EInvalidOp = CLASS(EMathError);
EZeroDivide = CLASS(EMathError);
EOverflow = CLASS(EMathError);
EUnderflow = CLASS(EMathError);
//type cast exceptions
EInvalidCast = CLASS(Exception);
EConvertError = CLASS(Exception);
//PM Routines
VAR
AppHandle:LONGWORD;
AppQueueHandle:LONGWORD;
DllModule:LONGWORD;
DllTerminating:LONGWORD;
DllInitTermResult:LONGWORD;
ModuleCount:BYTE;
RaiseIOError:BOOLEAN;
FUNCTION WinInitialize(flOptions:LONGWORD):LONGWORD;
FUNCTION WinTerminate(ahab:LONGWORD):BOOLEAN;
FUNCTION WinCreateMsgQueue(ahab:LONGWORD;cmsg:LONGINT):LONGWORD;
FUNCTION WinDestroyMsgQueue(ahmq:LONGWORD):BOOLEAN;
PROCEDURE MainDispatchLoop;
PROCEDURE SelToFlat(VAR p:POINTER);
FUNCTION Assigned(p: Pointer): Boolean;
IMPLEMENTATION
//General functions
FUNCTION Assigned(p: Pointer): Boolean;
BEGIN
Assigned := p <> Nil;
END;
PROCEDURE Check_Is(o:TObject;ClassInfo:TClass);
VAR bo:BOOLEAN;
BEGIN
IF o=NIL THEN bo:=FALSE
ELSE bo:=o.InheritsFrom(ClassInfo);
ASM
CMPB $bo,1
LEAVE
RETN32 8
END;
END;
PROCEDURE Check_Is_Class(c:TClass;ClassInfo:TClass);
VAR bo:BOOLEAN;
BEGIN
bo:=c.InheritsFrom(ClassInfo);
ASM
CMPB $bo,1
LEAVE
RETN32 8
END;
END;
PROCEDURE Check_As(o:TObject;ClassInfo:TClass);
VAR Adr:LONGINT;
e:EInvalidCast;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF not o.InheritsFrom(ClassInfo) THEN
BEGIN
e.Create('Invalid type cast (EInvalidCast)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
END;
PROCEDURE SelToFlat(VAR p:POINTER);
BEGIN
asm
mov edi,$p
mov eax,[edi+0]
ror eax,16
shr ax,3
rol eax,16
mov [edi+0],eax
end;
END;
PROCEDURE OverflowError;
VAR e:EIntOverflow;
Adr:LONGWORD;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
e.Create('Integer Overflow (EIntOverflow)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
VAR MinStack:LONGWORD;
StackSize:LONGWORD;
PROCEDURE StackError(Adr:LONGWORD);
VAR e:EStackFault;
BEGIN
e.Create('Stack overflow (EStackFault)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
PROCEDURE CheckStack(Needed:LONGWORD);
VAR ESP:LONGWORD;
Adr:LONGWORD;
BEGIN
ASM
PUSHAD
MOV $ESP,ESP
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF ESP>MinStack THEN IF ESP<MinStack+StackSize THEN
BEGIN
IF ((ESP-Needed<MinStack)OR(ESP-Needed>MinStack+StackSize))
THEN StackError(Adr);
END;
ASM
POPAD
END;
END;
PROCEDURE RangeCheckError(Adr:LONGWORD);
VAR e:ERangeError;
BEGIN
e.Create('Range check error (ERangeError)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
PROCEDURE CheckRange(U,O,V:LONGINT);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$V
CMP EAX,$U
JL !err_this_xxx
MOV EAX,$V
CMP EAX,$O
JG !err_this_xxx
POP EAX
LEAVE
RETN32 12
!err_this_xxx:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRangeUnsigned(U,O,V:LONGWORD);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$V
CMP EAX,$U
JB !err_this_xxx1
MOV EAX,$V
CMP EAX,$O
JA !err_this_xxx1
POP EAX
LEAVE
RETN32 12
!err_this_xxx1:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRange2(Nr,V:LONGINT);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$Nr
CMP EAX,1
JNE !my_lab1
MOV EAX,$V
CMP EAX,MINSHORTINT
JL !err_this_xxx2
CMP EAX,MAXSHORTINT
JG !err_this_xxx2
jmp !ex_this_xxx
!my_lab1:
CMP EAX,2
JNE !my_lab2
MOV EAX,$V
CMP EAX,MININT
JL !err_this_xxx2
CMP EAX,MAXINT
JG !err_this_xxx2
jmp !ex_this_xxx
!my_lab2:
CMP EAX,4
JNE !ex_this_xxx
MOV EAX,$V
CMP EAX,MINLONGINT
JL !err_this_xxx2
CMP EAX,MAXLONGINT
JG !err_this_xxx2
!ex_this_xxx:
POP EAX
LEAVE
RETN32 8
!err_this_xxx2:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRangeUnsigned2(Nr,V:LONGWORD);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$Nr
CMP EAX,1
JNE !my_lab1w
MOV EAX,$V
CMP EAX,MINBYTE
JB !err_this_xxx2w
CMP EAX,MAXBYTE
JA !err_this_xxx2w
jmp !ex_this_xxxw
!my_lab1w:
CMP EAX,2
JNE !my_lab2w
MOV EAX,$V
CMP EAX,MINWORD
JB !err_this_xxx2w
CMP EAX,MAXWORD
JA !err_this_xxx2w
jmp !ex_this_xxxw
!my_lab2w:
CMP EAX,4
JNE !ex_this_xxxw
MOV EAX,$V
CMP EAX,MINLONGWORD
JB !err_this_xxx2w
CMP EAX,MAXLONGWORD
JA !err_this_xxx2w
!ex_this_xxxw:
POP EAX
LEAVE
RETN32 8
!err_this_xxx2w:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
FUNCTION Swap(i:INTEGER):INTEGER;
BEGIN
Swap:=lo(i)*256+hi(i);
END;
VAR
MaxWindMin: WORD; { Max Window upper left coordinates }
MaxWindMax: WORD; { Max Window lower right coordinates }
Redirect,RedirectOut,RedirectIn:BOOLEAN;
//PM routines
IMPORTS
FUNCTION WinMessageBox(hwndParent,hwndOwner:LONGWORD;pszText,pszCaption:CSTRING;
idWindow,flStyle:LONGWORD):LONGWORD;
APIENTRY; PMWIN index 789;
END;
TYPE
PTIB2=^TIB2;
TIB2=RECORD
tib2_ultid:LONGWORD; { Thread I.D. }
tib2_ulpri:LONGWORD; { Thread priority }
tib2_version:LONGWORD; { Version number for this structure }
tib2_usMCCount:WORD; { Must Complete count }
tib2_fMCForceFlag:WORD; { Must Complete force flag }
END;
PTIB=^TIB;
TIB=RECORD
tib_pexchain:POINTER; { Head of exception handler chain }
tib_pstack:POINTER; { Pointer to base of stack }
tib_pstacklimit:POINTER; { Pointer to end of stack }
tib_ptib2:PTIB2; { Pointer to system specific TIB }
tib_version:LONGWORD; { Version number for this TIB structure }
tib_ordinal:LONGWORD; { Thread ordinal number }
END;
{ Process Information Block (PIB) }
TYPE
PPIB=^PIB;
PIB=RECORD
pib_ulpid:LONGWORD; { Process I.D. }
pib_ulppid:LONGWORD; { Parent process I.D. }
pib_hmte:LONGWORD; { Program (.EXE) module handle }
pib_pchcmd:PChar; { Command line pointer }
pib_pchenv:PChar; { Environment pointer }
pib_flstatus:LONGWORD; { Process' status bits }
pib_ultype:LONGWORD; { Process' type code }
END;
FUNCTION DosGetInfoBlocks(VAR pptib:PTIB;VAR pppib:PPIB):LONGWORD;
APIENTRY; external 'DOSCALLS' index 312;
FUNCTION WinInitialize(flOptions:LONGWORD):LONGWORD;
VAR tib:PTIB;
pib:PPIB;
LABEL l;
BEGIN
DosGetInfoBlocks(tib,pib);
IF ((tib<>NIL)AND(tib^.tib_ptib2<>NIL)) THEN
BEGIN
IF tib^.tib_ptib2^.tib2_ultid=1 THEN goto l; {1st thread}
result:=WinInitializeAPI(flOptions);
END
ELSE
BEGIN
l:
IF AppHandle=0 THEN AppHandle:=WinInitializeAPI(flOptions);
result:=AppHandle;
END;
END;
FUNCTION WinTerminate(ahab:LONGWORD):BOOLEAN;
BEGIN
IF ahab=AppHandle THEN
BEGIN
WinTerminate:=FALSE;
exit;
END;
WinTerminate:=WinTerminateAPI(ahab);
END;
FUNCTION WinCreateMsgQueue(ahab:LONGWORD;cmsg:LONGINT):LONGWORD;
LABEL l;
BEGIN
IF ahab=AppHandle THEN
BEGIN
IF AppQueueHandle<>0 THEN
BEGIN
IF cmsg<>0 THEN
BEGIN
WinDestroyMsgQueueAPI(AppQueueHandle);
goto l;
END
ELSE WinCreateMsgQueue:=AppQueueHandle;
END
ELSE
BEGIN
l:
AppQueueHandle:=WinCreateMsgQueueAPI(ahab,cmsg);
result:=AppQueueHandle;
END;
END
ELSE result:=WinCreateMsgQueueAPI(ahab,cmsg);
END;
FUNCTION WinDestroyMsgQueue(ahmq:LONGWORD):BOOLEAN;
BEGIN
IF ahmq=AppQueueHandle THEN result:=FALSE
ELSE result:=WinDestroyMsgQueueAPI(ahmq);
END;
//Exception management
{The standard exception class}
FUNCTION Exception.GetMessage:STRING;
BEGIN
GetMessage:=FMessage^;
END;
PROCEDURE Exception.SetMessage(CONST Value:STRING);
BEGIN
IF FMessage<>NIL THEN
FreeMem(FMessage,length(FMessage^)+1);
GetMem(FMessage,length(value)+1);
FMessage^:=value;
END;
CONSTRUCTOR Exception.Create(CONST msg:STRING);
BEGIN
GetMem(FMessage,length(msg)+1);
FMessage^:=msg;
END;
DESTRUCTOR Exception.Destroy;
BEGIN
IF FMessage<>NIL THEN
FreeMem(FMessage,length(FMessage^)+1);
END;
//OS2 Exception numbers
CONST
XCPT_GUARD_PAGE_VIOLATION =$80000001;
XCPT_DATATYPE_MISALIGNMENT =$C000009E;
XCPT_BREAKPOINT =$C000009F;
XCPT_SINGLE_STEP =$C00000A0;
XCPT_ACCESS_VIOLATION =$C0000005;
XCPT_ILLEGAL_INSTRUCTION =$C000001C;
XCPT_FLOAT_DENORMAL_OPERAND =$C0000094;
XCPT_FLOAT_DIVIDE_BY_ZERO =$C0000095;
XCPT_FLOAT_INEXACT_RESULT =$C0000096;
XCPT_FLOAT_INVALID_OPERATION =$C0000097;
XCPT_FLOAT_OVERFLOW =$C0000098;
XCPT_FLOAT_STACK_CHECK =$C0000099;
XCPT_FLOAT_UNDERFLOW =$C000009A;
XCPT_INTEGER_DIVIDE_BY_ZERO =$C000009B;
XCPT_INTEGER_OVERFLOW =$C000009C;
XCPT_PRIVILEGED_INSTRUCTION =$C000009D;
XCPT_IN_PAGE_ERROR =$C0000006;
XCPT_PROCESS_TERMINATE =$C0010001;
XCPT_ASYNC_PROCESS_TERMINATE =$C0010002;
XCPT_NONCONTINUABLE_EXCEPTION =$C0000024;
XCPT_INVALID_DISPOSITION =$C0000025;
XCPT_INVALID_LOCK_SEQUENCE =$C000001D;
XCPT_ARRAY_BOUNDS_EXCEEDED =$C0000093;
XCPT_B1NPX_ERRATA_02 =$C0010004;
XCPT_UNWIND =$C0000026;
XCPT_BAD_STACK =$C0000027;
XCPT_INVALID_UNWIND_TARGET =$C0000028;
XCPT_SIGNAL =$C0010003;
XCPT_INTERNAL_RTL =$E0000000;
{return values}
CONST
XCPT_CONTINUE_SEARCH =$00000000; { exception not handled }
XCPT_CONTINUE_EXECUTION =$FFFFFFFF; { exception handled }
XCPT_CONTINUE_STOP =$00716668; { exception handled by }
{ debugger (VIA DosDebug) }
VAR
RegisterInfo:STRING;
{The exception handler. Incoming exceptions will come here first}
FUNCTION ExcptHandler(VAR p1:EXCEPTIONREPORTRECORD;
VAR p2:EXCEPTIONREGISTRATIONRECORD;
VAR p3:CONTEXTRECORD;
pv:POINTER):LONGWORD;CDECL;
BEGIN
{Jump to the label set by setjmp}
WITH p3 DO
Registerinfo:= #13#10'at CS:EIP ='+
ToHex(ctx_SegCs )+':'+ToHex(ctx_RegEip);
IF POINTER(p2.ObjectType)=NIL THEN {no object associated}
BEGIN
//Handle all hardware exceptions
//all other exceptions will be notified by an exception class
CASE p1.ExceptionNum OF
XCPT_BREAKPOINT:
p2.ObjectType:=EBreakPoint.Create('Breakpoint exception (EBreakPoint) occured'+
RegisterInfo);
XCPT_BAD_STACK:
p2.ObjectType:=EStackFault.Create('Stack fault exception (EStackFault) occured'+
RegisterInfo);
XCPT_ACCESS_VIOLATION:
p2.ObjectType:=EGPFault.Create('Access violation exception (EGPFault) occured'+
RegisterInfo);
XCPT_IN_PAGE_ERROR:
p2.ObjectType:=EPageFault.Create('Page fault exception (EPageFault) occured'+
RegisterInfo);
XCPT_ILLEGAL_INSTRUCTION,XCPT_PRIVILEGED_INSTRUCTION:
p2.ObjectType:=EInvalidOpCode.Create('Invalid instruction exception (EInvalidOpCode) occured'+
RegisterInfo);
XCPT_SINGLE_STEP:
p2.ObjectType:=ESingleStep.Create('Single step exception (ESingleStep) occured'+
RegisterInfo);
XCPT_INTEGER_DIVIDE_BY_ZERO:
p2.ObjectType:=EDivByZero.Create('Integer divide by zero exception (EDivByZero) occured'+
RegisterInfo);
XCPT_INTEGER_OVERFLOW:
p2.ObjectType:=EIntOverFlow.Create('Integer overflow exception (EIntOverFlow) occured'+
RegisterInfo);
XCPT_FLOAT_DIVIDE_BY_ZERO:
p2.ObjectType:=EZeroDivide.Create('Float zero divide exception (EZeroDivide) occured'+
RegisterInfo);
XCPT_FLOAT_INVALID_OPERATION:
p2.ObjectType:=EInvalidOp.Create('Float invalid operation exception (EInvalidOp) occured'+
RegisterInfo);
XCPT_FLOAT_OVERFLOW:
p2.ObjectType:=EOverFlow.Create('Float overflow exception (EOverFlow) occured'+
RegisterInfo);
XCPT_FLOAT_UNDERFLOW:
p2.ObjectType:=EUnderFlow.Create('Float underflow exception (EUnderFlow) occured'+
RegisterInfo);
XCPT_FLOAT_DENORMAL_OPERAND,XCPT_FLOAT_INEXACT_RESULT,
XCPT_FLOAT_STACK_CHECK:
p2.ObjectType:=EMathError.Create('General float exception (EMathError) occured'+
RegisterInfo);
XCPT_PROCESS_TERMINATE: {don't handle}
BEGIN
{p2.ObjectType:=EProcessTerm.Create('Process terminated exception (EProcessTerm) occured');}
{}ExcptHandler:=XCPT_CONTINUE_SEARCH;
exit;{}
END;
XCPT_ASYNC_PROCESS_TERMINATE: {Don't handle}
BEGIN
ExcptHandler:=XCPT_CONTINUE_SEARCH;
exit;
END;
XCPT_GUARD_PAGE_VIOLATION: {Don't handle}
BEGIN
ExcptHandler:=XCPT_CONTINUE_SEARCH;
exit;
END;
XCPT_INTERNAL_RTL:
BEGIN
ExcptHandler:=XCPT_CONTINUE_EXECUTION;
exit;
END;
ELSE {Don't handle}
BEGIN
ExcptHandler:=XCPT_CONTINUE_SEARCH;
exit;
{p2.ObjectType:=EFault.Create('Unknown hardware exception (EFault) occured');}
END;
END; {case}
END;
p2.ObjectType.ReportRecord:=p1;
p2.ObjectType.RegistrationRecord:=p2;
p2.ObjectType.ExcptNum:=p1.ExceptionNum;
p2.ObjectType.ExcptAddr:=POINTER(p3.ctx_RegEIP);
p2.ObjectType.ContextRecord:=p3;
longjmp(p2.jmpWorker,LONGWORD(p2.ObjectType));
END;
IMPORTS
FUNCTION DosRaiseException(VAR Pexcept:EXCEPTIONREPORTRECORD):LONGWORD;
APIENTRY; DOSCALLS index 356;
END;
PROCEDURE ExcptRunError(e:Exception);
VAR
s:STRING;
cs:CSTRING;
cTitle:CSTRING;
RepRec:EXCEPTIONREPORTRECORD;
BEGIN
try
IF e.CameFromRTL THEN IF not e.Nested THEN
BEGIN
e.Nested:=TRUE;
RepRec.ExceptionNum:=XCPT_INTERNAL_RTL;
RepRec.fHandlerFlags:=0;
RepRec.NestedExceptionReportRecord:=NIL;
RepRec.ExceptionAddress:=NIL;
RepRec.cParameters:=2;
RepRec.ExceptionInfo[0]:=LONGWORD(e.RTLExcptAddr);
RepRec.ExceptionInfo[1]:=LONGWORD(e.FMessage);
DosRaiseException(RepRec);
END;
finally
e.ExcptAddr:=e.RTLExcptAddr;
end;
IF POINTER(e.ExcptAddr)<>NIL THEN
s:='Exception occured: '+e.Message+' at '+tohex(LONGWORD(e.ExcptAddr))+
#13#10'Program is terminated.'
ELSE
s:='Exception occured: '+e.Message+
#13#10'Program is terminated.';
IF ApplicationType=1 THEN
BEGIN
cs:=s;
cTitle:='Exception occured';
WinMessageBox(1,1,cs,ctitle,0,$4000 OR $0010);
END
ELSE Writeln(s);
Halt;
END;
PROCEDURE RaiseException(objekt:Exception;adress:LONGWORD);
VAR
PRegisRec:PEXCEPTIONREGISTRATIONRECORD; {top exception registration record}
ReportRec:EXCEPTIONREPORTRECORD;
ContextRec:CONTEXTRECORD;
RepRec:EXCEPTIONREPORTRECORD;
BEGIN
ASM
MOV ESI,0
db $64 //SEG FS
MOV EAX,[ESI+0]
MOV $PRegisRec,EAX
END;
IF LONGWORD(PRegisRec)=$ffffffff THEN {no handler installed}
BEGIN
ExcptRunError(objekt);
END;
PRegisRec^.ObjectType:=objekt; {set exception type}
{set up context record}
fillchar(ContextRec,sizeof(CONTEXTRECORD),0);
{set up report record}
fillchar(ReportRec,sizeof(EXCEPTIONREPORTRECORD),0);
IF Adress=0 THEN
BEGIN
ASM
MOV EAX,[EBP+4]
MOV $Adress,EAX
END;
END;
{Objekt.Nested:=TRUE;}
{Objekt.CameFromRTL:=TRUE;}
Objekt.RTLExcptAddr:=POINTER(Adress);
RepRec.ExceptionNum:=XCPT_INTERNAL_RTL;
RepRec.fHandlerFlags:=0;
RepRec.NestedExceptionReportRecord:=NIL;
RepRec.ExceptionAddress:=NIL;
RepRec.cParameters:=2;
RepRec.ExceptionInfo[0]:=LONGWORD(Objekt.RTLExcptAddr);
RepRec.ExceptionInfo[1]:=LONGWORD(Objekt.FMessage);
DosRaiseException(RepRec);
ReportRec.ExceptionAddress:=POINTER(Adress);
ExcptHandler(ReportRec,PRegisRec^,ContextRec,NIL);
END;
PROCEDURE RaiseExceptionAgain(e:Exception);
VAR
PRegisRec:PEXCEPTIONREGISTRATIONRECORD; {top exception registration record}
BEGIN
ASM
MOV ESI,0
db $64 //SEG FS
MOV EAX,[ESI+0]
MOV $PRegisRec,EAX
END;
IF LONGWORD(PRegisRec)=$ffffffff THEN {no handler installed}
BEGIN
ExcptRunError(e);
END;
PRegisRec^.ObjectType:=e; {set exception type}
ExcptHandler(e.ReportRecord,PRegisRec^,e.ContextRecord,NIL);
END;
PROCEDURE Beep(Freq,duration:LONGWORD);
BEGIN
ASM
PUSHL $duration
PUSHL $freq
MOV AL,2
CALLDLL DOSCALLS,286 //DosBeep
ADD ESP,8
END;
END;
//File I/O support
TYPE
PFEA2=^FEA2;
FEA2=RECORD {pack 1}
oNextEntryOffset:LONGWORD; { new field }
fEA:BYTE;
cbName:BYTE;
cbValue:WORD;
szName:CSTRING[1]; { new field }
END;
PFEA2LIST=^FEA2LIST;
FEA2LIST=RECORD {pack 1}
cbList:LONGWORD;
list:ARRAY[0..0] OF FEA2;
END;
PGEA2=^GEA2;
GEA2=RECORD {pack 1}
oNextEntryOffset:LONGWORD; { new field }
cbName:BYTE;
szName:ARRAY[0..0] OF BYTE; { new field }
END;
PGEA2LIST=^GEA2LIST;
GEA2LIST=RECORD { pack 1 }
cbList:LONGWORD;
list:ARRAY [0..0] OF GEA2;
END;
PEAOP2=^EAOP2;
EAOP2=RECORD { pack 1 }
fpGEA2List:PGEA2LIST; { GEA set }
fpFEA2List:PFEA2LIST; { FEA set }
oError:LONGWORD; { offset of FEA error }
END;
CONST
MAX_GEA = 500; // Max size for a GEA List
IMPORTS
FUNCTION DosOpen(pszFileName:CSTRING;VAR pHf:LONGWORD;VAR pulAction:LONGWORD;
cbFile,ulAttribute,fsOpenFlags,fsOpenMode:LONGWORD;
VAR apeaop2{:EAOP2}):LONGWORD;
APIENTRY; DOSCALLS index 273;
FUNCTION DosEnumAttribute(ulRefType:LONGWORD;VAR pvFile;ulEntry:LONGWORD;
VAR pvBuf;cbBuf:LONGWORD;VAR pulCount:LONGWORD;
ulInfoLevel:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 372;
FUNCTION DosQueryPathInfo(VAR pszPathName:CSTRING;ulInfoLevel:LONGWORD;
VAR pInfoBuf;cbInfoBuf:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 223;
FUNCTION DosQueryFileInfo(hf:LONGWORD;ulInfoLevel:LONGWORD;
VAR pInfo;cbInfoBuf:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 279;
FUNCTION DosSetPathInfo(pszPathName:CSTRING;ulInfoLevel:LONGWORD;VAR pInfoBuf;
cbInfoBuf,flOptions:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 219;
FUNCTION DosSetFileInfo(hf:LONGWORD;ulInfoLevel:LONGWORD;VAR pInfoBuf;
cbInfoBuf:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 218;
FUNCTION DosClose(ahFile:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 257;
FUNCTION DosSetFilePtr(ahFile:LONGWORD;ib:LONGINT;method:LONGWORD;
VAR ibActual:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 256;
FUNCTION DosCreateDir(pszDirName:CSTRING;VAR apeaop2:EAOP2):LONGWORD;
APIENTRY; DOSCALLS index 270;
FUNCTION DosDeleteDir(pszDir:CSTRING):LONGWORD;
APIENTRY; DOSCALLS index 226;
FUNCTION DosSetDefaultDisk(disknum:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 220;
FUNCTION DosQueryCurrentDisk(VAR pdisknum,plogical:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 275;
FUNCTION DosSetCurrentDir(pszDir:CSTRING):LONGWORD;
APIENTRY; DOSCALLS index 255;
FUNCTION DosQueryCurrentDir(disknum:LONGWORD;VAR pBuf;
VAR pcbBuf:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 274;
FUNCTION DosRead(ahFile:LONGWORD;VAR pBuffer;cbRead:LONGWORD;
VAR pcbActual:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 281;
FUNCTION DosWrite(ahFile:LONGWORD;VAR pBuffer;cbWrite:LONGWORD;
VAR pcbActual:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 282;
FUNCTION DosMove(VAR pszOld,pszNew:CSTRING):LONGWORD;
APIENTRY; DOSCALLS index 271;
FUNCTION DosSetFileSize(ahFile:LONGWORD;cbSize:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 272;
FUNCTION DosDelete(VAR pszFile:CSTRING):LONGWORD;
APIENTRY; DOSCALLS index 259;
END;
VAR
FileBufSize:LONGWORD; {Standard file buffer size (32768 bytes}
PROCEDURE Assign(VAR f:FILE;CONST s:String);
VAR ff:^FileRec;
SaveIOError:BOOLEAN;
BEGIN
ff:=@f;
fillchar(f,sizeof(f),0);
ff^.Name:=s; {Assign name to file variable}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
ff^.MaxCacheMem:=FileBufSize; {Initial bufsize}
ff^.Buffer:=NIL;
IF ff^.MaxCacheMem<16 THEN ff^.MaxCacheMem:=16;
IOResult:=0; {Clear IOResult variable}
END;
PROCEDURE InvalidFileNameError(Adr:LONGINT);
VAR
e:EInvalidFileName;
BEGIN
e.Create('Invalid file name (EInvalidFileName)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
e.ErrorCode:=206; {filename exceeds range}
RAISE e;
END;
PROCEDURE InOutError(Code:LONGWORD;Adr:LONGWORD);
VAR
e:EInOutError;
BEGIN
e.Create('Input/Output error (EInOutError)');
e.ErrorCode:=code;
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
RAISE e;
END;
CONST
{Modes for FileBlockIO}
ReadMode = 1;
WriteMode = 2;
PROCEDURE FileBlockIO(VAR f:FILE;BlockNr:LONGWORD;Mode:LONGWORD;
VAR result:LONGWORD);
VAR
l:LONGWORD;
po:LONGWORD;
temp:LONGWORD;
ff:^FileRec;
BEGIN
ff:=@f;
IOResult:=0;
IF ff^.changed THEN
BEGIN
ff^.changed:=FALSE;
FileBlockIO(f,ff^.block,WriteMode,Temp);
IF IOResult<>0 THEN exit;
END;
IF blocknr=ff^.LBlock THEN l:=ff^.LOffset
ELSE l:=ff^.MaxCacheMem;
po:=ff^.MaxCacheMem*blocknr;
IOResult:=DosSetFilePtr(ff^.Handle,po,0,Temp);
IF IOResult<>0 THEN exit;
IF l>0 THEN
BEGIN
CASE Mode OF
WriteMode:
BEGIN
IOResult:=DosWrite(ff^.Handle,ff^.Buffer^,l,result);
END;
ReadMode:
BEGIN
IOResult:=DosRead(ff^.Handle,ff^.Buffer^,l,result);
END;
END; {case}
END;
END;
FUNCTION FileFileSize(VAR f:FILE):LONGWORD;
VAR
ff:^FileRec;
Temp,Temp1,Temp2:LONGWORD;
BEGIN
ff:=@f;
IOResult:=DosSetFilePtr(ff^.Handle,0,1,Temp);
IF IOResult<>0 THEN exit;
IOResult:=DosSetFilePtr(ff^.Handle,0,2,Temp1);
IF IOResult<>0 THEN exit;
IOResult:=DosSetFilePtr(ff^.Handle,Temp,0,Temp2);
IF IOResult<>0 THEN exit;
FileFileSize:=Temp1;
END;
FUNCTION FileFilePos(VAR f:FILE):LONGWORD;
VAR
ff:^FileRec;
Temp:LONGWORD;
BEGIN
ff:=@f;
IOResult:=DosSetFilePtr(ff^.Handle,0,1,Temp);
IF IOResult<>0 THEN exit;
FileFilePos:=Temp;
END;
VAR OpenedFiles:ARRAY[1..51] OF LONGWORD; {Handles for opened files}
OpenedFilesCount:BYTE;
PROCEDURE Rewrite(VAR f:FILE;recsize:LONGWORD);
VAR
action:LONGWORD;
ff:^FileRec;
c:CSTRING;
e:EFileNotFound;
Size,Temp:LONGWORD;
SaveIOError:BOOLEAN;
Adr:LONGWORD;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IOResult:=0;
ff:=@f;
ff^.RecSize:=recsize;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle<>$ffffffff THEN
BEGIN
{Close file first}
SaveIoError:=RaiseIOError;
RaiseIOError:=FALSE;
Close(f);
RaiseIoError:=SaveIoError;
(*IOResult:=85; {File already assigned}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
END;
ff^.Buffer:=NIL;
c:=ff^.Name;
{for rewrite no extended attributes can be determined - use reset !}
IOResult:=DosOpen(c,ff^.Handle,action,0,$20,18,FileMode,NIL{EAOP2});
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN
BEGIN
e.Create('File not found (EFileNotFound)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
e.ErrorCode:=IoResult;
RAISE e;
END
ELSE exit;
END;
ff^.Mode:=FileMode;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
{Set the buffer values}
size:=FileFileSize(f);
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF OpenedFilesCount<50 THEN inc(OpenedFilesCount);
OpenedFiles[OpenedFilesCount]:=ff^.Handle;
getmem(ff^.Buffer,ff^.MaxCacheMem);
ff^.LBlock:=size DIV ff^.MaxCacheMem;
ff^.LOffset:=size MOD ff^.MaxCacheMem;
FileBlockIO(f,0,readmode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Block:=0;
ff^.Offset:=0;
END;
PROCEDURE Reset(VAR f:FILE;recsize:LONGWORD);
VAR
action:LONGWORD;
ff:^FileRec;
c:CSTRING;
p:POINTER;
pAllocc:POINTER;
pBigAlloc:POINTER;
cbBigAlloc:WORD;
ulEntryNum:LONGWORD;
ulEnumCnt:LONGWORD;
pLastIn:PHOLDFEA;
pNewFEA:PHOLDFEA;
pFEA:PFEA2;
pGEAList:PGEA2LIST;
eaopGet:EAOP2;
apHoldFEA:PHOLDFEA;
e:EFileNotFound;
size,Temp:LONGWORD;
SaveIoError:BOOLEAN;
Adr:LONGINT;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IOResult:=0;
ff:=@f;
ff^.RecSize:=recsize;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle<>$ffffffff THEN
BEGIN
{Close file first}
SaveIoError:=RaiseIOError;
RaiseIOError:=FALSE;
Close(f);
RaiseIoError:=SaveIoError;
(*IOResult:=85; {File already assigned}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
END;
ff^.Buffer:=NIL;
c:=ff^.Name;
{open and read extended attributes}
IOResult:=DosOpen(c,ff^.Handle,action,0,0,1,FileMode,NIL{EAOP2});
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN
BEGIN
e.Create('File not found (EFileNotFound)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
e.ErrorCode:=IoResult;
RAISE e;
END
ELSE exit;
END;
{Query extended attributes}
pAllocc:=NIL; // Holds the FEA struct returned by DosEnumAttribute
// used to create the GEA2LIST for DosQueryPathInfo
pBigAlloc:=NIL; // Temp buffer to hold each EA as it is read in
cbBigAlloc:=0; // Size of buffer
ulEntryNum := 1; // count of current EA to read (1-relative)
pLastIn:=NIL; // Points to last EA added, so new EA can link
pNewFEA:=NIL; // Struct to build the new EA in
GetMem(pAllocc, MAX_GEA);
pFEA := pAllocc; // pFEA always uses pAlloc buffer
apHoldFEA := NIL; // Reset the pointer for the EA linked list
WHILE TRUE DO // Loop continues until there are no more EAs */
BEGIN
ulEnumCnt := 1;
IF DosEnumAttribute(0,ff^.Handle,ulEntryNum,pAllocc^,
MAX_GEA,ulEnumCnt,1) <>0 THEN
BEGIN
{There was some sort of error}
goto l;
END;
IF ulEnumCnt <> 1 THEN goto l; // All the EAs have been read
inc(ulEntryNum);
GetMem(pNewFEA, sizeof(THOLDFEA));
pNewFEA^.cbName := pFEA^.cbName; // Fill in the HoldFEA structure
pNewFEA^.cbValue:= pFEA^.cbValue;
pNewFEA^.fEA := pFEA^.fEA;
pNewFEA^.next := NIL;
pNewFEA^.szName:=pFEA^.szName; // Copy in EA Name
cbBigAlloc := sizeof(FEA2LIST) + pNewFEA^.cbName+1 +
pNewFEA^.cbValue;
GetMem(pBigAlloc, cbBigAlloc);
pGEAList := pAllocc; // Set up GEAList structure
pGEAList^.cbList := sizeof(GEA2LIST) +
pNewFEA^.cbName; // +1 for NULL
pGEAList^.list[0].oNextEntryOffset := 0;
pGEAList^.list[0].cbName := pNewFEA^.cbName;
CSTRING(pGEAList^.list[0].szName):=pNewFEA^.szName;
eaopGet.fpGEA2List := pAllocc;
eaopGet.fpFEA2List := pBigAlloc;
eaopGet.fpFEA2List^.cbList := cbBigAlloc;
DosQueryFileInfo(ff^.Handle, // Get the complete EA info
3,
eaopGet,
sizeof(EAOP2));
getmem(pNewFEA^.aValue,pNewFEA^.cbValue); //memory for data
p:=pBigAlloc;
inc(p,sizeof(FEA2LIST)+pNewFEA^.cbName);
move(p^,
pNewFEA^.aValue^,
pNewFEA^.cbValue);
FreeMem(pBigAlloc,cbBigAlloc); // Release the temp Enum buffer
IF apHoldFEA = NIL THEN // If first EA, set pHoldFEA
apHoldFEA := pNewFEA
ELSE
pLastIn^.next := pNewFEA;
pLastIn := pNewFEA; // Update the end of the list
pLastIn^.Deleted:=FALSE; //EA is valid
END; {While}
l:
IF pLastIn<>NIL THEN pLastIn^.Next:=NIL;
FreeMem(pAllocc,MAX_GEA); // Free up the GEA buf for DosEnum
ff^.EAS:=apHoldFEA;
ff^.Mode:=FileMode;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
{Set the buffer values}
size:=FileFileSize(f);
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF OpenedFilesCount<50 THEN inc(OpenedFilesCount);
OpenedFiles[OpenedFilesCount]:=ff^.Handle;
getmem(ff^.Buffer,ff^.MaxCacheMem);
ff^.LBlock:=size DIV ff^.MaxCacheMem;
ff^.LOffset:=size MOD ff^.MaxCacheMem;
FileBlockIO(f,0,readmode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Block:=0;
ff^.Offset:=0;
END;
{Get extended attributes from a file}
FUNCTION GetEAData(VAR f:FILE):PHOLDFEA;
VAR
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
GetEAData:=NIL;
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
GetEAData:=ff^.EAS;
END;
{use with care !}
PROCEDURE EraseEAData(VAR f:FILE);
VAR
ff:^FileRec;
pFEA,next:PHOLDFEA;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
pFEA:=ff^.EAS;
WHILE pFEA<>NIL DO
BEGIN
freemem(pFEA^.aValue,pFEA^.cbValue);
next:=pFEA^.next;
dispose(pFEA);
pFEA:=next;
END;
ff^.EAS:=NIL;
END;
{use with care}
PROCEDURE SetEAData(VAR f:FILE;EAData:PHOLDFEA);
VAR
ff:^FileRec;
dummy:PHOLDFEA;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
{Erase old EA Data}
EraseEAData(f);
ff^.EAS:=NIL;
{copy the EA Data}
WHILE EAData<>NIL DO
BEGIN
IF ff^.EAS=NIL THEN
BEGIN
new(ff^.EAS);
dummy:=ff^.EAS;
END
ELSE
BEGIN
dummy:=ff^.EAS;
WHILE dummy^.Next<>NIL DO dummy:=dummy^.Next;
new(dummy^.next);
dummy:=dummy^.next;
END;
move(EAData^,dummy^,sizeof(THOLDFEA));
getmem(dummy^.aValue,dummy^.cbValue);
move(EAData^.aValue^,dummy^.avalue^,dummy^.cbValue);
dummy^.Next:=NIL;
EAData:=EAData^.Next;
END;
END;
{use with care !}
PROCEDURE DeleteEAData(VAR f:FILE);
VAR
ff:^FileRec;
pFEA,next:PHOLDFEA;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
pFEA:=ff^.EAS;
WHILE pFEA<>NIL DO
BEGIN
pFEA^.Deleted:=TRUE;
pFEA:=pFEA^.Next;
END;
END;
{Write extended attributes to an open file
The file need not to be opened but assigned
and the EA data must have been set using SetEAData
If the file is opened its sharing rights should not
conflict with exclusive write access}
PROCEDURE WriteEAData(VAR f:FILE);
VAR
ff:^FileRec;
pDL:PHOLDFEA;
pHFEA:PHOLDFEA;
eaopWrite:EAOP2;
aBuf:ARRAY[0..MAX_GEA] OF CHAR;
aPtr:^CSTRING;
pFEA:PFEA2;
usMemNeeded,usRet:LONGWORD;
pulPtr:^LONGWORD;
c:CSTRING;
p:POINTER;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
pHFEA:=ff^.EAS;
aPtr:=NIL;
pFEA:=@aBuf[4];
pulPtr:=@aBuf;
c:=ff^.Name;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
eaopWrite.fpFEA2List := @aBuf;
pFEA^.fEA := 0;
pFEA^.cbValue := 0;
pDL:=ff^.EAS;
WHILE pDL<>NIL DO // Clean out all the deleted EA names
BEGIN
IF pDL^.Deleted THEN
BEGIN
pFEA^.cbName := pDL^.cbName;
pulPtr^:= sizeof(FEA2LIST) + pFEA^.cbName;
pFEA^.szName:=pDL^.szName;
pFEA^.oNextEntryOffset := 0; {last entry}
// Delete EA's by saying cbValue=0
{DosSetPathInfo(c,2,eaopWrite,sizeof(EAOP2),$10);}
DosSetFileInfo(ff^.Handle,2,eaopWrite,sizeof(EAOP2));
END;
pDL := pDL^.next;
END;
WHILE pHFEA<>NIL DO // Go through each HoldFEA
BEGIN
IF not pHFEA^.Deleted THEN
BEGIN
usMemNeeded := sizeof(FEA2LIST) + pHFEA^.cbName+1 +
pHFEA^.cbValue;
GetMem(aPtr, usMemNeeded);
eaopWrite.fpFEA2List := POINTER(aPtr); // Fill in eaop struct
eaopWrite.fpFEA2List^.cbList := usMemNeeded;
eaopWrite.fpFEA2List^.list[0].fEA := pHFEA^.fEA;
eaopWrite.fpFEA2List^.list[0].cbName := pHFEA^.cbName;
eaopWrite.fpFEA2List^.list[0].cbValue := pHFEA^.cbValue;
eaopWrite.fpFEA2List^.list[0].oNextEntryOffset := 0; {last entry}
CSTRING(eaopWrite.fpFEA2List^.list[0].szName):=pHFEA^.szName;
p:=@eaopWrite.fpFEA2List^.list[0].szName;
inc(p,pHFEA^.cbName+1);
move(pHFEA^.aValue^,p^,pHFEA^.cbValue);
{IOResult := DosSetPathInfo(c,2,eaopWrite,sizeof(EAOP2),$10);}
IOResult:=DosSetFileInfo(ff^.Handle,2,eaopWrite,sizeof(EAOP2));
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
FreeMem(aPtr,usMemNeeded); // Free up the FEALIST struct
END;
pHFEA := pHFEA^.next;
END;
END;
PROCEDURE Close(VAR f:FILE);
VAR
ff:^FileRec;
Temp:LONGWORD;
t:BYTE;
Adr:LONGINT;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IOResult:=DosClose(ff^.Handle);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Mode:=0; {closed}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
exit;
END;
IOResult:=0;
{Write buffer to file}
IF ff^.changed THEN
BEGIN
ff^.changed:=FALSE;
FileBlockIO(F,ff^.block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
{Write EA's to the file}
WriteEAData(f);
FOR t:=1 TO OpenedFilesCount DO
BEGIN
IF OpenedFiles[t]=ff^.Handle THEN
BEGIN
move(OpenedFiles[t+1],OpenedFiles[t],(50-t)*4);
dec(OpenedFilesCount);
goto l;
END;
END;
l:
IOResult:=DosClose(ff^.Handle);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
EraseEAData(f);
ff^.Mode:=0; {closed}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
{free file buffers}
IF ff^.Buffer<>NIL THEN FreeMem(ff^.Buffer,ff^.MaxCacheMem);
ff^.Buffer:=NIL;
END;
PROCEDURE CloseAllOpenedFiles;
VAR t:BYTE;
BEGIN
FOR t:=1 TO OpenedFilesCount DO DosClose(OpenedFiles[t]);
OpenedFilesCount:=0;
END;
PROCEDURE Seek(VAR f:FILE;n:LONGINT);
VAR
ff:^FileRec;
result:LONGWORD;
pBlock:LONGWORD;
POffset:LONGWORD;
Temp:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
n:=n*ff^.RecSize;
CASE SeekMode OF
Seek_Current:inc(n,FilePos(f)*ff^.RecSize); //Seek_Current
Seek_End:inc(n,FileSize(f)*ff^.RecSize); //Seek_End
END;
IOResult:=0;
pblock:=n DIV ff^.maxcachemem;
poffset:=n MOD ff^.maxcachemem;
IF n>ff^.loffset+ff^.maxcachemem*ff^.lblock THEN
BEGIN
IF ff^.Mode AND (fmOutput OR fmInOut)<>0 THEN
BEGIN
ff^.loffset:=poffset;
ff^.lblock:=pblock;
END
ELSE
BEGIN
IOResult:=38; {Illegal pos}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
IF pblock<>ff^.block THEN
BEGIN
FileBlockIO(f,pblock,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
ff^.offset:=poffset;
ff^.block:=pblock;
END;
FUNCTION FilePos(var f:file):LongWord;
VAR
ff:^FileRec;
result:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IOResult:=0;
result:=ff^.block*ff^.maxcachemem+ff^.offset;
FilePos:=result DIV ff^.RecSize;
END;
FUNCTION Eof(var f:file):Boolean;
VAR
old,size:LONGWORD;
ff:^FIleRec;
SaveIO:BOOLEAN;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Reserved1 AND 1=1 THEN
BEGIN
eof:=TRUE;
exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IOResult:=0;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
size:=FileFileSize(f);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF ((f=Input)OR(f=Output)) THEN
BEGIN
Eof:=FALSE;
exit;
END
ELSE
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END
ELSE
BEGIN
Eof:=Size=FileFilePos(f);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
exit;
END;
IOResult:=0;
Eof:=(ff^.offset=ff^.loffset)AND(ff^.block=ff^.lblock);
END;
FUNCTION Eoln(VAR F:Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
Offset:LONGINT;
Value:BYTE;
SaveIoError:BOOLEAN;
Res:LONGWORD;
t:BYTE;
s:STRING;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF eof(f) THEN
BEGIN
result:=TRUE;
exit;
END;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
Seek(f,FilePos(f)-1);
RaiseIOError:=SaveIOError;
IF Res=0 THEN Value:=26; {EOF}
END;
END
ELSE value:=fi^.Buffer^[Offset];
IF value IN [13,10,26] THEN result:=TRUE
ELSE result:=FALSE;
END;
FUNCTION FileSize(var f:file):LongWord;
VAR
old,old1,result:LONGWORD;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IOResult:=0;
result:=ff^.lblock*ff^.maxcachemem+ff^.loffset;
FileSize:=result DIV ff^.RecSize;
END;
PROCEDURE Truncate(VAR f:FILE);
VAR
l:LONGWORD;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IOResult:=DosSetFileSize(ff^.Handle,FilePos(f));
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.lOffset:=ff^.Offset;
ff^.lBlock:=ff^.Block;
END;
PROCEDURE Append(VAR f:Text);
VAR
l:LONGWORD;
saveseek:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
Reset(f,1);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
l:=Filesize(f);
IF ioresult=0 THEN
BEGIN
SaveSeek:=seekmode;
seekmode:=0; {from file begin}
Seek(f,l);
seekmode:=saveseek;
END
ELSE
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE ChDir(CONST path:STRING);
VAR c:CSTRING;
Adr:LONGINT;
s:STRING;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF length(Path)=2 THEN IF Path[2]=':' THEN
BEGIN
IOResult:=DosSetDefaultDisk(ord(upcase(path[1]))-64);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
exit;
END;
IF POS(':\',path)=2 THEN {drive letter preceding}
BEGIN
IOResult:=DosSetDefaultDisk(ord(upcase(path[1]))-64);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
c:=upcase(path[1])+':\';
IOResult:=DosSetCurrentDir(c); {move to root directory}
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
IF path[length(Path)]='\' THEN
BEGIN
s:=Path;
dec(s[0]);
c:=s;
END
ELSE c:=path;
IOResult:=DosSetCurrentDir(c);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE GetDir(drive:byte;VAR path:STRING);
VAR
c:CSTRING;
drivemap,curdrive,MaxLen:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF Drive=0 THEN
BEGIN
{query current drive}
IOResult:=DosQueryCurrentDisk(curdrive,drivemap);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END
ELSE curdrive:=drive;
MaxLen:=250;
IOResult:=DosQueryCurrentDir(curdrive,c,MaxLen);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
path:=chr(curDrive+64)+':\'+c;
END;
PROCEDURE RmDir(CONST dir:STRING);
VAR
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
c:=Dir;
IOResult:=DosDeleteDir(c);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE MkDir(CONST dir:STRING);
VAR
c:CSTRING;
Adr:LONGINT;
BEGIN
c:=dir;
IOResult:=DosCreateDir(c,NIL);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE FileExpand(VAR f:FILE);
VAR
ff:^FileRec;
BEGIN
ff:=@f;
inc(ff^.LOffset);
IF ff^.LOffset=ff^.MaxCacheMem THEN
BEGIN
inc(ff^.LBlock);
ff^.LOffset:=0;
END;
END;
VAR
BlockReadResult,BlockWriteResult:LONGWORD;
PROCEDURE BlockRead(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
VAR
ff:^FileRec;
pp:P_FileBuffer;
t,t1:LONGWORD;
Temp:LONGWORD;
Offset,Size:LONGWORD;
OldBlock,OldOfs:LONGINT;
MaxCacheMem:LONGWORD;
Adr:LONGINT;
BEGIN
IF Count=0 THEN
BEGIN
result:=0;
exit;
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
pp:=@Buf;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IOResult:=DosRead(ff^.Handle,pp^,Count*ff^.RecSize,result);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
exit;
END;
result:=0;
Offset:=ff^.Offset;
Size:=Count*ff^.RecSize;
MaxCacheMem:=ff^.MaxCacheMem;
IF Size>MaxCacheMem THEN
BEGIN
{Block ist größer als Cache}
IF (ff^.Block*MaxCacheMem)+Offset+Size>(ff^.LBlock*MaxCacheMem)+ff^.LOffset THEN
Size:=((ff^.LBlock*MaxCacheMem)+ff^.LOffset)-
((ff^.Block*MaxCacheMem)+Offset);
IF ff^.Changed THEN
BEGIN
ff^.Changed:=FALSE;
OldBlock:=ff^.LBlock; {temporaray save}
OldOfs:=ff^.LOffset;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=Offset;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.LBlock:=OldBlock;
ff^.LOffset:=OldOfs;
END
ELSE
BEGIN
IOResult:=DosSetFilePtr(ff^.Handle,
(ff^.Block*MaxCacheMem)+Offset,0,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
IOResult:=DosRead(ff^.Handle,Buf,size,result);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
size:=result; {tatsächlich gelesen}
{set file buffer}
Temp:=Offset+size;
t:=Temp MOD MaxCacheMem;
IF size<MaxCacheMem THEN
BEGIN
move(pp^[size-t],ff^.Buffer^,t);
inc(ff^.Block,Temp DIV MaxCacheMem);
ff^.Offset:=t;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
END
ELSE
BEGIN
{nächsten Block lesen}
ff^.Changed:=FALSE;
inc(ff^.Block,Temp DIV MaxCacheMem);
FileBlockIO(f,ff^.block,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.offset:=t;
END;
IF ff^.Block>ff^.LBlock THEN
BEGIN
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
END;
result:=result DIV ff^.RecSize;
exit;
END;
IF ff^.block=ff^.LBlock THEN
BEGIN
IF Offset+size<ff^.LOffset THEN
BEGIN
{im letzten Block}
move(ff^.Buffer^[Offset],pp^,size);
inc(ff^.Offset,size);
inc(result,size);
result:=result DIV ff^.RecSize;
exit;
END;
END
ELSE
BEGIN
{irgendwo vor dem letzten Block}
IF Offset+Size<MaxCacheMem THEN
BEGIN
move(ff^.Buffer^[Offset],pp^,size);
inc(ff^.Offset,size);
inc(result,size);
result:=result DIV ff^.RecSize;
exit;
END;
END;
ff^.reserved1:=ff^.reserved1 and not 1;
FOR t:=1 TO Size DO
BEGIN
IF eof(f) THEN
BEGIN
result:=result DIV ff^.RecSize;
exit;
END;
pp^[t-1]:=ff^.Buffer^[ff^.offset];
inc(ff^.offset);
inc(result);
IF ff^.offset=maxcachemem THEN
BEGIN
FileBlockIO(f,ff^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.offset:=0;
inc(ff^.block);
END;
END;
result:=result DIV ff^.RecSize;
END;
PROCEDURE BlockWrite(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
VAR
ff:^FileRec;
pp:P_FileBuffer;
t,t1,Temp:LONGWORD;
value:BYTE;
size:LONGWORD;
Offset:LONGWORD;
OldBlock,OldOfs:LONGINT;
Adr:LONGINT;
LABEL l,l1;
BEGIN
IF Count=0 THEN
BEGIN
result:=0;
exit;
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
pp:=@Buf;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IOResult:=DosWrite(ff^.Handle,pp^,Count*ff^.RecSize,result);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
exit;
END;
result:=0;
IOResult:=0;
size:=Count*ff^.RecSize;
Offset:=ff^.Offset;
IF ff^.block=ff^.LBlock THEN
BEGIN
IF Offset=ff^.LOffset THEN
BEGIN
{am ende der Datei (im letzten Block und an LOffset)}
IF Offset+size<ff^.MaxCacheMem THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(ff^.LOffset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END
ELSE
BEGIN
{Groesse geht über alten Block hinaus}
l:
ff^.Changed:=FALSE;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
l1:
IOResult:=DosWrite(ff^.Handle,Buf,size,result);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
size:=result; {Tatsächlich geschrieben}
{set file buffer}
Temp:=Offset+size;
t:=Temp MOD ff^.MaxCacheMem;
move(pp^[size-t],ff^.Buffer^,t);
inc(ff^.Block,Temp DIV ff^.MaxCacheMem);
ff^.Offset:=t;
{we are at the end of the file}
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
result:=result DIV ff^.RecSize;
exit;
END;
END
ELSE
BEGIN
{im letzten Block aber nicht an LOffset}
IF Offset+size<ff^.LOffset THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END;
{ELSE goto l;}
END;
END
ELSE
BEGIN
{irgendwo vor dem letzten Block}
IF Offset+Size<ff^.MaxCacheMem THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END;
END;
(* IF Offset+Size>(ff^.LBlock*ff^.MaxCacheMem)+ff^.LOffset THEN
BEGIN
ff^.Changed:=FALSE;
OldBlock:=ff^.LBlock; {temporaray save}
OldOfs:=ff^.LOffset;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=Offset;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.LBlock:=OldBlock;
ff^.LOffset:=OldOfs;
goto l1;
END;*)
ff^.reserved1:=ff^.reserved1 and not 1;
FOR t:=1 TO size DO
BEGIN
value:=pp^[t-1];
IF value<>ff^.Buffer^[ff^.offset] THEN
BEGIN
ff^.Buffer^[ff^.offset]:=value;
ff^.Changed:=TRUE;
END;
IF EOF(f) THEN
BEGIN
ff^.changed:=TRUE;
FileExpand(f);
END;
inc(ff^.Offset);
inc(Result);
IF ff^.Offset=ff^.MaxCacheMem THEN
BEGIN
ff^.Changed:=FALSE;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
{neuen Block lesen}
ff^.Offset:=0;
inc(ff^.Block);
FileBlockIO(f,ff^.Block,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
END;
result:=result DIV ff^.RecSize;
END;
PROCEDURE Rename(VAR f:file;NewName:String);
VAR
c,c1:CSTRING;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
c:=NewName;
c1:=ff^.Name;
IOResult:=DosMove(c1,c);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE Erase(VAR f:file);
VAR
ff:^FileRec;
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
c:=ff^.name;
IoResult:=DosDelete(c);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE SetFileBuf(VAR f:FILE;VAR Buf;BufSize:LONGWORD);
BEGIN
IF BufSize<4096 THEN BufSize:=4096;
END;
PROCEDURE SetTextBuf(VAR f:TEXT;VAR Buf;BufSize:LONGWORD);
BEGIN
if BufSize>16*1024 then SetFileBuf(F,Buf,BufSize);
END;
PROCEDURE StrWriteText({VAR f:FILE}CONST s:STRING;format:LONGWORD);
VAR
fi:^FILE;
ss:STRING;
fillup:BYTE;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF Format+Length(s)>255 THEN Format:=255-length(s);
IF format>length(s) THEN
BEGIN
fillup:=format-length(s); {erst soviele Leerzeichen}
fillchar(ss[0],fillup,32);
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,ss[0],fillup);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
{must do this in ASM because s is constant parameter}
ASM
PUSHL $fi
MOV EDI,$s
INC EDI
PUSH EDI
DEC EDI
MOVZXB EAX,[EDI+0]
PUSH EAX
PUSHL OFFSET(SYSTEM.BlockWriteResult)
CALLN32 SYSTEM.BlockWrite
END;
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE CStrWriteText({VAR f:FILE}CONST s:CSTRING;format:LONGWORD);
VAR
ss:STRING;
l:LONGWORD;
fi:^FILE;
fillup:BYTE;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
l:=length(s);
IF Format+l>255 THEN Format:=255-l;
IF format>l THEN
BEGIN
fillup:=format-l;
fillchar(ss[0],fillup,32);
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,ss[0],fillup);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
{must do this in ASM because s is constant parameter}
ASM
PUSHL $fi
PUSHL $s
PUSHL $l
PUSHL OFFSET(SYSTEM.BlockWriteResult)
CALLN32 SYSTEM.BlockWrite
END;
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
{Float value is in ST(0) !}
PROCEDURE WriteExtendedText({VAR f:FILE}Format1,Format2:LONGWORD);
VAR
float:EXTENDED;
fi:^FILE;
s:STRING;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
FSTPT $float
PUSHL $Format1
PUSHL $Format2 //Nachkommas
LEA EAX,$float
PUSH EAX
LEA EAX,$s
PUSH EAX
CALLN32 SYSTEM.!Extended2Str
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,s[1],length(s));
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE WritelnText(VAR f:FILE);
VAR
w:WORD;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
{Write #13#10}
w:=$0a0d;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(f,w,2);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE WriteText(VAR f:FILE);
BEGIN
{do nothing here - just pop f}
END;
PROCEDURE FileWrite({VAR f:FILE)}VAR Buf;size:LONGWORD);
VAR
fi:^FILE;
fr:^FileRec;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
MOV $fr,EAX
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,Buf,size DIV fr^.RecSize);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE FileRead({VAR f:FILE}VAR Buf;size:LONGWORD);
VAR
fi:^FILE;
fr:^FileRec;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
MOV $fr,EAX
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(fi^,Buf,size DIV fr^.RecSize);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
FUNCTION SeekEoln(VAR F:Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
Offset:LONGINT;
Value:BYTE;
SaveIoError:BOOLEAN;
Res:LONGWORD;
t:BYTE;
s:STRING;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF eof(f) THEN
BEGIN
result:=TRUE;
exit;
END;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
Seek(f,FilePos(f)-1);
RaiseIOError:=SaveIOError;
IF Res=0 THEN Value:=26; {EOF}
END;
END
ELSE value:=fi^.Buffer^[Offset];
IF value IN [13,10,26] THEN result:=TRUE
ELSE
BEGIN
IF not (value IN [9,32]) THEN result:=FALSE
ELSE {must read the line}
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
Offset:=FilePos(f);
Readln(f,s);
Seek(f,Offset);
RaiseIOError:=SaveIOError;
result:=TRUE;
FOR t:=1 TO length(s) DO
IF not (s[t] IN [#9,#32]) THEN result:=FALSE;
END;
END;
END;
FUNCTION SeekEof(Var F :Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
OldFP:LONGWORD;
ch:Char;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
OldFP := FilePos(F);
WHILE not Eof(F) DO
BEGIN
Read(F,ch);
IF not (ch IN [#32,#9,#13,#10]) THEN break;
END;
Result := Eof(f);
Seek(F,OldFP);
END;
PROCEDURE TextRead({VAR f:TEXT;VAR Ziel;}VAR s:STRING;Typ,MaxLen:LONGWORD);
VAR
fi:^FileRec;
fi2:^TEXT;
Offset,Ende,t,Temp,Res,Res1:LONGWORD;
Count:WORD;
Value:BYTE;
SaveIoError:BOOLEAN;
Adr:LONGINT;
LABEL l,skip;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+24] //VAR f:TEXT
MOV $fi,EAX
MOV $fi2,EAX
END;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
IF eof(fi2^) THEN
BEGIN
(*IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
CASE Typ OF
1:s:=''; {String}
2:s:=chr(26); {Char}
3:s:=''; {Number}
ELSE s:='';
END; {case}
exit;
END;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Count:=0;
s:='';
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
l:
FOR t:=Offset TO Ende-1 DO
BEGIN
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
fi^.BufferBytes:=0;
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(fi2^,Value,1,Res);
RaiseIOError:=SaveIOError;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF Res=0 THEN Value:=26; {EOF}
fi^.BufferBytes:=1 OR (Value SHL 8);
END;
END
ELSE value:=fi^.Buffer^[t];
IF value=26 {EOF} THEN
BEGIN
{SaveIoError:=RaiseIoError;
RaiseIOError:=FALSE;
Seek(fi2^,FileSize(fi2^));
RaiseIOError:=SaveIoError;}
fi^.Reserved1:=fi^.Reserved1 OR 1; {mark EOF}
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
IF s='' THEN s:=#26;
inc(fi^.Offset);
fi^.BufferBytes:=0;
exit;
END;
CASE Typ OF
1: {String}
BEGIN
CASE value OF
13,10:
BEGIN
IF Count>255 THEN Count:=255;
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END; {case}
END;
2: {Char}
BEGIN
s[1]:=chr(Value);
s[0]:=#1;
IF fi^.Buffer<>NIL THEN inc(fi^.Offset)
ELSE fi^.BufferBytes:=0;
IF fi^.Offset=Ende THEN
BEGIN
IF Eof(fi2^) THEN exit;
{Ende erreicht --> erweitern}
IF fi^.Buffer=NIL THEN exit;
FileBlockIO(fi2^,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
exit;
END;
3: {Number}
BEGIN
CASE value OF
13,10,32,9:
BEGIN
IF Count=0 THEN goto skip; {skip preceding chars}
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END; {case}
END;
END; {case}
inc(Count);
IF Count<256 THEN IF Count<=MaxLen THEN s[Count]:=chr(value);
skip:
inc(fi^.Offset);
fi^.BufferBytes:=0;
IF Count>=MaxLen THEN
BEGIN
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END;
IF eof(fi2^) THEN
BEGIN
(*IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
{Ende erreicht --> erweitern}
IF fi^.Buffer<>NIL THEN
BEGIN
FileBlockIO(fi2^,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
IF eof(fi2^) THEN
BEGIN
IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
goto l;
END;
PROCEDURE TextReadLF(VAR f:TEXT);
VAR
fi:^FileRec;
Offset,Ende,t,Temp,Res:LONGWORD;
Value:BYTE;
Read13,Read10:BOOLEAN;
Adr:LONGINT;
SaveIO:BOOLEAN;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
IF Eof(f) THEN exit;
Offset:=fi^.Offset;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
Read13:=FALSE;
Read10:=FALSE;
l:
FOR t:=Offset TO Ende-1 DO
BEGIN
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
fi^.BufferBytes:=0;
END
ELSE
BEGIN
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF Res=0 THEN Value:=26; {EOF}
fi^.BufferBytes:=1 OR (Value SHL 8);
END;
END
ELSE value:=fi^.Buffer^[t];
CASE value OF
26: {EOF}
BEGIN
fi^.Reserved1:=fi^.Reserved1 OR 1; {mark EOF}
exit;
END;
13:
BEGIN
IF ((Read13)OR(Read10)) THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
Read13:=TRUE;
END;
10:
BEGIN
IF Read10 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
IF f=Input THEN IF Read13 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
Read10:=TRUE;
END;
ELSE
BEGIN
IF Read13 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
IF Read10 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
END;
END; {case}
inc(fi^.Offset);
fi^.BufferBytes:=0;
END;
IF Eof(f) THEN exit;
{Ende erreicht --> erweitern}
IF fi^.Buffer<>NIL THEN
BEGIN
FileBlockIO(f,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
IF eof(f) THEN exit;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
goto l;
END;
PROCEDURE ReadLnText(VAR source:TEXT);
BEGIN
TextReadLF(source);
END;
//TextScreen IO support
TYPE ProcVar=PROCEDURE;
PROCEDURE TScreenInOutClass.WriteStr(CONST s:STRING);
VAR
actual:LONGWORD;
by,by1:LONGWORD;
Handle:LONGWORD;
b:BYTE;
ff:^FileRec;
s1,s2:STRING;
y:LONGINT;
Fill:WORD;
LABEL l,l1;
BEGIN
ff:=@Output;
Handle:=ff^.Handle;
IF RedirectOut THEN goto l1;
s1:=s;
b:=Pos(#13#10,s1);
WHILE b<>0 DO
BEGIN
s2:=s1;
s1:=copy(s1,1,b-1);
WriteStr(s1);
s1:=#13#10;
ASM
LEA EAX,$actual
PUSH EAX //pcbActual
LEA EDI,$s1
MOVZXB EAX,[EDI]
PUSH EAX //cbWrite
INC EDI
PUSH EDI //pBuffer
PUSHL $Handle //FileHandle
MOV AL,4
CALLDLL DosCalls,282 //DosWrite
ADD ESP,16
END;
y:=VioWhereYProc;
IF y-1>Hi(WindMax) THEN
BEGIN
{Scroll window}
Fill:= 32 + WORD(TextAttr) SHL 8;
VioScrollUpProc(Hi(WindMin),Lo(WindMin),
Hi(WindMax),Lo(WindMax),
1,Fill,0);
dec(y);
END;
GotoXY(1,y-Hi(WindMin));
s1:=copy(s2,b+2,length(s2)-(b+1));
b:=Pos(#13#10,s1);
END;
IF length(s1)>(Lo(WindMax)-Lo(WindMin)-
(VioWhereXProc-lo(WindMin)))+1 THEN
BEGIN
by:=(Lo(WindMax)-Lo(WindMin)-(VioWhereXProc-lo(WindMin)))+2;
by1:=length(s1)-by;
l:
ASM
LEA EAX,$actual
PUSH EAX //pcbActual
LEA EDI,$s1
INC EDI
PUSHL $by //cbWrite
PUSH EDI //pBuffer
PUSHL $Handle //FileHandle
MOV AL,4
CALLDLL DosCalls,282 //DosWrite
ADD ESP,16
END;
s1:=copy(s1,by+1,length(s1)-by);
IF ((WindMin<>MaxWindMin)OR(WindMax<>MaxWindMax)) THEN WriteLF;
IF length(s1)>(Lo(WindMax)-Lo(WindMin)-(VioWhereXProc-lo(WindMin)))+1 THEN
BEGIN
by:=(Lo(WindMax)-Lo(WindMin)-(VioWhereXProc-lo(WindMin)))+2;
by1:=length(s1)-by;
goto l;
END;
ASM
LEA EAX,$actual
PUSH EAX //pcbActual
LEA EDI,$s1
INC EDI
PUSHL $by1 //cbWrite
PUSH EDI //pBuffer
PUSHL $Handle //FileHandle
MOV AL,4
CALLDLL DosCalls,282 //DosWrite
ADD ESP,16
END;
exit;
END;
l1:
ASM
LEA EAX,$actual
PUSH EAX //pcbActual
LEA EDI,$s1
MOVZXB EAX,[EDI]
PUSH EAX //cbWrite
INC EDI
PUSH EDI //pBuffer
PUSHL $Handle //FileHandle
MOV AL,4
CALLDLL DosCalls,282 //DosWrite
ADD ESP,16
END;
END;
PROCEDURE TScreenInOutClass.WriteCStr(CONST s:CSTRING);
VAR
c:STRING;
b:LONGWORD;
pc:^CSTRING;
LABEL l;
BEGIN
pc:=@s;
l:
b:=Length(pc^);
IF b<255 THEN
BEGIN
c:=pc^;
WriteStr(c);
END
ELSE
BEGIN
move(pc^,c[1],255);
c[0]:=#255;
inc(pc,255);
WriteStr(c);
goto l;
END;
END;
PROCEDURE TScreenInOutClass.WriteLF;
VAR y:BYTE;
Fill:WORD;
s:STRING[3];
actual:LONGWORD;
ff:^FileRec;
Handle:LONGWORD;
BEGIN
s:=#13#10;
ff:=@Output;
Handle:=ff^.Handle;
ASM
LEA EAX,$actual
PUSH EAX //pcbActual
LEA EDI,$s
MOVZXB EAX,[EDI]
PUSH EAX //cbWrite
INC EDI
PUSH EDI //pBuffer
PUSHL $Handle //FileHandle
MOV AL,4
CALLDLL DosCalls,282 //DosWrite
ADD ESP,16
END;
y:=VioWhereYProc;
IF y-1>Hi(WindMax) THEN
BEGIN
{Scroll window}
Fill:= 32 + WORD(TextAttr) SHL 8;
VioScrollUpProc(Hi(WindMin),Lo(WindMin),
Hi(WindMax),Lo(WindMax),
1,Fill,0);
dec(y);
END;
GOTOXY(1,y-Hi(WindMin));
END;
PROCEDURE TScreenInOutClass.ReadLF(VAR s:STRING);
TYPE
STRINGINBUF=RECORD
cb:WORD;
cchIn:WORD;
END;
VAR si:STRINGINBUF;
t:BYTE;
ff:^FileRec;
y:LONGINT;
Fill:WORD;
BEGIN
{si.cb:=255;
si.cchin:=0;
KbdStringInProc(s[1],si,0,0);
s[0]:=chr(si.cchIn);}
ASM
PUSHD OFFSET(SYSTEM.Input)
PUSHL 0
MOV EAX,$s
PUSH EAX
PUSHL 1
PUSHL 255
CALLN32 SYSTEM.TextRead
ADD ESP,8
PUSHD OFFSET(SYSTEM.Input)
CALLN32 SYSTEM.TextReadLF
END;
t:=Pos(#26,s);
IF t<>0 THEN
BEGIN
ff:=@Input;
ff^.Reserved1:=ff^.Reserved1 OR 1; {mark EOF}
s[0]:=chr(t-1);
END;
y:=VioWhereYProc;
IF y-1>Hi(WindMax) THEN
BEGIN
{Scroll window}
Fill:= 32 + WORD(TextAttr) SHL 8;
VioScrollUpProc(Hi(WindMin),Lo(WindMin),
Hi(WindMax),Lo(WindMax),
1,Fill,0);
dec(y);
END;
ScreenInOut.GotoXY(1,y-Hi(WindMin));
END;
PROCEDURE TScreenInOutClass.GotoXY(x,y:BYTE);
BEGIN
X:=X-1+Lo(WindMin);
Y:=Y-1+Hi(WindMin);
IF (X<=Lo(WindMax))and(Y<=Hi(WindMax)) THEN VioSetCurPosProc(Y,X,0);
END;
PROCEDURE TPMScreenInOutClass.Error;
VAR
cs:CSTRING;
cTitle:CSTRING;
BEGIN
ctitle:='Wrong linker target';
cs:='PM Linker mode does not support text screen IO.'+#13+
'Use the unit WinCrt if you wish to use text'+#13+
'screen IO inside PM applications.';
WinMessageBox(1,1,cs,ctitle,0,$4000 OR $0010);
Halt(0);
END;
PROCEDURE TPMScreenInOutClass.WriteStr(CONST s:STRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.WriteCStr(CONST s:CSTRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.WriteLF;
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.ReadLF(VAR s:STRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.GotoXY(x,y:BYTE);
BEGIN
Error;
END;
IMPORTS
FUNCTION DosLoadModule(pszName:CSTRING;cbName:LONGWORD;pszModname:CSTRING;
VAR phmod:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 318;
FUNCTION DosQueryProcAddr(hmod:LONGWORD;ordinal:LONGWORD;
VAR pszName:CSTRING;
VAR ppfn:ProcVar):LONGWORD;
APIENTRY; DOSCALLS index 321;
END;
TYPE
VIOMODEINFO=RECORD {pack 1}
cb:WORD;
fbType:BYTE;
color:BYTE;
col:WORD;
row:WORD;
hres:WORD;
vres:WORD;
fmt_ID:BYTE;
attrib:BYTE;
buf_addr:LONGWORD;
buf_length:LONGWORD;
full_length:LONGWORD;
partial_length:LONGWORD;
ext_data_addr:POINTER;
END;
PROCEDURE InitScreenInOutPM;
VAR
c:TPMScreenInOutClass;
BEGIN
c.Create;
ScreenInOut:=TScreenInOutClass(c);
END;
PROCEDURE InitScreenInOut;
VAR VioModule:LONGWORD;
s:CSTRING;
VioMode:VioModeInfo;
Size,Value:WORD;
LABEL l;
BEGIN
ScreenInOut.Create;
IF DosLoadModule(s,255,'KBDVIO32',VioModule)<>0 THEN
BEGIN
l:
{ScreenInOut.WriteStr('RunError 217');}
RunError(217); {could not load KBDVIO32}
END;
IF DosQueryProcAddr(VioModule,40,NIL,ProcVar(VioScrollDnProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,41,NIL,ProcVar(VioScrollUpProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,33,NIL,ProcVar(VioGetModeProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,34,NIL,ProcVar(VioSetModeProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,3,NIL,ProcVar(VioWhereXProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,4,NIL,ProcVar(VioWhereYProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,30,NIL,ProcVar(VioSetCurPosProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,36,NIL,ProcVar(VioReadCellStrProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,64,NIL,ProcVar(VioGetConfigProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,9,NIL,ProcVar(KbdStringInProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,1,NIL,ProcVar(ReadKeyProc))<>0 THEN goto l;
IF DosQueryProcAddr(VioModule,2,NIL,ProcVar(KeyPressedProc))<>0 THEN goto l;
VioMode.cb := SizeOf(VioModeInfo);
VioGetModeProc(VioMode, 0);
WITH VioMode DO
BEGIN
IF Col = 40 THEN LastMode := BW40
ELSE LastMode := BW80;
IF (fbType AND 4) = 0 THEN
IF LastMode = BW40 THEN LastMode := CO40
ELSE LastMode := CO80;
IF Color = 0 THEN LastMode := Mono;
IF Row > 25 THEN Inc(LastMode,Font8x8);
END;
WindMin := 0;
WindMax := VioMode.Col - 1 + (VioMode.Row - 1) SHL 8;
MaxWindMin :=WindMin;
MaxWindMax :=WindMax;
Size := 2;
VioReadCellStrProc(Value, Size, VioWhereYProc-1, VioWhereXProc-1, 0);
TextAttr := Hi(Value) AND $7F;
END;
PROCEDURE StrWrite(CONST s:STRING;format:LONGWORD);
VAR ss:STRING;
p:^STRING;
BEGIN
IF Format+Length(s)>255 THEN Format:=255-length(s);
IF format>length(s) THEN
BEGIN
format:=format-length(s);
ss[0]:=chr(format+length(s));
fillchar(ss[1],format,32);
p:=@s;
move(p^[1],ss[format+1],length(s));
ScreenInOut.WriteStr(ss);
END
ELSE ScreenInOut.WriteStr(s);
END;
PROCEDURE CStrWrite(CONST s:CSTRING;format:LONGWORD);
VAR ss:CSTRING;
p:^CSTRING;
l:LONGWORD;
BEGIN
l:=length(s);
IF ((format>l)AND(l+format<255)) THEN
BEGIN
format:=format-l;
fillchar(ss[0],format,32);
p:=@s;
move(p^[0],ss[format],l+1);
ScreenInOut.WriteCStr(ss);
END
ELSE ScreenInOut.WriteCStr(s);
END;
PROCEDURE WriteLine;
BEGIN
ScreenInOut.WriteLF;
END;
PROCEDURE ReadLine;
VAR
s:STRING;
BEGIN
ScreenInOut.ReadLF(s);
END;
PROCEDURE StrRead(VAR s:STRING);
BEGIN
ScreenInOut.ReadLF(s);
END;
CONST
Typ_String = 1;
Typ_Char = 2;
Typ_Number = 3;
PROCEDURE GetNextStr(VAR s,Ziel:STRING;Typ:LONGWORD);
VAR t:BYTE;
LABEL l;
BEGIN
IF s='' THEN
BEGIN
StrRead(s);
s:=s+#13#10;
END;
Ziel:='';
CASE Typ OF
Typ_String:
BEGIN
{copy whole}
IF s=#13#10 THEN Ziel:=''
ELSE
BEGIN
Ziel:=Copy(s,1,length(s)-2);
s:=#13#10;
END;
END;
Typ_Char:
BEGIN
Ziel:=s[1];
Delete(s,1,1);
END;
Typ_Number:
BEGIN
l:
IF length(s)<3 THEN {am Zeilenende ??}
BEGIN
StrRead(s);
s:=s+#13#10;
END;
{Skip spaces}
IF s[1]=#32 THEN
BEGIN
Delete(s,1,1);
goto l;
END;
FOR t:=1 TO length(s) DO
BEGIN
CASE s[t] OF
#9,#13,#10,#32: {Trennzeichen}
BEGIN
Ziel:=Copy(s,1,t-1);
Delete(s,1,t-1); {Trenner nicht mit löschen}
exit;
END;
END; {case}
END;
END;
END; {case}
END;
//************************************************************************
// CLASS support
//************************************************************************
{Constructor for all classes}
CONSTRUCTOR TObject.Create;
BEGIN
InitInstance(POINTER(SELF));
END;
{Destructor for all classes}
DESTRUCTOR TObject.Destroy;
BEGIN
END;
{Frees an instance of a class}
PROCEDURE TObject.Free;
BEGIN
IF POINTER(SELF)<>NIL THEN Self.Destroy;
END;
{frees an Instance of a class}
PROCEDURE TObject.FreeInstance;
BEGIN
{FreeInstance is normally called by the Destructor to
deallocate memory for the object. In Speed-Pascal the
memory deallocation is done by the compiler thus
overriding this method has no effect}
END;
{Gets class information from the ClassInfo structure}
CLASS FUNCTION TObject.GetClassInfo: Pointer;
BEGIN
ASM
MOV EAX,$!ClassInfo
MOV EAX,[EAX+4]
MOV $!FUNCRESULT,EAX
END;
END;
{Returns size of an instance of a class of TObject or a class derived
from TObject from the ClassInfo structure}
CLASS FUNCTION TObject.InstanceSize:LONGWORD;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !InstanceSize_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !InstanceSize_NoInfo
MOV EAX,[EDI+0] //Get class size
!InstanceSize_NoInfo:
MOV $!FUNCRESULT,EAX
END;
END;
{Generates a new instance of a class from the ClassInfo structure
and calls the constructor for that class}
CLASS FUNCTION TObject.NewInstance: TObject;
BEGIN
{NewInstance is normally called by the Constructor to
allocate memory for the object. In Speed-Pascal the
memory allocation is done by the compiler thus
overriding this method has no effect}
END;
{Initializes an Instance from the ClassInfo structure given by Instance}
CLASS FUNCTION TObject.InitInstance(Instance: Pointer): TObject;
BEGIN
{Fill the object with zeros. Object must be initialized with Create !}
inc(Instance,4);
FillChar(Instance^,InstanceSize-4,0);
dec(Instance,4);
InitInstance:=TObject(Instance);
END;
CLASS FUNCTION TObject.ClassName: STRING;
VAR ps:^STRING;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !ClassName_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !ClassName_NoInfo
LEA EDI,[EDI+16] //points to class name
MOV EAX,EDI
!ClassName_NoInfo:
MOV $ps,EAX
END;
IF ps<>NIL THEN ClassName:=ps^
ELSE ClassName:='';
END;
CLASS FUNCTION TObject.ClassUnit:STRING;
VAR ps:^STRING;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !ClassUnit_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !ClassUnit_NoInfo
LEA EDI,[EDI+16] //points to class name
MOVZXB EAX,[EDI+0] //overreas class name
ADD EDI,EAX
INC EDI
MOV EAX,EDI
!ClassUnit_NoInfo:
MOV $ps,EAX
END;
IF ps<>NIL THEN ClassUnit:=ps^
ELSE ClassUnit:='';
END;
{Default handler for messages}
PROCEDURE TObject.DefaultHandler(VAR Message);
BEGIN
{Do nothing here !}
END;
{Default frame handler for messages}
PROCEDURE TObject.DefaultFrameHandler(VAR Message);
BEGIN
{Do nothing here !}
END;
{Dispatches dynamic methods}
PROCEDURE TObject.Dispatch(VAR Message);
BEGIN
{Check if there's a DMT entry for the message
The message ID MUST be the first DWORD of Message !!
If an entry is found call the message handler}
ASM
MOV EDI,$Message
MOV EAX,[EDI+0] //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch
!DLoop:
CMP [ESI+0],EAX
JNE !ELoop
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop:
ADD ESI,8 //Next DMT entry
LOOP !DLoop //try to find next
!EndeDispatch:
END; {case}
{other case call the Default handler}
DefaultHandler(Message);
END;
{Dispatches dynamic methods}
PROCEDURE TObject.DispatchCommand(VAR Message;Command:LONGWORD);
BEGIN
{Check if there's a DMT entry for the WM_COMMAND message}
ASM
MOV EDI,$Message
MOV EAX,$Command //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch_2
!DLoop_2:
CMP [ESI+0],EAX
JNE !ELoop_2
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop_2:
ADD ESI,8 //Next DMT entry
LOOP !DLoop_2 //try to find next
!EndeDispatch_2:
END; {case}
{other case call the Default handler}
DefaultHandler(Message);
END;
{Dispatches dynamic methods}
PROCEDURE TObject.FrameDispatch(VAR Message);
BEGIN
{Check if there's a DMT entry for the message
The message ID MUST be the first DWORD of Message !!
If an entry is found call the message handler}
ASM
MOV EDI,$Message
MOV EAX,[EDI+0] //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch_1
!DLoop_1:
CMP [ESI+0],EAX
JNE !ELoop_1
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop_1:
ADD ESI,8 //Next DMT entry
LOOP !DLoop_1 //try to find next
!EndeDispatch_1:
END; {case}
{other case call the Default handler}
DefaultFrameHandler(Message);
END;
ASSEMBLER
!GetMethodName PROC NEAR32
//INPUT : EAX adress to find
// EDI VMT pointer
//OUTPUT: String adress or NIL in EAX
MOV EDI,[EDI+4] //Get class info pointer
LEA EDI,[EDI+16] //points to class name
MOVZXB EBX,[EDI+0] //get Class name length
INC EDI
ADD EDI,EBX
MOVZXB EBX,[EDI+0] //get Unit name length
INC EDI
ADD EDI,EBX //points on first method adress
!MLoop:
CMPD [EDI+0],0 //end of list ??
JE !MELoop
CMP [EDI+0],EAX //Method found
JNE !MWLoop
//Method found
LEA EAX,[EDI+4] //points to Method name
JMP !MEFLoop
!MWLoop:
ADD EDI,4
MOVZXB EBX,[EDI+0] //get method name length
INC EDI
ADD EDI,EBX //points to next method address
JMP !MLoop //try next
!MELoop:
MOV EAX,0 //not found
!MEFLoop:
RETN32
!GetMethodName ENDP
END;
{returns the Method Name for an adress or an empty string}
CLASS FUNCTION TObject.MethodName(Address: POINTER): STRING;
VAR ps:^STRING;
Class_Info:POINTER;
BEGIN
ps:=NIL; {Default}
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV $Class_Info,EDI //get address to find
!MAgain:
MOV EDI,$Class_Info
MOV EAX,$Address
CALLN32 !GetMethodName //search for method
CMP EAX,0
JE !Nfound
//Method was found
MOV $ps,EAX
JMP !Mfound
!Nfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !MAgain //Try again if parents exist
!Mfound:
END;
IF ps=NIL THEN MethodName:=''
ELSE MethodName:=ps^;
END;
ASSEMBLER
!GetMethodAddress PROC NEAR32
//INPUT : ESI pointer to string to find
// EDI VMT pointer
//OUTPUT: method pointer or NIL in EAX
MOV EDI,[EDI+4] //Get class info pointer
LEA EDI,[EDI+16] //points to class name
MOVZXB EBX,[EDI+0] //get Class name length
INC EDI
ADD EDI,EBX
MOVZXB EBX,[EDI+0] //get Unit name length
INC EDI
ADD EDI,EBX //points on first method adress
MOV CL,[ESI+0] //get method string length
!ALoop:
MOV EDX,EDI //save pointer
MOV EBX,ESI //save pointer
CMPD [EDI+0],0 //end of list ??
JE !AELoop
ADD EDI,4 //onto name
CMP CL,[EDI+0] //length correct
JNE !AWLoop
//length was correct
MOVZX ECX,CL //String length
INC EDI
INC ESI
CLD
REP
CMPSB //Compare strings
JNE !AWLoop
//Method was found
MOV EAX,[EDX+0] //get method adress
JMP !AEFLoop
!AWLoop:
MOV EDI,EDX //get old pointer
MOV ESI,EBX //get old pointer
ADD EDI,4
MOVZXB EAX,[EDI+0] //get method name length
INC EDI
ADD EDI,EAX //points to next method address
MOV CL,[ESI+0]
JMP !ALoop //try next
!AELoop:
MOV EAX,0 //not found
!AEFLoop:
RETN32
!GetMethodAddress ENDP
END;
{returns the adress of a method or NIL}
CLASS FUNCTION TObject.MethodAddress(CONST Name: STRING): POINTER;
VAR
Adr:POINTER;
Class_Info:POINTER;
BEGIN
Adr:=NIL; {Default}
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV $Class_Info,EDI //get address to find
!AAgain_1:
MOV EDI,$Class_Info
MOV ESI,$Name
CALLN32 !GetMethodAddress //search for method
CMP EAX,0
JE !ANfound
//Method was found
MOV $Adr,EAX
JMP !AMfound
!ANfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !AAgain_1 //Try again if parents exist
!AMfound:
END;
MethodAddress:=Adr;
END;
ASSEMBLER
!GetFieldOffset PROC NEAR32
//INPUT : ESI pointer to string to find
// EDI VMT pointer
//OUTPUT: field offset or 0 in EAX
MOV EDI,[EDI+8] //Field info start
MOV AL,[ESI+0] //get method string length
INC ESI
!FLoop:
MOV EDX,EDI //save pointer
MOV EBX,ESI //save pointer
CMPD [EDI+0],0 //end of list ??
JE !FELoop
CMP AL,[EDI+4] //length correct
JNE !FWLoop
//length was correct
MOVZX ECX,AL //String length
ADD EDI,5 //onto first char
CLD
REP
CMPSB //Compare strings
JNE !FWLoop
//Method was found
MOV EAX,[EDX+0] //get method adress
JMP !FEFLoop
!FWLoop:
MOV EDI,EDX //get old pointer
MOV ESI,EBX //get old pointer
ADD EDI,4
MOVZXB EBX,[EDI+0] //get method name length
INC EDI
ADD EDI,EBX //points to next method address
JMP !FLoop //try next
!FELoop:
MOV EAX,0 //not found
!FEFLoop:
RETN32
!GetFieldOffset ENDP
END;
FUNCTION TObject.FieldAddress(Name: STRING): POINTER;
VAR
Adr:POINTER;
Class_Info:POINTER;
BEGIN
Adr:=NIL; {Default}
UpcaseStr(Name);
ASM
MOV EDI,$SELF //get object pointer
MOV EDI,[EDI+0] //get VMT Pointer
MOV EDI,[EDI+4] //get Class info pointer
MOV $Class_Info,EDI //get address to find
!FAgain:
MOV EDI,$Class_Info
LEA ESI,$Name
CALLN32 !GetFieldOffset //search for method
CMP EAX,0
JE !FNfound
//Method was found
MOV EBX,$SELF
MOV $Adr,EBX
ADD $Adr,EAX
JMP !FMfound
!FNfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !FMfound //not found
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !FAgain //Try again if parents exist
!FMfound:
END;
FieldAddress:=Adr;
END;
{returns type of a class}
CLASS FUNCTION TObject.ClassType: TClass;
BEGIN
ASM
MOV EAX,$!ClassInfo
MOV $!FUNCRESULT,EAX
END;
END;
{Returns Parent Class pointer of the Object or NIL}
CLASS FUNCTION TObject.ClassParent: TClass;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //get Class info pointer
CMP EDI,0
JE !ClassParent_NoInfo
MOV EDI,[EDI+4] //points to Class information
CMP EDI,0
JE !ClassParent_NoInfo
MOV EAX,[EDI+4] //Get Parent Class pointer
!ClassParent_NoInfo:
MOV $!FUNCRESULT,EAX
END;
END;
{returns true if the Class is derived from AClass, otherwise FALSE}
CLASS FUNCTION TObject.InheritsFrom(AClass: TClass): BOOLEAN;
BEGIN
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV EAX,$AClass //class to check
MOVD $!FUNCRESULT,0 //Default
!ILoop:
CMP EDI,EAX //is it this class ?
JNE !IWLoop
//The Class was found
MOVD $!FUNCRESULT,1
JMP !IELoop
!IWLoop:
//try parent class
MOV EDI,[EDI+4] //points to class info
MOV EDI,[EDI+4] //get parent info
CMP EDI,0
JNE !ILoop
!IELoop:
END;
END;
{internally: returns true if the Class1 is derived from Class2 otherwise FALSE}
FUNCTION CheckDerived(Class1,Class2: TClass): BOOLEAN;
BEGIN
ASM
MOV EDI,$Class1 //get Class info pointer
MOV EAX,$Class2 //class to check
MOVD $!FUNCRESULT,0 //Default
!ILoop11:
CMP EDI,EAX //is it this class ?
JNE !IWLoop11
//The Class was found
MOVD $!FUNCRESULT,1
JMP !IELoop11
!IWLoop11:
//try parent class
MOV EDI,[EDI+4] //points to class info
MOV EDI,[EDI+4] //get parent info
CMP EDI,0
JNE !ILoop11
!IELoop11:
END;
END;
ASSEMBLER
//Abstract method (causes Runtime Error 210)
SYSTEM.!Abstract PROC NEAR32
PUSHL 210
CALLN32 SYSTEM.RunError
SYSTEM.!Abstract ENDP
END;
//************************************************************************
// LongJmp support
//************************************************************************
FUNCTION SetJmp(VAR JmpBuf:Jmp_Buf):LONGWORD;
BEGIN
ASM
MOV EDI,$JmpBuf
MOV EAX,[EBP+0]
MOV [EDI+0],EAX
MOV EAX,[EBP+4]
MOV [EDI+4],EAX
MOV EAX,EBP
ADD EAX,12
MOV [EDI+8],EAX
MOV ESI,0
db $64 //SEG FS
MOV EAX,[ESI+0]
MOV [EDI+$18],EAX
FSTCW [EDI+$1C]
XOR EAX,EAX
MOV $!FUNCRESULT,EAX
END;
END;
PROCEDURE LongJmp(VAR JmpBuf:Jmp_Buf;RetVal:LONGWORD);
BEGIN
ASM
MOV EDI,$JmpBuf
PUSHL 0
MOV EAX,*ljmpret
PUSH EAX
PUSHL [EDI+$18]
MOV AL,3
CALLDLL DosCalls,357 //DosUnwindException
ljmpret:
MOV EDI,$JmpBuf
db $db,$e3 //FINIT Init FPU
FWAIT
FLDCW [EDI+$1C]
MOV EAX,$RetVal
AND EAX,EAX
JNZ !rtv0
MOV EAX,1
!rtv0:
PUSHL [EDI+0]
POP EBP
MOV ESP,[EDI+8]
ADD EDI,4
db $0ff,$27 //JMP NEAR32 [EDI+0] --> jump into proc
END;
END;
//***************************************************
// String Support routines
//***************************************************
PROCEDURE UpcaseStr(VAR s:STRING);
BEGIN
ASM
MOV EDI,$s
XOR ECX,ECX
MOV CL,[EDI+0]
OR CL,CL
JE !usend
INC EDI
MOV EBX,*ustab
CLD
!usfilter:
MOV AL,[EDI+0]
XLAT
STOSB
DEC ECX
JNZ !usfilter
!usend:
LEAVE
RETN32 4
ustab:
db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
db 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38
db 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57
db 58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76
db 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96
db 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83
db 84,85,86,87,88,89,90
db 123,124,125,126,127,128,129,130,131,132,133,134,135,136,137
db 138,139,140,141,142,143,144,145,146,147,148,149,150,151,152
db 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167
db 168,169,170,171,172,173,174,175,176,177,178,179,180,181,182
db 183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198
db 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213
db 214,215,216,217,218,219,220,221,222,223,224,225,226,227,228
db 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244
db 245,246,247,248,249,250,251,252,253,254,255
END;
END;
PROCEDURE LongWord2Str(l:LONGWORD;Format:LONGWORD;VAR result:STRING);
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EAX,$l
MOV EBX,10
XOR ECX,ECX
Lw46_1nn:
XOR EDX,EDX
DIV EBX
PUSH DX
INC CX
OR EAX,EAX
JNE Lw46_1nn
MOV ESI,$RESULT
MOVB [ESI+0],0
MOV EDI,ESI
CMP ECX,$Format
JAE Lw47nn
//format the string
MOV EAX,$Format
SUB EAX,ECX
MOV [ESI+0],AL
INC EDI
PUSH ECX
MOV ECX,EAX
MOV AL,32
CLD
REP STOSB //fill up with space
DEC EDI
POP ECX
Lw47nn:
POP AX
ADD AL,48
INCB [ESI+0]
INC EDI
MOV [EDI+0],AL
LOOP Lw47nn
END;
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION GetBoolValue(b:BOOLEAN):STRING;
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
IF b THEN GetBoolValue:='TRUE'
ELSE GetBoolValue:='FALSE';
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
PROCEDURE LongInt2Str(l:LONGINT;Format:LONGWORD;VAR result:STRING);
VAR
IsNeg:BOOLEAN;
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOVB $IsNeg,0
MOV EAX,$l
MOV EBX,10
XOR ECX,ECX
CMP EAX,0
JNL Lw46_1
NEG EAX
MOVB $IsNeg,1
Lw46_1:
XOR EDX,EDX
DIV EBX
PUSH DX
INC CX
OR EAX,EAX
JNE Lw46_1
MOV ESI,$RESULT
MOVB [ESI+0],0
MOV EDI,ESI
MOV EBX,ECX
CMPB $IsNeg,1
JNE !nin1
INC EBX
!nin1:
CMP EBX,$Format
JAE Lw47_1n
//format the string
MOV EAX,$Format
SUB EAX,EBX
MOV [ESI+0],AL
INC EDI
PUSH ECX
MOV ECX,EAX
MOV AL,32
CLD
REP STOSB //fill up with space
DEC EDI
POP ECX
Lw47_1n:
CMPB $IsNeg,1
JNE Lw47
INC EDI
INCB [ESI+0]
MOVB [EDI+0],45 //'-'
Lw47:
POP AX
ADD AL,48
INCB [ESI+0]
INC EDI
MOV [EDI+0],AL
LOOP Lw47
END;
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION POS(CONST item,source:STRING):BYTE;
VAR
result:BYTE;
BEGIN
ASM
MOV ESI,$item //item
CLD
LODSB
OR AL,AL
JE lab2
MOVZX EAX,AL
MOV EDX,EAX
MOV EDI,$source //source
MOVZXB ECX,[EDI+0]
SUB ECX,EDX
JB lab2
INC ECX
INC EDI
lab1:
LODSB
REPNE
SCASB
JNE lab2
MOV EAX,EDI
MOV EBX,ECX
MOV ECX,EDX
DEC ECX
REPE
CMPSB
JE lab3
MOV EDI,EAX
MOV ECX,EBX
MOV ESI,$item //item
INC ESI
JMP lab1
Lab2:
XOR EAX,EAX
JMP Lab4
lab3:
DEC EAX
SUB EAX,$source //source
Lab4:
MOV $result,AL
END;
POS:=result;
END;
FUNCTION Copy(CONST Source:STRING; Index,Count:INTEGER):STRING;
BEGIN
ASM
MOV ESI,$source //Source string
MOV EDI,$!FuncResult //Destination string
MOVW [EDI+0],0 //Empty String
MOVSXW ECX,$Count //Count
CMP ECX,1
JL !_CopyE
MOVSXW EAX,$Index //Index
CMP EAX,1
JNL !_Copy1
MOV EAX,1 //Index:=1
!_Copy1:
MOVZXB EBX,[ESI+0] //Length of Source
CMP EAX,EBX
JA !_CopyE
MOV EDX,EAX
ADD EDX,ECX //Index+Count
CMP EDX,EBX
JNA !_Copy2
MOV ECX,EBX
SUB ECX,EAX
INC ECX //Count := Length(S)-Index+1
!_Copy2:
MOV [EDI+0],CL
INC EDI
ADD ESI,EAX //first char
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!_CopyE:
END;
END;
FUNCTION ToHex(l:LONGWORD):STRING;
VAR
HexNum:STRING;
result:STRING;
r:LONGWORD;
BEGIN
HexNum:='0123456789ABCDEF';
result:='';
WHILE l>=16 DO
BEGIN
r:=l MOD 16;
l:=l DIV 16;
result:=HexNum[r+1]+result;
END;
result:=HexNum[l+1]+result;
WHILE length(result)<8 DO result:='0'+result;
ToHex:='$'+Result;
END;
PROCEDURE SUBSTR(VAR source:STRING;start,ende:Byte);
BEGIN
ASM
CLD
MOV ESI,$source //Source string
MOV EDI,ESI //Destination string
MOVZXB AX,[ESI+0] //Length of source
MOVZXB ECX,$Start //Index
OR ECX,ECX
JG !_Lab1_1
MOV ECX,1
!_Lab1_1:
ADD ESI,ECX
SUB AX,CX
JB !_Lab3_1
INC AX
MOVZXB CX,$Ende //Count
OR CX,CX
JGE !_Lab2_1
XOR CX,CX
!_Lab2_1:
CMP AX,CX
JBE !_Lab4_1
MOV AX,CX
JMP !_Lab4_1
!_Lab3_1:
XOR AX,AX
!_Lab4_1:
CLD
STOSB
MOVZX ECX,AX
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
END;
END;
PROCEDURE Insert(CONST Source:STRING; VAR S:STRING; Index:INTEGER);
BEGIN
IF Length(Source) = 0 THEN exit;
IF Length(S) = 0 THEN
BEGIN
S := Source;
exit;
END;
IF Index < 1 THEN Index := 1;
IF Index > Length(S) THEN Index := Length(S)+1;
S := copy(S,1,Index-1) + Source + copy(S,Index,Length(S)-Index+1);
END;
{$H+}
PROCEDURE Delete(VAR S:STRING; Index,Count:INTEGER);
BEGIN
IF Index < 1 THEN exit;
IF Index > Length(S) THEN exit;
IF Count < 1 THEN exit;
IF Index+Count > Length(S) THEN Count := Length(S)-Index+1;
S := copy(S,1,Index-1) + copy(S,Index+Count,Length(S)-Index-Count+1);
END;
FUNCTION ConvertStr2Long(VAR s:STRING):LONGINT;
VAR
c:Integer;
result:LONGINT;
BEGIN
VAL(s,result,c);
IF c<>0 THEN
BEGIN
END;
ConvertStr2Long:=result;
END;
{Liefert Extended in ST(0) !!}
PROCEDURE ConvertStr2Extended(VAR s:STRING);
VAR
c:Integer;
result:Extended;
BEGIN
VAL(s,result,c);
IF c<>0 THEN
BEGIN
END;
ASM
FLDT $result
END;
END;
FUNCTION GetStrErrorPos(VAR s:STRING):LONGINT;
VAR t,t1:BYTE;
BEGIN
result:=1;
t:=1;
IF t<=length(s) THEN IF s[t] IN ['+','-'] THEN inc(t);
IF t<=length(s) THEN IF s[t]='$' THEN inc(t);
FOR t1:=t TO length(s) DO
BEGIN
CASE s[t1] OF
'0'..'9':;
ELSE
BEGIN
result:=t1;
exit;
END;
END;
END;
END;
ASSEMBLER
SYSTEM.!Str2Long PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_11:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_11
CMP ECX,0
JE !do_11
DEC ECX
INC EDI
JMP !ndo_11 //skip spaces
!do_11:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_11_1
DEC ECX
POP EDI
JMP !do_11
!do_11_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !nohex
MOVD [EBP-10],16 //Base
CMP ECX,1
JE !qerr
DEC ECX
!nohex:
CMP AL,'-'
JNE !q2
CMP ECX,1
JE !qerr
DEC ECX
MOVB [EBP-6],1
!q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !qerr
CMP AL,57
JNA !noqerr
CMP AL,102
JA !qerr
CMP AL,65
JB !qerr
CMP AL,70
JBE !hexnum
CMP AL,97
JB !qerr
SUB AL,32 //To upper
!hexnum:
CMPD [EBP-10],16
JNE !qerr
SUB AL,7
!noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !q1
!qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !q3
!qqqq:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !q3
NEG EAX
!q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],EAX
LEAVE
RETN32 12
SYSTEM.!Str2Long ENDP
SYSTEM.!Str2Word PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_22:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_22
CMP ECX,0
JE !do_22
DEC ECX
INC EDI
JMP !ndo_22
!do_22:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_22_1
DEC ECX
POP EDI
JMP !do_22
!do_22_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !__nohex
MOVD [EBP-10],16 //Base
CMP ECX,1
JE !__qerr
DEC ECX
!__nohex:
CMP AL,'-'
JNE !__q2
CMP ECX,1
JE !__qerr
DEC ECX
MOVB [EBP-6],1
!__q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!__q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !__qerr
CMP AL,57
JNA !__noqerr
CMP AL,102
JA !__qerr
CMP AL,65
JB !__qerr
CMP AL,70
JBE !__hexnum
CMP AL,97
JB !__qerr
SUB AL,32 //To upper
!__hexnum:
CMPD [EBP-10],16
JNE !__qerr
SUB AL,7
!__noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !__q1
!__qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq1 //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !__q3
!qqqq1:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !__q3
NEG EAX
!__q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],AX
LEAVE
RETN32 12
SYSTEM.!Str2Word ENDP
SYSTEM.!Str2Byte PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_33:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_33
CMP ECX,0
JE !do_33
DEC ECX
INC EDI
JMP !ndo_33
!do_33:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_33_1
DEC ECX
POP EDI
JMP !do_33
!do_33_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !___nohex
CMP ECX,1
JE !___qerr
MOVD [EBP-10],16 //Base
DEC ECX
!___nohex:
CMP AL,'-'
JNE !___q2
CMP ECX,1
JE !___qerr
DEC ECX
MOVB [EBP-6],1
!___q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!___q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !___qerr
CMP AL,57
JNA !___noqerr
CMP AL,102
JA !___qerr
CMP AL,65
JB !___qerr
CMP AL,70
JBE !___hexnum
CMP AL,97
JB !___qerr
SUB AL,32 //To upper
!___hexnum:
CMPD [EBP-10],16
JNE !___qerr
SUB AL,7
!___noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !___q1
!___qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq2 //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !___q3
!qqqq2:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !___q3
NEG EAX
!___q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],AL
LEAVE
RETN32 12
SYSTEM.!Str2Byte ENDP
END;
ASSEMBLER
SYSTEM.!AssignStr2Array PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //Destination Array
MOV ESI,[EBP+12] //Source String
MOVZXB ECX,[ESI+0]
INC ESI
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!AssignStr2Array ENDP
SYSTEM.!AssignCStr2Array PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+12] //Source CString
MOV EDI,ESI
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EDI,[EBP+8] //Destination Array
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!AssignCStr2Array ENDP
SYSTEM.!StrCopy PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination String
MOV ESI,[EBP+16] //Source String
MOV ECX,[EBP+8] //Maximum length
LODSB
CMP AL,CL
JBE _L1
MOV AL,CL
_L1:
STOSB
MOVZX ECX,AL
MOV EAX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EAX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP ECX
POP EAX
LEAVE
RETN32 12
SYSTEM.!StrCopy ENDP
SYSTEM.!AssignStr2PChar PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination CString
MOV ESI,[EBP+16] //Source String
MOV ECX,[EBP+8] //Maximum length
LODSB //get length of source string
MOVZX EAX,AL
CMP EAX,ECX
JB _L1_1
MOV EAX,ECX
_L1_1:
MOV ECX,EAX
MOV EDX,EAX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0
STOSB //terminate PChar
POP ESI
POP EDI
POP EDX
POP ECX
POP EAX
LEAVE
RETN32 12
SYSTEM.!AssignStr2PChar ENDP
SYSTEM.!AssignPChar2Str PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+16] //Source CString
MOV EDX,[EBP+8] //Maximum length
MOV EDI,ESI //Source CString
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EAX,ECX //length of source string
DEC EAX //without #0
MOV EDI,[EBP+12] //Destination String
CMP EAX,EDX
JB _L1_2
MOV EAX,EDX //set to maximum length
_L1_2:
MOV ECX,EAX
STOSB //set string length
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 12
SYSTEM.!AssignPChar2Str ENDP
SYSTEM.!CopyArrayStr PROC NEAR32
CLD
MOV EBX,ESP
MOV EDI,[EBX+12] //Destination String
MOV ESI,[EBX+16] //Source Array
MOV ECX,[EBX+8] //Maximum string length
DEC ECX //minus length byte
MOV EAX,[EBX+4] //Array length
CMP AL,CL
JBE _L11
MOV AL,CL
_L11:
STOSB //String length
MOV CL,AL
MOVZX ECX,CL
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
RETN32 16
SYSTEM.!CopyArrayStr ENDP
SYSTEM.!PCharCopy PROC NEAR32
CLD
MOV EBX,ESP
MOV EDI,[EBX+12] //Source
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EDX,[EBX+4] //Maximum length
CMP EDX,ECX
JAE _re
MOV ECX,EDX
_re:
MOV ESI,[EBX+12] //Source
MOV EDI,[EBX+8] //Destination
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
RETN32 12
SYSTEM.!PCharCopy ENDP
SYSTEM.!PCharLength PROC NEAR32
MOV EBX,ESP
PUSH EBX
PUSH EDI
PUSH ECX
MOV EDI,[EBX+4] //Source
MOV ECX,$0FFFFFFFF
XOR AL,AL
CLD
REPNE
SCASB
NOT ECX
MOV EAX,ECX
DEC EAX //without #0
POP ECX
POP EDI
POP EBX
RETN32 4
SYSTEM.!PCharLength ENDP
SYSTEM.!StrAdd PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination
MOV ESI,[EBP+8] //String to add
MOVZXB ECX,[EDI+0] //length of destination
CLD
LODSB //length of string to add
ADD [EDI+0],AL
JNC _lll1
MOVB [EDI+0],255
MOV AL,CL
NOT AL
_lll1:
ADD EDI,ECX
INC EDI
MOV CL,AL
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StrAdd ENDP
SYSTEM.!PCharAdd PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
CLD
MOV ESI,[EBP+8] //String to add
MOV EDI,[EBP+8] //String to add
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string to add
DEC ECX //without #0
MOV EBX,ECX
MOV EDI,[EBP+12] //Destination
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of destination
DEC ECX //without #0
MOV EDI,[EBP+12] //Destination
ADD EDI,ECX //add length to destination
MOV ECX,EBX //length of string to add
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0
STOSB //terminate PChar
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharAdd ENDP
SYSTEM.!Str2PChar PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+8] //String to convert
MOV EDI,ESI
MOVZXB ECX,[ESI+0]
INC ESI
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0 //terminate PChar
STOSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 4
SYSTEM.!Str2PChar ENDP
SYSTEM.!PChar2Str PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //string to convert
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX //used to set len
MOV ESI,[EBP+8]
ADD ESI,ECX //to last character of source
DEC ESI
MOV EDI,ESI
INC EDI //destination is 1 up
STD //move the bytes 1 up
REP
MOVSB
MOV AL,DL //set string length
STOSB
CLD
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32
SYSTEM.!PChar2Str ENDP
SYSTEM.!StringCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
MOV ESI,[EBP+8]
LODSB
MOV AH,[EDI+0]
INC EDI
MOV CL,AL
CMP CL,AH
JBE _nl1
MOV CL,AH
_nl1:
OR CL,CL
JE _nl2
MOVZX ECX,CL
CLD
REP
CMPSB
JNE _nl3
_nl2:
CMP AL,AH
_nl3:
POP ESI
POP EDI
POP ECX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StringCmp ENDP
SYSTEM.!PCharCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8]
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12]
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX
MOV EDI,[EBP+12]
MOV ESI,[EBP+8]
CMP EBX,ECX
JNE _nl3_1
_nl1_1:
OR ECX,ECX
JE _nl2_1
CLD
REP
CMPSB
JNE _nl3_1
_nl2_1:
CMP EBX,EDX
_nl3_1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharCmp ENDP
SYSTEM.!StrPCharCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //PChar
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12] //Str
MOVZXB ECX,[EDI]
MOV EDX,ECX
MOV EDI,[EBP+12] //Str
INC EDI
MOV ESI,[EBP+8] //PChar
CMP EBX,ECX
JNE _nl3_1_r1
_nl1_1_r1:
OR ECX,ECX
JE _nl2_1_r1
CLD
REP
CMPSB
JNE _nl3_1_r1
_nl2_1_r1:
CMP EBX,EDX
_nl3_1_r1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StrPCharCmp ENDP
SYSTEM.!PCharStrCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //Str
MOVZXB ECX,[EDI]
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12] //PChar
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX
MOV EDI,[EBP+12] //PChar
MOV ESI,[EBP+8] //Str
INC ESI
CMP EBX,ECX
JNE _nl3_1_r2
_nl1_1_r2:
OR ECX,ECX
JE _nl2_1_r2
CLD
REP
CMPSB
JNE _nl3_1_r2
_nl2_1_r2:
CMP EBX,EDX
_nl3_1_r2:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharStrCmp ENDP
END;
//************************************************************************
// Error support functions
//************************************************************************
IMPORTS
FUNCTION DosExit(action,result:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 234;
END;
PROCEDURE ExitAll;
BEGIN
DosExit(1,ExitCode);
END;
PROCEDURE Halt(Code:LONGWORD);
VAR
cs:CSTRING;
cTitle:CSTRING;
BEGIN
ExitCode:=Code;
ASM
!exloop:
PUSHL *!raddr //Return adress for ExitProc
PUSHL SYSTEM.ExitProc //ExitProc on Stack
RETN32
!raddr:
JMP !exloop //until termination
END;
END;
PROCEDURE HaltIntern(Code:LONGWORD);
VAR
cs:CSTRING;
cTitle:CSTRING;
BEGIN
ExitCode:=Code;
IF ExitCode<>0 THEN
BEGIN
IF ApplicationType=1 THEN
BEGIN
cs:='Speed Pascal/2 Runtime error '+tostr(ExitCode);
cTitle:='Runtime error';
WinMessageBox(1,1,cs,ctitle,0,$4000 OR $0010);
END
ELSE Writeln('Speed Pascal/2 Runtime error ',ExitCode);
END;
ASM
!exloop_11:
PUSHL *!raddr_11 //Return adress for ExitProc
PUSHL SYSTEM.ExitProc //ExitProc on Stack
RETN32
!raddr_11:
JMP !exloop_11 //until termination
END;
END;
PROCEDURE RunError(Code:LONGWORD);
BEGIN
HaltIntern(Code);
END;
//************************************************************************
//
//
// Memory support management functions
//
//
//************************************************************************
IMPORTS
FUNCTION DosAllocMem(VAR ppb:POINTER;cb,flag:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 299;
FUNCTION DosFreeMem(pb:POINTER):LONGWORD;
APIENTRY; DOSCALLS index 304;
FUNCTION DosSubAllocMem(pbBase:POINTER;VAR ppb:POINTER;
cb:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 345;
FUNCTION DosSubFreeMem(pbBase:POINTER;pb:POINTER;
cb:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 346;
FUNCTION DosSubSetMem(pbBase:POINTER;flag,cb:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 344;
FUNCTION DosSubUnsetMem(pbBase:POINTER):LONGWORD;
APIENTRY; DOSCALLS index 347;
END;
CONST
PAG_READ =$00000001; { read access }
PAG_WRITE =$00000002; { write access }
PAG_COMMIT =$00000010; { commit storage }
DOSSUB_INIT =$01; { initialize pages }
DOSSUB_SPARSE_OBJ =$04; { handle commitment }
DC_SEM_SHARED =$01; { heap Semaphore flag }
PROCEDURE ErrorInvalidPointer(Adr:LONGINT);
VAR
e:EInvalidPointer;
BEGIN
e.Create('Invalid pointer operation (EInvalidPointer)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE ErrorOutOfMemory(Adr:LONGINT);
VAR
e:EOutOfMemory;
BEGIN
e.Create('Out of memory (EOutOfMemory)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE ErrorInvalidHeap(Adr:LONGINT);
VAR
e:EInvalidHeap;
BEGIN
e.Create('Heap corrupted or destroyed (EInvalidHeap)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE GetAPIMem(VAR p:POINTER;Size:LONGWORD);
VAR Adr:LONGINT;
BEGIN
IF DosAllocMem(p,Size,PAG_READ OR PAG_WRITE OR PAG_COMMIT)<>0 THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
PROCEDURE FreeAPIMem(p:POINTER;size:LONGWORD);
VAR Adr:LONGINT;
BEGIN
IF DosFreeMem(p)<>0 THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
PROCEDURE Mark(VAR p:POINTER);
BEGIN
END;
PROCEDURE Release(VAR p:POINTER);
BEGIN
END;
FUNCTION StdHeapError(size:LONGWORD):INTEGER;
BEGIN
StdHeapError:=0; {Raise Runtime error}
END;
IMPORTS
FUNCTION DosCreateMutexSem(pszName:CSTRING;VAR aphmtx:LONGWORD;flAttr:LONGWORD;
fState:LONGBOOL):LONGWORD;
APIENTRY; DOSCALLS index 331;
FUNCTION DosRequestMutexSem(ahmtx:LONGWORD;ulTimeout:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 334;
FUNCTION DosReleaseMutexSem(ahmtx:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 335;
END;
CONST HeapFlag=$524E544C;
VAR HeapMutex:LONGWORD;
type
PHeapList=^THeapList;
THeapList=RECORD
Flag:LONGWORD; {RNTM}
Size:LONGWORD;
LastLeak:PHeapList;
NextLeak:PHeapList;
END;
type
PHeapPages=^THeapPages;
THeapPages=ARRAY[0..2047] OF PHeapList; {Pointers to heap handles}
VAR LastHeapPage:PHeapList;
LastHeapPageAdr:PHeapList;
HeapStrategyBestFit:BOOLEAN;
PROCEDURE RequestHeapMutex;
BEGIN
{$IFDEF OS2}
DosRequestMutexSem(HeapMutex,-1);
{$ENDIF}
{$IFDEF Win95}
WaitForSingleObject(HeapMutex,$FFFFFFFF);
{$ENDIF}
END;
PROCEDURE ReleaseHeapMutex;
BEGIN
{$IFDEF Win95}
ReleaseMutex(HeapMutex);
{$ENDIF}
{$IFDEF OS2}
DosReleaseMutexSem(HeapMutex);
{$ENDIF}
END;
PROCEDURE HeapErrorIntern(Code:LONGINT;Adr:LONGWORD);
BEGIN
ReleaseHeapMutex; {!!}
CASE Code OF
1:
BEGIN
NewSystemHeap; {!!}
ErrorOutOfMemory(Adr);
Halt;
END;
2:
BEGIN
ErrorInvalidPointer(Adr);
Halt;
END;
3:
BEGIN
NewSystemHeap; {!!}
ErrorInvalidHeap(Adr);
Halt;
END;
ELSE
BEGIN
ErrorInvalidPointer(Adr);
Halt;
END;
END; {case}
END;
VAR MemPageSize:LONGWORD;
PROCEDURE AllocNewPage(Size:LONGWORD);ASSEMBLER;
VAR Adr:LONGWORD;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV ECX,$Size
MOV EBX,SYSTEM.MemPageSize
SUB EBX,40
CMP ECX,EBX //32730
JBE !AllocSizeOk
{ensure that we can write HeapList with at least 2 entries}
ADD ECX,32
!AllocSizeOk:
{round page up to multiple of 128K}
MOV EBX,SYSTEM.MemPageSize
SUB EBX,1
MOV EDX,$FFFFFFFF
SUB EDX,EBX
ADD ECX,EBX //32767
AND ECX,EDX //$FFFF8000
{Allocate Page}
MOV $Size,ECX
{IF DosAllocMem(LastHeapPage,size,PAG_READ OR PAG_WRITE OR PAG_COMMIT)<>0 THEN}
PUSHL $13 {PAG_READ OR PAG_WRITE OR PAG_COMMIT}
PUSH ECX
PUSHL OFFSET(SYSTEM.LastHeapPage)
MOV AL,3
CALLDLL DosCalls,299 {DosAllocMem}
ADD ESP,12
CMP EAX,0
JE !AllocNoError
PUSHL 1 {Out of memory error}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!AllocNoError:
MOV EDI,SYSTEM.HeapOrg
MOV ECX,2047
MOV EAX,0
CLD
REPNE
SCASD
CMP ECX,0
JNE !AllocPageFound
PUSHL 1 {Out of memory error}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!AllocPageFound:
SUB EDI,4
MOV EAX,SYSTEM.LastHeapPage {dummy^[t]:=LastHeapPage}
MOV [EDI],EAX
MOV SYSTEM.LastHeapPageAdr,EDI {LastHeapPageAdr:=@dummy^[t];}
{First leak node - never changed}
MOV EDI,SYSTEM.LastHeapPage
MOV ECX,$Size
MOV [EDI].THeapList.Size,ECX {LastHeapPage^.size:=Initial size;}
MOVD [EDI].THeapList.Flag,HeapFlag {LastHeapPage^.Flag:=HeapFlag;}
MOVD [EDI].THeapList.LastLeak,0 {LastHeapPage^.LastLeak:=NIL;}
MOV EAX,EDI
ADD EAX,16 {LastHeapPage^.NextLeak:=LastHeapPage+16;}
MOV [EDI].THeapList.NextLeak,EAX
{second leak node contains size of first leak (whole page-32 here}
{This ensures that we have at least 2 page entries free}
{EAX=LastHeapPage^.NextLeak}
SUB ECX,32 {LastHeapPage^.NextLeak^.size:=size-32;}
MOV [EAX].THeapList.size,ECX
MOV [EAX].THeapList.LastLeak,EDI {LastHeapPage^.NextLeak^.LastLeak:=LastHeapPage;}
MOVD [EAX].THeapList.NextLeak,0 {LastHeapPage^.NextLeak^.NextLeak:=NIL;}
MOVD [EAX].THeapList.Flag,HeapFlag {LastHeapPage^.NextLeak^.Flag:=HeapFlag;}
END;
PROCEDURE GetMem(VAR p:POINTER;size:LONGWORD);ASSEMBLER;
VAR OldEDI,OldECX,Adr:LONGWORD;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
CALLN32 SYSTEM.RequestHeapMutex
MOVD $OldEDI,0
{IF LastHeapPage=NIL THEN}
CMPD SYSTEM.LastHeapPage,0
JNE !GetMemLastPageSet
{Search for first page node allocated}
!GetMemScanMapStart:
MOV EDI,SYSTEM.HeapOrg
MOV ECX,2047
!GetMemScanMapAgain:
{Scan for first Page<>NIL}
MOV EAX,0
CLD
REPE
SCASD
CMP ECX,0
JNE !GetMemPageFound
{no previously allocated Page found --> new page}
MOVD $OldEDI,$FFFFFFFF {dont loop again to scan map}
MOV ECX,$Size
ADD ECX,4
PUSH ECX
CALLN32 SYSTEM.AllocNewPage
JMP !GetMemLastPageSet
!GetMemPageFound:
MOV $OldEDI,EDI
MOV $OldECX,ECX
{Calculate index for that item}
MOV EAX,EDI
SUB EAX,4
MOV SYSTEM.LastHeapPageAdr,EAX
MOV EAX,[EAX] {get pointer to start of page}
MOV SYSTEM.LastHeapPage,EAX
!GetMemLastPageSet:
{Try to find the memory in LastHeapPage}
MOV ECX,$Size
TEST ECX,ECX
JNE !GetMemSizeOk
MOV EDI,$p
MOVD [EDI],0
CALLN32 SYSTEM.ReleaseHeapMutex
LEAVE
RETN32 8
!GetMemSizeOk:
{Round up requested size to multiples of 16 and add 4 byte for page item}
ADD ECX,4
ADD ECX,15
AND ECX,$FFFFFFF0
MOV EDI,SYSTEM.LastHeapPage {dummy:=LastHeapPage;}
MOV ESI,EDI {Last:=LastHeapPage;}
MOV EBX,0 {Found:=NIL;}
MOV EDX,$FFFFFFFF {FoundLen:=$FFFFFFFF;}
JMP !GetMemLoop2
!GetMemLoop1:
MOV ESI,EDI {Last:=dummy}
MOV EDI,[EDI].THeapList.NextLeak {dummy:=dummy^.NextLeak}
!GetMemLoop2:
{WHILE dummy<>NIL DO}
TEST EDI,EDI
JE !GetMemLoopEnd
CMPD [EDI].THeapList.Flag,HeapFlag {IF dummy^.Flag<>HeapFlag}
JE !GetMemFlagOk
PUSHL 3 {HeapList Corrupted}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!GetMemFlagOk:
{dont use first entry (contains overall size of page}
CMP EDI,SYSTEM.LastHeapPage
JE !GetMemLoop1
{IF dummy^.Size>=len THEN}
CMP [EDI].THeapList.Size,ECX
JB !GetMemLoop1
{IF dummy^.Size<>Len THEN}
JNE !GetMemLenGreater
!GetMemFit:
{Requested memory fits the leak}
MOV EBX,EDI {Found:=dummy;}
MOV EDX,ECX {FoundLen:=dummy^.size;}
JMP !GetMemFoundOk
!GetMemLenGreater:
{If Heap strategy is not "Best Fit" - use the first leak}
CMPB SYSTEM.HeapStrategyBestFit,1 {Best fit ??}
JNE !GetMemFit
{IF dummy^.size<FoundLen THEN}
CMP [EDI].THeapList.Size,EDX
JA !GetMemLoop1
MOV EBX,EDI {Found:=dummy;}
MOV EDX,[EDI].THeapList.Size {FoundLen:=dummy^.Size;}
JMP !GetMemLoop1
!GetMemLoopEnd:
{IF Found=NIL THEN}
CMP EBX,0
JNE !GetMemFoundOk
{No leak found that fulfilles the request - try scan map again}
MOV EDI,$OldEDI
CMP EDI,$FFFFFFFF
JNE !GetMemScanMapPossible
PUSHL 1 {Out of Memory}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!GetMemScanMapPossible:
CMP EDI,0 {No previous scan}
JE !GetMemScanMapStart
MOV ECX,$OldECX
CMP ECX,0
JA !GetMemScanMapAgain
PUSHL 1 {Out of Memory}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!GetMemFoundOk:
{Leak found}
{IF Leak fits exactly use the next entry for NextLeak}
MOV EAX,[EBX].THeapList.Size
CMP EAX,ECX
JNE !LeakIsGreater
MOV ESI,[EBX].THeapList.NextLeak
{Dont use last leak - in extreme case the size of LastLeak is 0 !}
CMP ESI,0
JE !LeakIsGreater
{Leak fits exactly - delete leak and update leak list}
MOV EAX,[EBX].THeapList.LastLeak
MOV [EAX].THeapList.NextLeak,ESI
MOV [ESI].THeapList.LastLeak,EAX
JMP !GetMemEnd
!LeakIsGreater:
{Leak is greater - shrink the leak}
MOV ESI,EBX {Found^.LastLeak^.NextLeak:=Found+len;}
ADD ESI,ECX
MOV EAX,[EBX].THeapList.LastLeak
MOV [EAX].THeapList.NextLeak,ESI
{EBX=Found, ESI=Found^.NextLeak New, ECX=Len}
MOV EAX,[EBX].THeapList.Size {Found^.NextLeak New^.size:=Found^.size-Len;}
SUB EAX,ECX
MOV [ESI].THeapList.Size,EAX
MOV EAX,[EBX].THeapList.NextLeak {Found^.NextLeak New^.NextLeak:=Found^.NextLeak;}
MOV [ESI].THeapList.NextLeak,EAX
MOVD [ESI].THeapList.Flag,HeapFlag {Found^.NextLeak New^.Flag:=HeapFlag;}
MOV EAX,[EBX].THeapList.LastLeak {Found^.NextLeak New^.LastLeak:=Found^.LastLeak;}
MOV [ESI].THeapList.LastLeak,EAX
MOV EAX,[ESI].THeapList.NextLeak {Found^.NextLeak New^.NextLeak^.LastLeak:=Found;}
CMP EAX,0
JE !GetMemEnd
MOV [EAX].THeapList.LastLeak,ESI
!GetMemEnd:
{Set the page for which this item was allocated}
MOV EAX,SYSTEM.LastHeapPageAdr
MOV [EBX+0],EAX
ADD EBX,4
MOV EDI,$p {p:=Found}
MOV [EDI+0],EBX
PUSH EBX //for FillMem
CALLN32 SYSTEM.ReleaseHeapMutex
POP EDI //for FillMem
CMPB SYSTEM.FillMemoryWithZero,0
JE !DoNotFillMem
CLD
MOV ECX,$size
MOV EAX,0
MOV EDX,ECX
SHR ECX,2
REP
STOSD
MOV ECX,EDX
AND ECX,3
REP
STOSB
!DoNotFillMem:
LEAVE
RETN32 8
END;
PROCEDURE SAVEGETMEM(var pp:Pointer;size:LongWord);
BEGIN
ASM {!!}
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
GetMem(pp,size);
ASM {!!}
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
IMPORTS
FUNCTION DosAllocSharedMem(VAR ppb:POINTER;VAR pszName:CSTRING;
cb,flag:LONGWORD):LONGWORD;
APIENTRY; DOSCALLS index 300;
END;
PROCEDURE GETSHAREDMEM(var pp:Pointer;size:LongWord);
VAR Adr:LONGINT;
BEGIN
IF DosAllocSharedMem(pp,NIL,size,$313) <> 0 THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
PROCEDURE FREESHAREDMEM(p:pointer;size:LongWord);
BEGIN
DosFreeMem(p);
END;
PROCEDURE FreeMem(p:POINTER;size:LONGWORD);ASSEMBLER;
VAR Page:PHeapPages;
PageOrg:PHeapList;
Adr:LONGWORD;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
CALLN32 SYSTEM.RequestHeapMutex
MOV ECX,$Size
TEST ECX,ECX
JNE !FreeMemSizeOk
CALLN32 SYSTEM.ReleaseHeapMutex
LEAVE
RETN32 8
!FreeMemSizeOk:
MOV EDI,$p
JNE !FreeMemPointerOk
PUSHL 2 {Illegal pointer operation}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!FreeMemPointerOk:
SUB EDI,4
MOV EDI,[EDI]
MOV $Page,EDI {Page record pointer}
MOV EDI,[EDI] {Page Pointer}
MOV $PageOrg,EDI
ADD ECX,4
ADD ECX,15
AND ECX,$FFFFFFF0
{EDI=Page Pointer, ECX=Size}
MOV ESI,$p
MOV EDI,$PageOrg
SUB ESI,4
JMP !FreeMemStartLoop
!FreeMemLoop1:
MOV EDI,[EDI].THeapList.NextLeak
!FreeMemStartLoop:
TEST EDI,EDI
JNE !FreeMemPOk {invalid pointer operation}
PUSHL 2 {Illegal pointer operation}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!FreeMemPOk:
CMP EDI,ESI
JAE !FreeMemLabErr1
CMPD [EDI].THeapList.Flag,HeapFlag
JE !FreeMemLab1
PUSHL 3 {Heap corrupted}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!FreeMemLab1:
CMP [EDI].THeapList.NextLeak,ESI
JB !FreeMemLoop1
JMP !Proceed {entry found}
!FreeMemLabErr1:
PUSHL 2 {illegal pointer operation}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!Proceed:
{The memory is between dummy and dummy^.NextLeak}
{ESI=p-4, EDI=dummy (LastLeak), ECX=Len}
MOV EAX,ESI
ADD EAX,ECX
CMP EAX,[EDI].THeapList.NextLeak
JA !FreeMemLabErr1 {illegal pointer operation}
MOV EAX,EDI {EAX=LastLeak}
ADD EAX,16
{IF LastLeak<>PageOrg THEN Add Size}
CMP EDI,$PageOrg
JE !FreeMemIsPageOrg
SUB EAX,16 {Subtract 16 bytes because the size includes it}
ADD EAX,[EDI].THeapList.Size
!FreeMemIsPageOrg:
CMP ESI,EAX
JAE !LeakOk
PUSHL 2 {Illegal pointer operation}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!LeakOk:
{dummy=EDI, Len=ECX, ESI=p-4}
{erstes Loch erhalten !}
{IF ((dummy<>PageOrg)AND(dummy+dummy^.size=p)) THEN}
CMP EDI,$PageOrg
JE !FreeMemElseLab
MOV EAX,EDI
ADD EAX,[EDI].THeapList.size
CMP EAX,ESI
JNE !FreeMemElseLab
{Speicher grenzt an Vorgängerloch - verschmelzen}
MOV ESI,EDI {FreeP:=dummy;}
ADD [ESI].THeapList.size,ECX {inc(FreeP^.size,Len);}
JMP !FreeMemElseEnd
{ELSE}
!FreeMemElseLab:
{FreeP=ESI=p}
MOV [ESI].THeapList.Size,ECX {FreeP^.size:=len;}
MOV [ESI].THeapList.LastLeak,EDI {FreeP^.LastLeak:=dummy;}
MOV [ESI].THeapList.Flag,HeapFlag {FreeP^.Flag:=HeapFlag;}
MOV EDX,[EDI].THeapList.NextLeak {FreeP^.NextLeak:=dummy^.NextLeak;}
MOV [ESI].THeapList.NextLeak,EDX
MOV [EDI].THeapList.NextLeak,ESI {dummy^.NextLeak:=FreeP;}
MOV [EDX].THeapList.LastLeak,ESI {FreeP^.NextLeak^.LastLeak:=FreeP;}
!FreeMemElseEnd:
{IF FreeP+FreeP^.size>=FreeP^.NextLeak THEN}
MOV EAX,ESI
ADD EAX,[ESI].THeapList.Size
CMP EAX,[ESI].THeapList.NextLeak
JB !FreeMemDone
JE !LeaksAreOk
PUSHL 2 {Illegal pointer operation}
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!LeaksAreOk:
{Speicher grenzt an Nachfolgelock - verschmelzen}
MOV EDI,[ESI].THeapList.NextLeak {inc(FreeP^.size,FreeP^.NextLeak^.size);}
{EDI=FreeP^.NextLeak}
MOV EAX,[EDI].THeapList.Size
ADD [ESI].THeapList.Size,EAX
{Clear Flag of next leak}
MOVD [EDI].THeapList.Flag,0
MOV EAX,[EDI].THeapList.NextLeak {FreeP^.NextLeak:=FreeP^.NextLeak^.NextLeak;}
MOV [ESI].THeapList.NextLeak,EAX
CMP EAX,0 {FreeP^.NextLeak can be NIL !}
JE !FreeMemDone
MOV [EAX].THeapList.LastLeak,ESI {FreeP^.NextLeak^.LastLeak:=FreeP;}
!FreeMemDone:
{Check if this is the last entry and LastLeak=Page Pointer}
CMPD [ESI].THeapList.NextLeak,0 {IF FreeP^.NextLeak=NIL THEN}
JNE !FreeMemExit
MOV EBX,$PageOrg {Page Pointer}
CMP [ESI].THeapList.LastLeak,EBX {IF FreeP^.LastLeak=Start of Page THEN}
JNE !FreeMemExit
{ensure that last entry starts immediately after Page start}
{this ensures that no more memory is allocated bewteen these entries}
{IF FreeP=Start OF Page+16 THEN}
MOV EAX,EBX
ADD EAX,16
CMP ESI,EAX
JNE !FreeMemExit
{All storage was freed from the page > Free Page itself}
PUSH EBX
MOV AL,1
CALLDLL DosCalls,304 {DosFreeMem}
ADD ESP,4
CMP EAX,0
JE !DosFreeMemOk
PUSHL 2
PUSHL $Adr
CALLN32 SYSTEM.HeapErrorIntern
!DosFreeMemOk:
{dont use that page anymore}
MOV EDI,$Page
MOV ESI,$PageOrg
MOVD $Page,0
MOVD $PageOrg,0
{EDI=Page, ESI=PageOrg
{Clear the entry in the page table and clear LastHeapPage if not valid}
MOVD [EDI],0
{If this page was the active page - clear it}
{IF LastHeapPage=PageOrg THEN}
CMP SYSTEM.LastHeapPage,ESI
JNE !FreeMemExit1 {Leave LastHeapPage and LastHeapPageAddr as they are}
!FreeMemExit:
{Set LastHeapPage and LastHeapPageAdr to the current page}
MOV EAX,$PageOrg
MOV SYSTEM.LastHeapPage,EAX
MOV EAX,$Page
MOV SYSTEM.LastHeapPageAdr,EAX
!FreeMemExit1:
CALLN32 SYSTEM.ReleaseHeapMutex
LEAVE
RETN32 8
END;
PROCEDURE SAVEFREEMEM(pp:pointer;size:LongWord);
BEGIN
ASM {!!}
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
FreeMem(pp,size);
ASM {!!}
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION MaxAvail:LongWord;
VAR Page:PHeapPages;
dummy:PHeapList;
t,temp:LONGINT;
BEGIN
RequestHeapMutex;
{MaxAvail is APIAvail or biggest leak if greater}
result:=HeapSize;
Page:=HeapOrg;
temp:=0;
FOR t:=0 TO 2047 DO
BEGIN
dummy:=Page^[t];
{sub page size from MaxAvail}
IF dummy<>NIL THEN dec(result,dummy^.Size);
{don't use first entry since it contains page size}
IF dummy<>NIL THEN dummy:=dummy^.NextLeak;
WHILE dummy<>NIL DO
BEGIN
IF dummy^.size>temp THEN temp:=dummy^.size;
dummy:=dummy^.NextLeak;
END;
END;
IF temp>result THEN result:=temp;
ReleaseHeapMutex;
END;
FUNCTION MemAvail:LongWord;
VAR Page:PHeapPages;
dummy:PHeapList;
t:LONGINT;
BEGIN
RequestHeapMutex;
{MemAvail is APIAvail plus all free leaks}
result:=HeapSize;
Page:=HeapOrg;
FOR t:=0 TO 2047 DO
BEGIN
dummy:=Page^[t];
{Sub Page size from MemAvail}
IF dummy<>NIL THEN dec(result,dummy^.Size);
{don't use first entry since it contains page size}
IF dummy<>NIL THEN dummy:=dummy^.NextLeak;
WHILE dummy<>NIL DO
BEGIN
inc(result,dummy^.size);
dummy:=dummy^.NextLeak;
END;
END;
ReleaseHeapMutex;
END;
FUNCTION CreateSystemHeap(Size:LONGWORD):BOOLEAN;
VAR p:POINTER;
r:LONGWORD;
BEGIN
IF size>32768*2048 THEN size:=32768*2048; {can only handle 64MB}
{Allocate Heap Pages Record}
r:=DosAllocMem(HeapOrg,8192,PAG_READ OR PAG_WRITE OR PAG_COMMIT);
IF r=0 THEN
BEGIN
FillChar(HeapOrg^,8192,0);
HeapEnd:=HeapOrg;
HeapPtr:=HeapOrg;
LastHeapPage:=NIL;
LastHeapPageAdr:=NIL;
HeapSize:=Size;
END
ELSE
BEGIN
HeapOrg:=NIL;
HeapEnd:=NIL;
HeapPtr:=NIL;
LastHeapPage:=NIL;
LastHeapPageAdr:=NIL;
END;
result:=r=0;
END;
PROCEDURE DestroyHeap(Heap:POINTER);
VAR t:LONGINT;
dummy:PHeapPages;
Adr:LONGWORD;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
dummy:=Heap;
{Deallocate all allocated pages}
FOR t:=0 TO 2047 DO IF dummy^[t]<>NIL THEN
BEGIN
IF DosFreeMem(dummy^[t])<>0 THEN HeapErrorIntern(2,Adr);
END;
{Deallocate Heap pages record}
IF DosFreeMem(Heap)<>0 THEN HeapErrorIntern(2,Adr);
END;
PROCEDURE NewSystemHeap; {delete old system heap and create new one}
VAR OldSize:LONGWORD;
Adr:LONGWORD;
BEGIN
RequestHeapMutex;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
{Free old system heap and generate new}
OldSize:=HeapSize;
DestroySystemHeap;
IF not CreateSystemHeap(OldSize) THEN
BEGIN
ReleaseHeapMutex;
HeapErrorIntern(3,Adr);
END
ELSE ReleaseHeapMutex;
END;
PROCEDURE DestroySystemHeap;
BEGIN
DestroyHeap(HeapOrg);
HeapOrg:=NIL;
HeapPtr:=NIL;
HeapEnd:=NIL;
FreeList:=NIL;
HeapTop:=NIL;
LastHeapPage:=NIL;
LastHeapPageAdr:=NIL;
END;
//**************************************************************************
//
// Random support
//
//**************************************************************************}
CONST
Factor:WORD=$8405;
IMPORTS
FUNCTION DosGetDateTime(VAR pdt:DATETIME):LONGWORD;
APIENTRY; DOSCALLS index 230;
END;
PROCEDURE Randomize;
VAR
d:DateTime;
BEGIN
DosGetDateTime(d);
RandSeed:=(((d.Hour SHL 8)+d.Min) SHL 16)+
((d.Sec SHL 8)+d.Hundredths);
END;
PROCEDURE NextRandom;
BEGIN
ASM
MOV AX,SYSTEM.RandSeed
MOV BX,SYSTEM.RandSeed+2
MOV CX,AX
MULW SYSTEM.Factor
SHL CX,3
ADD CH,CL
ADD DX,CX
ADD DX,BX
SHL BX,2
ADD DX,BX
ADD DH,BL
MOV CL,5
SHL BX,CL
ADD DH,BL
ADD AX,1
ADC DX,0
MOV SYSTEM.RandSeed,AX
MOV SYSTEM.RandSeed+2,DX
END;
END;
FUNCTION RANDOM(value:word):word;
BEGIN
ASM
CALLN32 SYSTEM.NextRandom
MOV CX,DX
MOV BX,$value
MUL BX
MOV AX,CX
MOV CX,DX
MUL BX
ADD AX,CX
ADC DX,0
MOV AX,DX
MOV $!FUNCRESULT,AX
END;
END;
FUNCTION FloatRandom:EXTENDED;
BEGIN
result:=Random(8192)/8192;
END;
//************************************************************************
//
//
// Direct Memory access support
//
//
//************************************************************************
PROCEDURE Move(CONST source; VAR dest; size:LONGWORD);ASSEMBLER;
ASM
MOV ESI,$Source
MOV EDI,$Dest
MOV ECX,$Size
CMP ESI,EDI
JE !MoveEnd
JA !MoveForw
MOV EBX,ESI
ADD EBX,ECX
CMP EBX,EDI // test overlapping
JBE !MoveForw
STD
ADD ESI,ECX
DEC ESI
ADD EDI,ECX
DEC EDI
REP
MOVSB
CLD
JMP !MoveEnd
!MoveForw:
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!MoveEnd:
END;
PROCEDURE SaveMove(VAR source; VAR dest; size:LONGWORD);ASSEMBLER;
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,$Source
MOV EDI,$Dest
MOV ECX,$Size
CMP ESI,EDI
JE !MoveEnd_1
JA !MoveForw_1
MOV EBX,ESI
ADD EBX,ECX
CMP EBX,EDI // test overlapping
JBE !MoveForw_1
STD
ADD ESI,ECX
DEC ESI
ADD EDI,ECX
DEC EDI
REP
MOVSB
CLD
JMP !MoveEnd_1
!MoveForw_1:
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!MoveEnd_1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
PROCEDURE CompareMem(VAR Buf1,Buf2;Size:LONGWORD);
BEGIN
ASM
CLD
MOV ESI,$Buf1
MOV EDI,$Buf2
MOV ECX,$Size
CLD
REP
CMPSB
END;
END;
PROCEDURE FILLCHAR(VAR dest;size:LongWord;value:byte);ASSEMBLER;
ASM
CLD
//Note: Stack is dword aligned !
MOV EDI,$Dest //Destination pointer
MOV ECX,$Size //count
CMP ECX,0
JE !ex_fillc
MOV AL,$Value //Value
MOV AH,AL
PUSH AX
PUSH AX
POP EAX
MOV EDX,ECX
SHR ECX,2
REP
STOSD
MOV ECX,EDX
AND ECX,3
REP
STOSB
!ex_fillc:
END;
//Set Support
ASSEMBLER
SYSTEM.TestInSet32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Set (32 Byte)
MOV AX,[EBP+12] //Byte or char value
MOV BX,16
XOR EDX,EDX
DIV BX //Calculate Word position
SHL AX,1
MOVZX EAX,AX
ADD EDI,EAX
MOV AX,DX //Bit Position [0..15]
SHL AX,1
MOVZX EAX,AX
MOV EBX,*SetTab_11
ADD EBX,EAX
MOV AX,[EBX+0] //Bit value
MOV BX,[EDI+0] //Old Value
AND AX,BX
CMP AX,0
JE !tis1 //not found
MOV AX,0 //test successful
CMP AX,0
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
!tis1:
MOV AX,1 //item not found
CMP AX,0
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SetTab_11 dw 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768
SYSTEM.TestInSet32 ENDP
SYSTEM.SetAssign32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ECX,8
MOV EAX,0
CLD
REP
STOSD
MOV EDI,[EBP+8] //Ziel
MOV ECX,[EBP+12] //Parameter count
CMP CX,0
JE !NSAs //only clear set
MOVZX ECX,CX
LEA ESI,[EBP+16] //Points to first parameter
!plo:
PUSH ECX
MOV ECX,[ESI+0] //Get parameter repeat
CMP ECX,0
JG !rr4
JE !NSAs
MOVSX ECX,CX
INC ECX
SUB ECX,[ESI+4]
JLE !NSAs
!rr4:
MOV EAX,[ESI+4] //Get value of parameter
ADD ESI,8 //to next parameter for next loop
!plo_rep:
XOR AH,AH
PUSH AX //store parameter value
MOV BX,16
XOR EDX,EDX
DIV BX //Calculate Word position
SHL AX,1
MOVZX EAX,AX
ADD EDI,EAX
MOV AX,DX //Bit Position [0..15]
SHL AX,1
MOVZX EAX,AX
MOV EBX,*SetTab
ADD EBX,EAX
MOV AX,[EBX+0]
MOVZX EAX,AX
MOV BX,[EDI+0] //Old Value
OR AX,BX
MOV [EDI+0],AX //Store new value
MOV EDI,[EBP+8] //Ziel
POP AX //get parameter repeat
INC AX //next parameter if it is parameter..parameter
LOOP !plo_rep
POP ECX
LOOP !plo //until all parameters processed
!NSAs:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8 //Return to caller
SetTab dw 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768
SYSTEM.SetAssign32 ENDP
SYSTEM.SetOr32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ESI,[EBP+12]
MOV ECX,8
!SAndl_1:
MOV EAX,[ESI+0]
OR EAX,[EDI+0]
MOV [EDI+0],EAX
ADD ESI,4
ADD EDI,4
LOOP !SAndl_1
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.SetOr32 ENDP
SYSTEM.TempSetOr32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
CMP ECX,0
JE !EndSetOr
LEA ESI,[EBP+16] //First Parameter
!TSAl_1:
PUSHL [ESI+4] //Value
MOV EAX,[ESI+0] //repeat count
//CMP EAX,0
//JG !rr1
//JE !EndSetOr2 //Error
//MOVSX EAX,AX
//INC EAX
//SUB EAX,[ESI+4]
//JLE !EndSetOr2 //Error
!rr1:
PUSH EAX //repeat count
ADD ESI,8
LOOP !TSAl_1
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
PUSH ECX
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!EndSetOr2:
MOV EAX,[EBP-36] //Old ESP
MOV ESP,EAX
LEA EAX,[EBP-32]
PUSH EAX
MOV EAX,[EBP+8] //Ziel
PUSH EAX
CALLN32 SYSTEM.SetOr32
!EndSetOr:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetOr32 ENDP
SYSTEM.SetAnd32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ESI,[EBP+12]
MOV ECX,8
!SAndl:
MOV EAX,[ESI+0]
AND EAX,[EDI+0]
MOV [EDI+0],EAX
ADD ESI,4
ADD EDI,4
LOOP !SAndl
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.SetAnd32 ENDP
SYSTEM.TempSetAnd32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
CMP ECX,0
JNE !TSAW
MOV EDI,[EBP+8] //Ziel
MOV ECX,8
MOV EAX,0
CLD
REP
STOSD
JMP !TempSetAndE
!TSAW:
LEA ESI,[EBP+16] //First Parameter
!TSAl:
PUSHL [ESI+4] //value
MOV EAX,[ESI+0] //repeat count
//CMP EAX,0
//JG !rr2
//JE !TempSetAndE2 //Error
//MOVSX EAX,AX
//INC EAX
//SUB EAX,[ESI+4]
//JLE !TempSetAndE2 //Error
!rr2:
PUSH EAX //repeat count
ADD ESI,8
LOOP !TSAl
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
PUSH ECX
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!TempSetAndE2:
MOV EAX,[EBP-36] //old ESP
MOV ESP,EAX
LEA EAX,[EBP-32]
PUSH EAX
MOV EAX,[EBP+8] //Ziel
PUSH EAX
CALLN32 SYSTEM.SetAnd32
!TempSetAndE:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetAnd32 ENDP
SYSTEM.TempSetCompare32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV ECX,[EBP+12] //Count
LEA ESI,[EBP+16] //First Parameter
CMP ECX,0 //empty set
JNE !TCSAl_2
//test empty set
MOV EAX,0
MOV ECX,8
CLD
REPE
SCASD
CMP ECX,0
JMP !ex_comp
!TCSAl_2:
PUSHL [ESI+4] //Value
MOV EAX,[ESI+0]
//CMP EAX,0
//JG !rr3
//JE !ex_comp2 //Error
//MOVSX EAX,AX
//SUB EAX,[ESI+4]
//JLE !ex_comp2 //Error
!rr3:
PUSH EAX //Repeat count
ADD ESI,8
LOOP !TCSAl_2
PUSHL [EBP+12] //Count
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!ex_comp2:
MOV EAX,[EBP-36] //old ESP
MOV ESP,EAX
CLD
LEA ESI,[EBP-32]
MOV EDI,[EBP+8]
MOV ECX,32
CLD
REP
CMPSB
!ex_comp:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetCompare32 ENDP
SYSTEM.NegateSet32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8]
MOV ECX,8
!NS_l:
MOV EAX,[EDI+0]
NOT EAX
MOV [EDI+0],EAX
ADD EDI,4
LOOP !NS_l
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 4
SYSTEM.NegateSet32 ENDP
END;
//************************************************************************
//
//
// VMT and object handling support
//
//
//************************************************************************
{$IFOPT D-}
{$D+}
{$ELSE}
{$DEFINE WASDEBUG}
{$ENDIF}
ASSEMBLER
SYSTEM.!VMTCall PROC NEAR32
MOV EBX,ESP
MOV EDI,[EBX+4]
MOV EDI,[EDI+0]
CMP EDI,0
JNE !VmtWeiter
MOV EDI,[EBX+4]
CMPD [EDI+4],0
JNE !VmtConstructor
PUSHL 214
CALLN32 SYSTEM.RunError
!VmtConstructor:
MOV EDI,[EDI+4]
!VmtWeiter:
LEA EDI,[EDI+EAX*4]
JMP [EDI+0]
SYSTEM.!VMTCall ENDP
END;
{$IFNDEF WASDEBUG}
{$D-}
{$ENDIF}
{$UNDEF WASDEBUG}
//************************************************************************
//
//
// Floating point support
//
//
//************************************************************************
PROCEDURE SetTrigMode(mode:BYTE);
BEGIN
CASE Mode OF
Rad:IsNotRad:=FALSE;
Deg:
BEGIN
ToRad:=0.01745329262;
FromRad:=57.29577951;
IsNotRad:=TRUE;
END;
Gra:
BEGIN
ToRad:=0.01570796327;
FromRad:=63.66197724;
IsNotRad:=TRUE;
END;
END; {case}
END;
ASSEMBLER
SYSTEM.!FormatStr PROC NEAR32 //Format in AL, String in EDI
//Format the string
CMP AL,0
JE !LLw47_1
MOV AH,[EDI+0] //Length of string
CMP AH,AL
JAE !LLw47_1 //No format to do
SUB AL,AH //Calculate spaces to add
ADD [EDI+0],AL //Set length to new value
PUSH EDI
MOVZX EBX,AH //old length of string
ADD EDI,EBX //End of string
MOVZX EBX,AL //Count of spaces to add
MOV ESI,EDI
ADD EDI,EBX //add count of spaces
MOVZX ECX,AH //Count (Length of string) to ECX
INC ECX //and #0
STD //From backwards
REP
MOVSB
MOV ECX,EBX
MOV AL,32 //Space
POP EDI //Pop it
PUSH EDI
INC EDI
CLD
REP
STOSB
POP EDI
MOVZXB EAX,[EDI+0]
INC EDI
ADD EDI,EAX
CLD
!LLw47_1:
RETN32
SYSTEM.!FormatStr ENDP
SYSTEM.!RadArc PROC NEAR32 //Converts ST(0) to Rad
CMPB SYSTEM.IsNotRad,1
JNE !!!_l80
FLDT SYSTEM.ToRad
FMULP ST(1),ST
!!!_l80:
RETN32
SYSTEM.!RadArc ENDP
SYSTEM.!NormRad PROC NEAR32 //Converts ST(0) to actual TrigMode
CMPB SYSTEM.IsNotRad,1
JNE !!!_l81
FLDT SYSTEM.FromRad
FMULP ST(1),ST
!!!_l81:
RETN32
SYSTEM.!NormRad ENDP
SYSTEM.!Calculate PROC NEAR32
//Input EDI String
//CX Count
//Output Value in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,4
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
!!!weiter1:
MOV AL,[EDI+0]
SUB AL,$3a
ADD AL,$0a
JNB !!!ex
XOR AH,AH
MOV [EBP-2],AX
FILDD SYSTEM.C10
FMULP ST(1),ST
FILDW [EBP-2]
FADDP ST(1),ST
FWAIT
INC EDI
DEC CX
CMP CX,0
JE !!!ex
JMP !!!weiter1
!!!ex:
LEAVE
RETN32
SYSTEM.!Calculate ENDP
SYSTEM.!DivTab PROC NEAR32
dw 0,0,0,32768,16383,0,0,0 //1
dw 0,0,0,40960,16386,0,0,0 //10
dw 0,0,0,51200,16389,0,0,0 //100
dw 0,0,0,64000,16392,0,0,0 //1000
dw 0,0,0,40000,16396,0,0,0 //10^4
dw 0,0,0,50000,16399,0,0,0 //10^5
dw 0,0,0,62500,16402,0,0,0 //10^6
dw 0,0,32768,39062,16406,0,0,0 //10^7
dw 0,0,8192,48828,16409,0,0,0 //10^8
SYSTEM.!DivTab ENDP
SYSTEM.!Power10Tab PROC NEAR32
db 0,0,0,0,0,$20,$bc,$be,$19,$40 //1.0E+8
db 0,0,0,4,$bf,$c9,$1b,$8e,$34,$40 //1.0E+16
db $9e,$b5,$70,$2b,$a8,$ad,$c5,$9d,$69,$40 //1.0E+32
db $d5,$a6,$cf,$0ff,$49,$1f,$78,$c2,$d3,$40 //1.0E+64
db $e0,$8c,$e9,$80,$c9,$47,$ba,$93,$a8,$41 //1.0E+128
db $8e,$de,$0f9,$9d,$fb,$eb,$7e,$aa,$51,$43 //1.0E+256
db $c7,$91,$0e,$a6,$ae,$a0,$19,$e3,$a3,$46 //1.0E+512
db $17,$0c,$75,$81,$86,$75,$76,$c9,$48,$4d //1.0E+1024
db $e5,$5d,$3d,$c5,$5d,$3b,$8b,$9e,$92,$5a //1.0E+2048
db $9b,$97,$20,$8a,2,$52,$60,$c4,$25,$75 //1.0E+4096
SYSTEM.!Power10Tab ENDP
SYSTEM.!MaxMulTab PROC NEAR32
db $9b,$97,$20,$8a,2,$52,$60,$c4,$25,$75 //1.0E+4096
SYSTEM.!MaxMulTab ENDP
SYSTEM.!DivMul10 PROC NEAR32
//Input: BX Count of divides/mult by 10
// AL 0-mult 1-divide
MOV CX,BX
AND CX,7 //31 only values 0..31
MOV ESI,@SYSTEM.!DivTab
MOVZX ECX,CX
SHL ECX,1
SHL ECX,1
SHL ECX,1
SHL ECX,1
ADD ESI,ECX
FLDT [ESI+0] //1..10^32 laden
SHR BX,1
SHR BX,1
SHR BX,1 //divide numbers by 8
MOV ESI,@SYSTEM.!Power10Tab
CMP BX,0
JE !!!process
!!!Power10:
SHR BX,1
JNB !!!mm //until a bit is set
FLDT [ESI+0]
FMULP ST(1),ST
!!!mm:
ADD ESI,10
CMP BX,0
JNE !!!Power10
!!!process:
CMP AL,1
JNE !!!_mul
FDIVP ST(1),ST
RETN32
!!!_mul:
FMULP ST(1),ST
RETN32
SYSTEM.!DivMul10 ENDP
SYSTEM.!Str2Float PROC NEAR32
//Input EDI String to convert
// CX Length of this string
//Output Floating point value in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,6 //for Control word and sign
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTCW [EBP-2] //Store control word
FWAIT
FCLEX //Clear exceptions
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FLDZ //Load +0.0
MOVB [EBP-4],0 //sign is positive
MOVW [EBP-6],0 //count of numbers after point
!!!again:
CMP CX,0 //String has zero length ?
JE !!!Error
MOV AL,[EDI+0] //load character
CMP AL,43 //'+'
JNE !!!not_plus
//Sign '+' was detected
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!weiter
!!!not_plus:
CMP AL,45 //'-'
JNE !!!not_minus
//Sign '-' was detected
MOVB [EBP-4],1 //Sign is negative
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!weiter
!!!not_minus:
CMP AL,32
JNE !!!weiter
INC EDI
DEC CX
JMP !!!again
!!!weiter:
CALLN32 SYSTEM.!Calculate //Calculate numbers before point
CMP CX,0
JNE !!!a_exp
CMPB [EBP-4],1
JNE !!!no_exp
FCHS
FWAIT //change sign
JMP !!!no_exp
!!!a_exp:
//Look for .
MOV AL,[EDI+0]
CMP AL,'.'
JNE !!!Change
DEC CX
CMP CX,0
JE !!!Change
INC EDI
PUSH CX
CALLN32 SYSTEM.!Calculate //Calculate numbers after point
POP BX
SUB BX,CX
MOV [EBP-6],BX //Count of numbers after point
!!!Change:
//in ST(0) is now an integer value
//[EBP-6] contains the current numbers after the point
CMPB [EBP-4],1
JNE !!!not_neg
FCHS
FWAIT //change sign
!!!not_neg:
//Check for exponent
CMP CX,0
JE !!!no_exp
MOV AL,[EDI+0]
CMP AL,'e'
JE !!!exp
CMP AL,'E'
JNE !!!no_exp
!!!exp:
//an exponent was detected
INC EDI
DEC CX
CMP CX,0
JE !!!Error
FLDZ //Load +0.0
MOVB [EBP-4],0 //sign is positive
MOV AL,[EDI+0]
CMP AL,'-'
JNE !!!no_minus
MOVB [EBP-4],1 //sign is negative
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!Calc
!!!no_minus:
CMP AL,43 //'+'
JNE !!!calc
INC EDI
DEC CX
CMP CX,0
JE !!!Error
!!!calc:
CALLN32 SYSTEM.!Calculate
FISTPW SYSTEM.Exponent //Store integer value and pop
MOV BX,SYSTEM.Exponent
MOV AL,0 //Mult
CMPB [EBP-4],1
JNE !!!make
MOV AL,1 //Divide if Exponent negative
!!!make:
PUSH CX
CALLN32 SYSTEM.!DivMul10
POP CX
!!!no_exp:
CMP CX,0
JNE !!!Error //invalid chars
MOV BX,[EBP-6]
MOV AL,1 //Divide
CALLN32 SYSTEM.!DivMul10
JMP !!!ok
!!!Error:
MOVW SYSTEM.IoResult,1 //FPU error
!!!ok:
LEAVE
RETN32
SYSTEM.!Str2Float ENDP
SYSTEM.!Str2Real PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2Float
MOV EDI,[EBP+12]
FSTPD [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex1
MOVW [EDI+0],1
!!__fex1:
LEAVE
RETN32 12
SYSTEM.!Str2Real ENDP
SYSTEM.!Str2Double PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2Float
MOV EDI,[EBP+12]
FSTPQ [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex11
MOVW [EDI+0],1
!!__fex11:
LEAVE
RETN32 12
SYSTEM.!Str2Double ENDP
SYSTEM.!Str2Extended PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2FLoat
MOV EDI,[EBP+12]
FSTPT [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex111
MOVW [EDI+0],1
!!__fex111:
LEAVE
RETN32 12
SYSTEM.!Str2Extended ENDP
SYSTEM.!ValReal PROC NEAR32
//Input EDI : Destination String
//AX Kommastellen
//BX Len oder 17h
//Floatvalue in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,264
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
$result EQU [EBP-256]
$len EQU [EBP-258]
$comma EQU [EBP-260]
$s EQU [EBP-264]
MOV $comma,AX
CMP BX,0
JA !!6666
MOV BX,1
!!6666:
CMP BX,254 //$17
JB !!6666_1
MOV BX,$17
!!6666_1:
MOV $len,BX
MOV $s,EDI
MOV CX,$comma
OR CX,CX
JNS !!37ea
MOV CX,8
SUB CX,$len
CMP CX,$0FFFE
JLE !!37ea
MOV CX,$0FFFE
!!37ea:
LEA EDI,$result
CALLN32 SYSTEM.!Real2Str1 //Get string in EDI and length in CX
MOV ESI,EDI
MOV EDI,$s
MOV DX,255
MOV AX,$len
CMP AX,CX
JNL !!3812
MOV AX,CX
!!3812:
CLD
STOSB
SUB AX,CX
JE !!3820
PUSH CX
MOVZX ECX,AX
MOV AL,$20
REP
STOSB
POP CX
!!3820:
MOVZX ECX,CX
REP
MOVSB
LEAVE
RETN32
SYSTEM.!ValReal ENDP
SYSTEM.!!!!!Help1 PROC NEAR32
FWAIT
FSTCW [EBP-2]
FWAIT
FCLEX
FLDCW SYSTEM.FpuControl
FWAIT
FSTPT [EBP-$14]
XOR EDX,EDX
CMP CX,$12
JLE !!311a
MOV CX,$12
!!311a:
CMP CX,$0FFEE
JNL !!3122
MOV CX,$0FFEE
!!3122:
RETN32
SYSTEM.!!!!!Help1 ENDP
SYSTEM.!!!!!Help2 PROC NEAR32
MOV [EBP-$0c],AX
FLDT [EBP-$14]
SUB AX,$3FFF
XOR EDX,EDX
MOV DX,$4D10
IMUL DX
MOV [EBP-8],DX
MOV AX,$11
SUB AX,DX
CALLN32 SYSTEM.!Div_Mul10
FRNDINT
MOV ESI,*Tabx1
FLDT [ESI+0]
FCOMP ST(1)
FSTSW [EBP-4]
FWAIT
RETN32
Tabx1:
db 0,0,$40,$76,$3a,$6b,$0b,$de,$3a,$40
SYSTEM.!!!!!Help2 ENDP
SYSTEM.!!!!!Help3 PROC NEAR32
MOV AL,$45
STOSB
MOV AL,$2b
MOV DX,[EBP-8]
OR DX,DX
JNS !!3280
MOV AL,$2d
NEG DX
!!3280:
STOSB
MOV EAX,$640a
XCHG DX,AX
DIV DH
MOV DH,AH
DB $66
CBW
DIV DL
ADD AX,$3030
STOSW
MOV AL,DH
DB $66
CBW
DIV DL
ADD AX,$3030
STOSW
RETN32
SYSTEM.!!!!!Help3 ENDP
SYSTEM.!Real2Str1 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,$28
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EDI
CALLN32 SYSTEM.!!!!!Help1
CLD
NOP
FWAIT
MOV [EBP-6],CX
MOV AX,[EBP-$0c]
MOV [EBP-$0a],AX
AND AX,$7FFF
JE !!315c
CMP AX,$7FFF
JNE !!3165
CMPW [EBP-$0e],$8000
JE !!3149
MOV AX,$414e
STOSW
MOV AL,$4e
STOSB
JMP !!3299
!!3149:
CMPW [EBP-$0a],0
JNS !!3152
MOV AL,$2d
STOSB
!!3152:
MOV AX,$4e49
STOSW
MOV AL,$46
STOSB
JMP !!3299
!!315c:
MOV [EBP-8],AX
MOV [EBP-$28],AL
JMP !!3216
!!3165:
CALLN32 SYSTEM.!!!!!Help2
TESTW [EBP-4],$4100
JE !!31a1
INCW [EBP-8]
FILDD SYSTEM.C10
FDIVP ST(1),ST
!!31a1:
PUSH EBP
POP ESI
FBSTPT [ESI-$14]
MOV ESI,9
LEA EBX,[EBP-$28]
MOV CL,4
FWAIT
!!31af:
PUSH EDI
LEA EDI,[EBP-$15]
ADD EDI,ESI
MOV AL,[EDI+0]
POP EDI
MOV AH,AL
SHR AL,CL
AND AH,$0F
ADD AX,$3030
MOV [EBX+0],AX
ADD EBX,2
DEC ESI
JNE !!31af
MOV [EBX+0],SI
CMPW [EBP-6],0
JL !!31d8
CMPW [EBP-8],$24
JL !!31d8
MOVW [EBP-6],$0FFEE
!!31d8:
MOV SI,[EBP-6]
OR SI,SI
JS !!31eb
ADD SI,[EBP-8]
INC SI
JNS !!31ed
MOVB [EBP-$28],0
JMP !!3216
!!31eb:
NEG SI
!!31ed:
CMP SI,$12
JNB !!3216
MOVZX ESI,SI
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
CMPB [EDI+0],$35
MOVB [EDI+0],0
POP EDI
JB !!3216
!!31fc:
DEC SI
JS !!320e
MOVZX ESI,SI
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INCB [EDI+0]
CMPB [EDI+0],$39
POP EDI
JBE !!3216
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOVB [EDI+0],0
POP EDI
JMP !!31fc
!!320e:
INCW [EBP-8]
MOVW [EBP-$28],$31
!!3216:
XOR ESI,ESI
MOV DX,[EBP-6]
OR DX,DX
JS !!3254
CMPW [EBP-$0a],0
JNS !!3228
MOV AL,$2d
STOSB
!!3228:
MOV CX,[EBP-8]
OR CX,CX
JNS !!3234
MOV AL,$30
STOSB
JMP !!323b
!!3234:
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOV AL,[EDI+0]
INC SI
POP EDI
OR AL,AL
JNE !!32b6
MOV AL,$30
DEC SI
!!32b6:
STOSB
DEC CX
JNS !!3234
!!323b:
OR DX,DX
JE !!3299
MOV AL,$2e
STOSB
!!3242:
INC CX
JE !!324b
!!3245:
MOV AL,$30
STOSB
DEC DX
JNE !!3242
!!324b:
DEC DX
JS !!3299
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOV AL,[EDI+0]
INC SI
POP EDI
OR AL,AL
JNE !!32b6_1a
MOV AL,$30
DEC SI
!!32b6_1a:
STOSB
JMP !!324b
!!3254:
MOV AL,$20
CMPW [EBP-$0a],0
JNS !!325e
MOV AL,$2d
!!325e:
STOSB
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INC SI
MOV AL,[EDI+0]
POP EDI
OR AL,AL
JNE !!32b6_1b
MOV AL,$30
DEC SI
!!32b6_1b:
STOSB
INC DX
JE !!3270
MOV AL,$2e
STOSB
!!3269:
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INC SI
MOV AL,[EDI+0]
POP EDI
OR AL,AL
JNE !!32b6_1c
MOV AL,$30
DEC SI
!!32b6_1c:
STOSB
INC DX
JNE !!3269
!!3270:
CALLN32 SYSTEM.!!!!!Help3
!!3299:
MOV ECX,EDI
POP EDI
SUB ECX,EDI
FCLEX //Clear Exceptions
FLDCW [EBP-2]
FWAIT
LEAVE
RETN32
{*Tab1:
db 0,0,40h,76h,3ah,6bh,0bh,deh,3ah,40h}
SYSTEM.!Real2Str1 ENDP
SYSTEM.!Div_Mul10 PROC NEAR32
CMP AX,$1000
JLE !!3382
PUSH ESI
MOV ESI,@SYSTEM.!MaxMulTab
FLDT [ESI+0]
POP ESI
FMULP ST(1),ST
SUB AX,$1000
!!3382:
CMP AX,$0F000
JNL !!3393
PUSH ESI
MOV ESI,@SYSTEM.!MaxMulTab
FLDT [ESI+0]
POP ESI
FDIVP ST(1),ST
ADD AX,$1000
!!3393:
MOV BX,AX
OR AX,AX
JE !!33d4
JNS !!339d
NEG AX
!!339d:
MOV SI,AX
AND SI,7
MOVZX ESI,SI
SHL ESI,1
SHL ESI,1
SHL ESI,1
SHL ESI,1
PUSH EDI
MOV EDI,@SYSTEM.!DivTab
ADD EDI,ESI
FLDT [EDI+0]
POP EDI
SHR AX,1
SHR AX,1
SHR AX,1
MOV ESI,@SYSTEM.!Power10Tab
JMP !!33c5
!!33b7:
SHR AX,1
JNB !!33c2
FLDT [ESI+0]
FMULP ST(1),ST
!!33c2:
ADD ESI,10
!!33c5:
OR AX,AX
JNE !!33b7
OR BX,BX
JS !!33d1
FMULP ST(1),ST
!!33d0:
RETN32
!!33d1:
FDIVP ST(1),ST
!!33d4:
RETN32
SYSTEM.!Div_Mul10 ENDP
SYSTEM.!Real2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDD [EDI+0] //Load real value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOVZXB EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 12
SYSTEM.!Real2Str ENDP
SYSTEM.!Double2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDQ [EDI+0] //Load double value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOV EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 12
SYSTEM.!Double2Str ENDP
SYSTEM.!Extended2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDT [EDI+0] //Load extended value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOV EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 16
SYSTEM.!Extended2Str ENDP
SYSTEM.!WriteExtended PROC NEAR32 //Writes extended in ST
PUSH EBP
MOV EBP,ESP
SUB ESP,260
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-260]
PUSHL [EBP+12] //Format
PUSHL [EBP+8] //Nachkommas
LEA EAX,[EBP-260]
PUSH EAX
LEA EAX,[EBP-250]
PUSH EAX
CALLN32 SYSTEM.!Extended2Str
LEA EAX,[EBP-250]
PUSH EAX
PUSHL 0 //[EBP+8] ??? //Format value
CALLN32 SYSTEM.StrWrite
LEAVE
RETN32 8
SYSTEM.!WriteExtended ENDP
SYSTEM.!FPULoadLong PROC NEAR32
PUSH EBP
MOV EBP,ESP
FILDD [EBP+8]
LEAVE
RETN32 4
SYSTEM.!FPULoadLong ENDP
SYSTEM.!Sin PROC NEAR32 //calculate SIN in ST(0)
CALLN32 SYSTEM.!RadArc
FSIN
RETN32
SYSTEM.!Sin ENDP
SYSTEM.!Cos PROC NEAR32 //calculate COS in ST(0)
CALLN32 SYSTEM.!RadArc
FCOS
RETN32
SYSTEM.!Cos ENDP
SYSTEM.!Tan PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Sin
FLDT [EBP-10]
CALLN32 SYSTEM.!Cos
FTST
FSTSW [EBP-12]
FWAIT
MOV AH,[EBP-11]
SAHF
JNE !!!_l50
FSTP ST(0)
FSTP ST(0)
FLDZ
MOVW SYSTEM.FPUResult,2
JMP !!!_l51
!!!_l50:
FDIVP ST(1),ST
!!!_l51:
POP EAX
LEAVE
RETN32
SYSTEM.!Tan ENDP
SYSTEM.!Cot PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Cos
FLDT [EBP-10]
CALLN32 SYSTEM.!Sin
FTST
FSTSW [EBP-12]
FWAIT
MOV AH,[EBP-11]
SAHF
JNE !!!_l53
FSTP ST(0)
FSTP ST(0)
FLDZ
MOVW SYSTEM.FPUResult,2
JMP !!!_l54
!!!_l53:
FDIVP ST(1),ST
!!!_l54:
POP EAX
LEAVE
RETN32
SYSTEM.!Cot ENDP
SYSTEM.!ArcTan PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,4
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH ECX
MOVW SYSTEM.FPUResult,0
FXAM //Type of ST(0)
FWAIT
FSTSW [EBP-2]
MOV AH,[EBP-1]
SAHF
XCHG CX,AX
JB !!!_l30
JNE !!!_l31
JMP !!!_l32
!!!_l30:
JE !!!_l32
JNP !!!_l32
FSTP ST(0)
FLDT SYSTEM.fl3
JMP !!!_l33
!!!_l31:
FABS
FLD1
FCOM ST(1)
FWAIT
FSTSW [EBP-2]
MOV AH,[EBP-1]
SAHF
JNE !!!_l34
FCOMPP
FLDT SYSTEM.fl2
JMP !!!_l33
!!!_l34:
JNB !!!_l35
FXCH ST(1)
!!!_l35:
FPATAN
JNB !!!_l33
FLDT SYSTEM.fl3
FSUBP ST(1),ST
XOR CH,2
!!!_l33:
TEST CH,2
JE !!!_l32
FCHS
FWAIT
!!!_l32:
CALLN32 SYSTEM.!NormRad
POP ECX
POP EAX
LEAVE
RETN32
SYSTEM.!ArcTan ENDP
SYSTEM.!Sqrt PROC NEAR32
FSQRT
RETN32
SYSTEM.!Sqrt ENDP
SYSTEM.!ln PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLDLN2
FXCH ST(1)
FXAM
FWAIT
FSTSW [EBP-10]
MOV AH,[EBP-9]
SAHF
JB !!!_l20
JE !!!_l21
TEST AH,2
JE !!!_l22
!!!_l21:
FSTP ST(0)
JMP !!!_l23
!!!_l20:
FSTP ST(0)
JE !!!_l24
JNP !!!_l24
!!!_l23:
FSTP ST(0)
FLDD SYSTEM.fl1
!!!_l24:
FTST
JMP !!!_l29
!!!_l22:
FLD ST(0)
FSTPT [EBP-10]
CMPW [EBP-2],$3fff
JNE !!!_l25
CMPW [EBP-4],$8000
JNE !!!_l25
FLD1
FSUBP ST(1),ST
FYL2XP1
JMP !!!_l29
!!!_l25:
FYL2X
!!!_l29:
POP EAX
LEAVE
RETN32
SYSTEM.!ln ENDP
SYSTEM.!Exp PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,16
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
MOVW SYSTEM.FPUResult,0
FLDL2E
FXCH ST(1)
FXAM
FWAIT
FSTSW [EBP-6]
FXCH ST(1)
MOV AH,[EBP-5]
SAHF
XCHG BX,AX
JB !!!_l40
JNE !!!_l41
FSTP ST(0)
FSTP ST(0)
FLD1
JMP !!!_l43
!!!_l40:
FSTP ST(0)
JE !!!_l44
JNP !!!_l44
!!!_l48:
FSTP ST(0)
FLDD SYSTEM.fl4
!!!_l44:
FTST
JMP !!!_l43
!!!_l41:
FMULP ST(1),ST
FABS
FLDD SYSTEM.fl5
FXCH ST(1)
FSTPT [EBP-16]
FLDT [EBP-16]
FCOMPP
FWAIT
FSTSW [EBP-6]
FLDT [EBP-16]
TESTB [EBP-5],$41
JE !!!_l46
F2XM1
FLD1
FADDP ST(1),ST
FWAIT
JMP !!!_l47
!!!_l46:
FLD1
FLD ST(1)
FWAIT
FSTCW [EBP-6]
FSCALE
ORB [EBP-5],$0f
FLDCW [EBP-6]
FWAIT
FRNDINT
ANDB [EBP-5],$0f3
FLDCW [EBP-6]
FWAIT
FISTD [EBP-4]
FXCH ST(1)
FCHS
FXCH ST(1)
FSCALE
FSTP ST(1)
FSUBP ST(1),ST
CMPW [EBP-2],0
JG !!!_l48
F2XM1
FLD1
FADDP ST(1),ST
FWAIT
MOV CX,[EBP-4]
SHR CX,1
MOV [EBP-4],CX
JNB !!!_l49
FLDT SYSTEM.fl6
FMULP ST(1),ST
!!!_l49:
FILDW [EBP-4]
FXCH ST(1)
FSCALE
FSTP ST(1)
!!!_l47:
TEST BH,2
JE !!!_l43
FLD1
FDIVRP ST(1),ST
!!!_l43:
POP ECX
POP EBX
POP EAX
LEAVE
RETN32
SYSTEM.!Exp ENDP
SYSTEM.!Frac PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-10]
FLDT [EBP-10]
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FLDT [EBP-10]
FXCH ST(1)
FSUBP ST(1),ST
LEAVE
RETN32
SYSTEM.!Frac ENDP
SYSTEM.!Int PROC NEAR32
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
RETN32
SYSTEM.!Int ENDP
SYSTEM.!Round PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Frac
FLDT [EBP-10]
FADDP ST(1),ST
CALLN32 SYSTEM.!Trunc
LEAVE
RETN32
SYSTEM.!Round ENDP
SYSTEM.!Trunc PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FISTPD [EBP-10]
MOV EAX,[EBP-10]
LEAVE
RETN32
SYSTEM.!Trunc ENDP
SYSTEM.!Sqr PROC NEAR32
FLD St(0)
FMULP ST(1),ST
RETN32
SYSTEM.!Sqr ENDP
SYSTEM.!ArcSin PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLD St(0)
FABS
FLD1
FCOMPP
FWAIT
FSTSW [EBP-12]
MOV AH,[EBP-11]
SAHF
JB !!!_l60
JNE !!!_l62
//ArcSin(1.0)=w*pi/2
FLDT SYSTEM.fl7 //1.5707...
FMULP ST(1),ST
JMP !!!_l61
!!!_l62:
FLD St(0)
FSTPT [EBP-10]
FLD St(0)
FMULP ST(1),ST
FLD1
FSUBP ST(1),ST
FSQRT
FLDT [EBP-10]
FXCH ST(1)
FDIVP ST(1),ST
CALLN32 SYSTEM.!ArcTan
JMP !!!_l61
!!!_l60:
MOVW SYSTEM.FPUResult,3
!!!_l61:
CALLN32 SYSTEM.!NormRad
POP EAX
LEAVE
RETN32
SYSTEM.!ArcSin ENDP
SYSTEM.!ArcCos PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ArcSin
FLDT SYSTEM.fl7 //PI/2
FXCH ST(1)
FSUBP ST(1),ST
CALLN32 SYSTEM.!NormRad
RETN32
SYSTEM.!ArcCos ENDP
SYSTEM.!ArcCot PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ArcTan
FLDT SYSTEM.fl7 //PI/2
FXCH ST(1)
FSUBP ST(1),ST
CALLN32 SYSTEM.!NormRad
RETN32
SYSTEM.!ArcCot ENDP
SYSTEM.!Sinh PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!Exp
FLD St(0)
FLD1
FXCH ST(1)
FDIVP ST(1),ST
FXCH ST(1)
FSUBP ST(1),ST
FLDT SYSTEM.fl8
FMULP ST(1),ST
RETN32
SYSTEM.!Sinh ENDP
SYSTEM.!Cosh PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!Exp
FLD St(0)
FLD1
FXCH ST(1)
FDIVP ST(1),ST
FADDP ST(1),ST
FWAIT
FLDT SYSTEM.fl8
FMULP ST(1),ST
RETN32
SYSTEM.!Cosh ENDP
SYSTEM.!Tanh PROC NEAR32
MOVW SYSTEM.FPUResult,0
FLDT SYSTEM.fl9 //2.0
FMULP ST(1),ST
CALLN32 SYSTEM.!Exp
FLD1
FADDP ST(1),ST
FWAIT
FLDT SYSTEM.fl9 //2.0
FXCH ST(1)
FDIVP ST(1),ST
FLD1
FSUBP ST(1),ST
RETN32
SYSTEM.!Tanh ENDP
SYSTEM.!Coth PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLD St(0)
FSTPT [EBP-10]
CALLN32 SYSTEM.!Sinh
FTST
FWAIT
FSTSW [EBP-12]
MOV AH,[EBP-11]
SAHF
JE !!!_l70
FLDT [EBP-10]
CALLN32 SYSTEM.!Cosh
FXCH ST(1)
FDIVP ST(1),ST
JMP !!!_l71
!!!_l70:
MOVW SYSTEM.FPUResult,4
!!!_l71:
POP EAX
LEAVE
RETN32
SYSTEM.!Coth ENDP
SYSTEM.!lg PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ln
FLDT SYSTEM.fl10
FDIVP ST(1),ST
RETN32
SYSTEM.!lg ENDP
SYSTEM.!lb PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ln
FLDT SYSTEM.fl11
FDIVP ST(1),ST
RETN32
SYSTEM.!lb ENDP
SYSTEM.!ReadReal PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Real
LEAVE
RETN32 4
SYSTEM.!ReadReal ENDP
SYSTEM.!ReadDouble PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Double
LEAVE
RETN32 4
SYSTEM.!ReadDouble ENDP
SYSTEM.!ReadExtended PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Extended
LEAVE
RETN32 4
SYSTEM.!ReadExtended ENDP
END;
ASSEMBLER
SYSTEM.!ParaInfo PROC NEAR32 //(AL=Function - 1 count of parameters to CL
// 2 Pointer to parameter CL to ESI
//Input:argument start in ESI
MOV BX,0 //we start with parameter 0
CMP AL,2 //get parameter name ?
JNE !no_name
PUSH ESI
CMP CL,0 //parameter 0 required ?
JE !no_args
POP ESI
!no_name:
//Overread the EXE file name
CLD
PUSH AX
!rrloop:
LODSB
CMP AL,0
JNE !rrloop
POP AX
CMP AL,2 //get parameter name ?
JE !get_argname
MOV CL,255 //impossible parameter
!get_argname:
XOR CH,CH
MOV BX,1 //now finally we start with parameter 1
LODSB
//check whether the first character is a separator
CMP AL,' '
JE !aagain
CMP AL,0 //is this already the end -->Urrgh !
JNE !al2
PUSHL 0 //The (nonexistent) parameters -->Throw it away guy !
MOV BL,0 //No parameters
JMP !no_args
!al2:
DEC ESI //restore old position
!aagain:
PUSH ESI //save last adress
CMP CL,BL //is the parameter reached ??
JE !no_args
!readloop:
LODSB
CMP AL,0
JE !no_args1 //No more arguments detected
//check all separators possible
CMP AL,' '
JE !separator
//No separator --> normal character
JMP !readloop
!separator:
//Check whether more separators follow
LODSB
CMP AL,' '
JE !one_more
CMP AL,0 //A zero parameter is stupid
JNE !no_more
POP EAX //Clear stack
PUSHL 0 //The (nonexistent) parameter -->Throw it away guy !
JMP !no_args
!one_more:
JMP !separator
!no_more:
DEC ESI
INC BX //Increment parameter count
POP EAX //clear stack
JMP !aagain
!no_args1:
//Argument index was invalid
POP ESI //Clear Stack
PUSHL 0 //Pointer to parameter is NIL
!no_args:
MOV CL,BL //Parameter count
POP ESI //Adress of last parameter
RETN32
SYSTEM.!ParaInfo ENDP
END;
FUNCTION PARAMSTR(item:Byte):STRING;
VAR s,s1:STRING;
BEGIN
ParamStr:=''; {Clear}
ASM
MOV CL,$item //index to CL
MOV AL,2 //Get Parameter name
MOV ESI,SYSTEM.ArgStart
CALLN32 SYSTEM.!ParaInfo
MOV EDI,[EBP+8] //Result string
MOVB [EDI+0],0 //Result string is empty
LEA EDI,$s //result string
XOR AL,AL //Stringlen to 0
STOSB
CMP ESI,0 //Parameter invalid ?
JE _Lpe
CLD
LEA EDI,$s //result string
XOR AL,AL //Stringlen to 0
STOSB
MOV CL,0 //Len is 0
__lp1:
LODSB
//Check all separators
CMP AL,' '
JE __Lps
CMP AL,0 //Last parameter
JE __Lps
INC CL
//No separator --> save
STOSB
JMP __lp1
__Lps:
LEA EDI,$s //Result string
MOV [EDI+0],CL //set Stringlen
_lpe:
END;
IF item=0 THEN
BEGIN
IF pos('.',s)=0 THEN s:=s+'.EXE';
IF pos('\',s)=0 THEN
BEGIN
getdir(0,s1);
IF s1[length(s1)]='\' THEN dec(s1[0]);
s:=s1+'\'+s;
END;
END;
ParamStr:=s;
END;
FUNCTION PARAMCOUNT:Byte;
BEGIN
ASM
MOV AL,1 //get parametercount
MOV ESI,SYSTEM.ArgStart
CALLN32 SYSTEM.!ParaInfo
MOV AL,CL
XOR AH,AH
MOV $!FUNCRESULT,AX
END;
END;
//************************************************************************
//
//
// System initialization code
//
//
//************************************************************************
ASSEMBLER
SYSTEM.!CorrectArgList PROC NEAR32
CLD
MOVB SYSTEM.Redirect,0
MOV ESI,SYSTEM.ArgStart
CMP ESI,0
JNE !cal1_rrloop
RETN32
!cal1_rrloop:
//Overread EXE file name
LODSB
CMP AL,0
JNE !cal1_rrloop
!cal1_1:
MOV AL,[ESI+0]
CMP AL,32
JNE !cal1_3
CMPB [ESI+1],0
JNE !cal1_3
MOV AL,0
!cal1_3:
CMP AL,'|'
JE !cal1_51x
CMP AL,'>'
JE !cal1_5!
CMP AL,'<'
JNE !cal1_4
MOVB SYSTEM.RedirectIn,1
JMP !cal1_51x
!cal1_5!:
MOVB SYSTEM.RedirectOut,1
!cal1_51x:
pushl 1000
pushl 1000
calln32 system.beep
//redirect symbol found
//Set REDIRECT on TRUE
MOVB SYSTEM.Redirect,1
MOV EDI,ESI
MOV AL,0
!cal1_51!:
DEC EDI
CMP EDI,SYSTEM.ArgStart
JB !cal1_4
CMPB [EDI+0],32
JNE !cal1_4
MOVB [EDI+0],0
JMP !cal1_51!
!cal1_4:
MOV [ESI+0],AL
INC ESI
CMP AL,0
JNE !cal1_1
RETN32
SYSTEM.!CorrectArgList ENDP
END;
TYPE
PSCUFileFormat=^TSCUFileFormat;
TSCUFileFormat=RECORD
Version:STRING[5];
ObjectOffset,ObjectLen:LONGINT;
NameTableOffset,NameTableLen:LONGINT;
ResourceOffset,ResourceLen:LONGINT;
ObjectCount:LONGINT;
UseEntry:LONGINT; {used by project management}
NextEntry:POINTER;
END;
PROCEDURE AddSCUData(Data:PSCUFileFormat);
BEGIN
Data^.NextEntry:=SCUPointer;
SCUPointer:=Data;
END;
VAR ArgStart:POINTER;
EnvStart:POINTER;
CONST
C10:LONGWORD=10;
FPUControl:WORD=$133f;
FPURound:WORD=$1f3f;
FPURoundUp:WORD=$1b3f;
Exponent:WORD=0;
fl1:ARRAY[0..3] OF BYTE=(0,$42,$c0,$ff);
fl2:ARRAY[0..9] OF BYTE=($35,$c2,$68,$21,$a2,$da,$0f,$c9,$fe,$3f); //0.7853...
fl3:ARRAY[0..9] OF BYTE=($35,$c2,$68,$21,$a2,$da,$0f,$c9,$ff,$3f);
fl4:ARRAY[0..3] OF BYTE=(0,$4a,$c0,$ff);
fl5:ARRAY[0..3] OF BYTE=(0,0,0,$3f);
fl6:ARRAY[0..9] OF BYTE=($85,$64,$de,$f9,$33,$f3,4,$b5,$ff,$3f);
fl7:ARRAY[0..9] OF BYTE=($48,$7e,$2a,$92,$a2,$da,$0f,$c9,$ff,$3f); //PI/2
fl8:ARRAY[0..9] OF BYTE=(0,0,0,0,0,0,0,$80,$fe,$3f); //0.5
fl9:ARRAY[0..9] OF BYTE=(0,0,0,0,0,0,0,$80,0,$40); //2.0
fl10:ARRAY[0..9] OF BYTE=($83,$ab,$4b,$ac,$dd,$8d,$5d,$93,0,$40); //ln(10)
fl11:ARRAY[0..9] OF BYTE=($7e,$c0,$68,$77,$0d,$18,$72,$b1,$fe,$3f); //ln(2)
PROCEDURE SystemInit(HeapSize,TheStackSize:LONGWORD);
VAR
ff:^FileRec;
ESP:LONGWORD;
BEGIN
ASM
MOV $ESP,ESP
MOVD SYSTEM.MemPageSize,131072
END;
StackSize:=TheStackSize;
MinStack:=(ESP-StackSize)+16384;
ExitProc:=@ExitAll;
RedirectIn:=FALSE;
RedirectOut:=FALSE;
Redirect:=FALSE;
ASM
//Initialize FPU
FINIT
FCLEX
FLDCW SYSTEM.FPUControl
FWAIT
//correct arguments
CALLN32 SYSTEM.!CorrectArgList
END;
FileBufSize:=32760; {Standard file buffer size}
ff:=@Input;
ff^.Handle:=0; {Handle to standard input}
ff^.RecSize:=1;
ff^.Name:='';
ff^.EAS:=NIL;
ff^.Flags:=$6666;
ff^.Mode:=0;
ff^.Buffer:=NIL;
ff^.MaxCacheMem:=0;
ff^.Offset:=0;
ff^.LOffset:=0;
ff^.Block:=0;
ff^.LBlock:=0;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
ff:=@Output;
ff^.Handle:=1; {Handle to standard output}
ff^.RecSize:=1;
ff^.Name:='';
ff^.EAS:=NIL;
ff^.Flags:=$6666;
ff^.Mode:=0;
ff^.Buffer:=NIL;
ff^.MaxCacheMem:=0;
ff^.Offset:=0;
ff^.LOffset:=0;
ff^.Block:=0;
ff^.LBlock:=0;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
HeapError:=StdHeapError;
IF DosCreateMutexSem(NIL,HeapMutex,DC_SEM_SHARED,FALSE)<>0
THEN RunError(218);
HeapStrategyBestFit:=FALSE;
LastHeapPage:=NIL;
LastHeapPageAdr:=NIL;
IF not CreateSystemHeap(HeapSize*1024) THEN RunError(218);
{Initialize system variables}
OpenedFilesCount:=0;
IOResult:=0;
FileMode:=fmInOut;
SeekMode:=0; {File begin}
SetTrigMode(rad);
IF ApplicationType=1 THEN {initialize PM}
BEGIN
AppHandle:=WinInitialize(0);
AppQueueHandle:=WinCreateMsgQueue(AppHandle,0);
END;
END;
TYPE
POINTL=RECORD
x:LONGINT;
y:LONGINT;
END;
QMSG=RECORD
hwnd:LONGWORD;
msg:LONGWORD;
mp1:LONGWORD;
mp2:LONGWORD;
time:LONGWORD;
ptl:POINTL;
reserved:LONGWORD;
END;
PROCEDURE MainDispatchLoop;
VAR _qmsg:QMSG;
BEGIN
ASM
!ndis:
PUSHL 0
PUSHL 0
PUSHL 0
LEA EAX,$_qmsg
PUSH EAX
PUSHL SYSTEM.AppHandle
MOV AL,5
CALLDLL PMWIN,915 //WinGetMsg
ADD ESP,20
CMP EAX,0
JE !exdis
LEA EAX,$_qmsg
PUSH EAX
PUSHL SYSTEM.AppHandle
MOV AL,2
CALLDLL PMWIN,912 //WinDispatchMsg
ADD ESP,8
JMP !ndis
!exdis:
END;
END;
PROCEDURE SystemEnd(ReturnCode:WORD);
BEGIN
Halt(0);
END;
{$D+}
BEGIN
END.
{$ENDIF OS2}
{$IFDEF WIN95}
{***************************************************************************
* *
* SPEED PASCAL for Windows95 *
* (C) 1992..95 SpeedSoft Software *
* *
* Unit SYSTEM : Low level basic functions *
* *
* Note: Compile with DWORD align !! *
* *
***************************************************************************}
INTERFACE
//General functions
FUNCTION Swap(i:INTEGER):INTEGER;
//general constants
CONST
MINSHORTINT = -128;
MAXSHORTINT = 127;
MAXINT = 32767;
MININT =-32768;
MAXLONGINT = 2147483647;
{$IFDEF DOSOS2} //BP doesn't accept this
MINLONGINT =-2147483647;
{$ELSE}
MINLONGINT =-2147483648;
{$ENDIF}
MINBYTE = 0;
MAXBYTE = 255;
MINWORD = 0;
MAXWORD = 65535;
MAXLONGWORD = $ffffffff;
MINLONGWORD = 0;
NULLHANDLE = 0;
SCUPointer:POINTER=NIL;
//General types
//General types
TYPE
PChar =^CSTRING;
PString =^STRING;
PDATETIME=^DATETIME;
DATETIME=RECORD
CASE INTEGER OF
1: ( hour:BYTE;
min:BYTE;
sec:BYTE;
hundredths:BYTE;
day:BYTE;
month:BYTE;
year:WORD;
timezone:INTEGER;
weekday:BYTE;
);
2: ( hours:BYTE;
minutes:BYTE;
seconds:BYTE;
);
END;
{Generic procedure pointer}
TProcedure = procedure;
// Memory management functions
TYPE
HeapFunc=FUNCTION(size:LONGWORD):Integer;
VAR
HeapOrg:Pointer; {Bottom of heap}
HeapEnd:Pointer; {End of heap}
HeapPtr:Pointer; {Actual heap position}
FreeList:Pointer; {List of free blocks}
HeapTop:POINTER; {Highest heap adress that has been commited}
HeapSize:LONGWORD; {Size of heap}
HeapError:HeapFunc; {Heap Error Function}
HeapResult:LONGWORD; {Result from last heap function}
MemAvailBytes:LONGWORD;
FUNCTION MaxAvail:LongWord;
FUNCTION MemAvail:LongWord;
PROCEDURE GetMem(VAR pp:Pointer;size:LongWord);
PROCEDURE GetSharedMem(VAR pp:Pointer;size:LongWord);
PROCEDURE Mark(VAR p:POINTER);
PROCEDURE Release(VAR p:POINTER);
PROCEDURE FreeMem(pp:pointer;size:LongWord);
PROCEDURE FreeSharedMem(p:pointer;size:LongWord);
PROCEDURE GetAPIMem(VAR p:POINTER;size:LONGWORD);
PROCEDURE FreeAPIMem(p:POINTER;size:LONGWORD);
PROCEDURE NewSystemHeap;
FUNCTION CreateSystemHeap(Size:LONGWORD):BOOLEAN;
PROCEDURE DestroySystemHeap;
PROCEDURE DestroyHeap(Heap:POINTER);
// Random numbers support
VAR
RandSeed:LONGWORD;
PROCEDURE Randomize;
FUNCTION Random(value:word):word;
//Direct memory access
PROCEDURE MOVE(CONST source;VAR dest;size:LongWord);
PROCEDURE FILLCHAR(VAR dest;size:LongWord;value:byte);
//LongJmp support
TYPE Jmp_Buf=ARRAY[0..8] OF LONGWORD;
FUNCTION SetJmp(VAR JmpBuf:Jmp_Buf):LONGWORD;
PROCEDURE LongJmp(VAR JmpBuf:Jmp_Buf;RetVal:LONGWORD);
//String functions
PROCEDURE UpcaseStr(VAR s:STRING);
FUNCTION POS(CONST item,source:STRING):BYTE;
FUNCTION Copy(CONST Source:STRING; Index,Count:INTEGER):STRING;
PROCEDURE SubStr(VAR source:STRING;start,ende:Byte);
PROCEDURE Insert(CONST Source:STRING; VAR S:STRING; Index:INTEGER);
PROCEDURE Delete(VAR S:STRING; Index,Count:INTEGER);
FUNCTION ToHex(l:LONGWORD):STRING;
//Floating point support
CONST
rad=1;
deg=2;
gra=3;
VAR
IsNotRad:BOOLEAN;
ToRad,FromRad:EXTENDED;
FPUResult:WORD;
PROCEDURE SetTrigMode(mode:BYTE);
CONST
PI=3.141592653589793240;
{TYPE
(* Class structures layout, particulary also valid for objects *)
PClassInfoLayout=^TClassInfoLayout;
TClassInfoLayout=RECORD
ClassSize:LONGWORD;
ParentObjectAddr:POINTER;
FieldAdress:POINTER;
(*Class Info following here*)
END;
PDmtLayout=^TDmtLayout;
TDmtLayout=RECORD
NumDmts:LONGWORD; (*Number of entries*)
(*entries follow here
each entry is 8 byte long
the first DWord contains the message id,
the second DWord contains the VMT index*)
END;
PVmtLayOut=^TVmtLayOut;
TVmtLayOut=RECORD
Dmt:PDmtLayout; (*Pointer to DMT*)
ClassInfo:PClassInfoLayout;
ClassSize:LONGWORD;
VmtSize:LONGWORD; (*Number of entries*)
(*entries follow here
each entry is 4 byte long and contains
the address for that VMT index*)
END;
TClassLayout=RECORD
Vmt:PVmtLayout;
(*Object variables follow here*)
END;}
TYPE
TObject = CLASS;
TClass = CLASS OF TObject;
TObject = CLASS
CONSTRUCTOR Create;
DESTRUCTOR Destroy; VIRTUAL;
PROCEDURE Free;VIRTUAL;
CLASS FUNCTION NewInstance: TObject; VIRTUAL;
PROCEDURE FreeInstance; virtual;
CLASS FUNCTION InitInstance(Instance: Pointer): TObject;
CLASS FUNCTION ClassType: TClass;
CLASS FUNCTION ClassName: STRING;
CLASS FUNCTION ClassUnit: STRING;
CLASS FUNCTION ClassParent: TClass;
CLASS FUNCTION GetClassInfo: POINTER; //conflicts with PMWIN CLASSINFO
CLASS FUNCTION InstanceSize: LONGWORD;
CLASS FUNCTION InheritsFrom(AClass: TClass): BOOLEAN;
PROCEDURE DefaultHandler(VAR Message); VIRTUAL;
PROCEDURE DefaultFrameHandler(VAR Message); VIRTUAL;
PROCEDURE Dispatch(VAR Message);
PROCEDURE DispatchCommand(VAR Message;Command:LONGWORD);
PROCEDURE FrameDispatch(VAR Message);
CLASS FUNCTION MethodAddress(CONST Name: STRING): POINTER;
CLASS FUNCTION MethodName(Address: POINTER): STRING;
FUNCTION FieldAddress(Name: STRING): POINTER;
END;
TYPE TScreenInOutClass=CLASS
PROCEDURE WriteStr(CONST s:STRING);VIRTUAL;
PROCEDURE WriteCStr(CONST s:CSTRING);VIRTUAL;
PROCEDURE WriteLF;VIRTUAL;
PROCEDURE ReadLF(VAR s:STRING);VIRTUAL;
PROCEDURE GotoXY(x,y:BYTE);VIRTUAL;
END;
TPMScreenInOutClass=CLASS
PROCEDURE WriteStr(CONST s:STRING);VIRTUAL;
PROCEDURE WriteCStr(CONST s:CSTRING);VIRTUAL;
PROCEDURE WriteLF;VIRTUAL;
PROCEDURE ReadLF(VAR s:STRING);VIRTUAL;
PROCEDURE GotoXY(x,y:BYTE);VIRTUAL;
PROCEDURE Error;
END;
VAR ScreenInOut:TScreenInOutClass;
VAR
IOResult:LONGWORD;
CONST
{FileMode values}
fmDenyRead = $00000002; {deny read access by other processes }
fmDenyWrite = $00000001; {deny write access by other processes }
fmDenyNone = $00000003; {deny neither read nor write }
fmDenyBoth = $0; {deny both read and write access (standard) }
fmClosed = 0;
fmInput = $80000000 or fmDenyWrite; {Read only }
fmOutput = $40000000 or fmDenyRead; {Write only }
fmInOut = $C0000000 or fmDenyNone; {allow both read and write access (standard) }
CONST
{Seek Origin Constants}
Seek_Begin = 0; //Seek from beginning of file
Seek_Current = 1; //Seek from current position of file
Seek_End = 2; //Seek from end of file
VAR
FileMode:LONGWORD; {file mode for both reset and rewrite}
SeekMode:LONGWORD; {seek mode for seek }
TYPE
P_FileBuffer=^T_FileBuffer;
T_FileBuffer=ARRAY[0..MaxLongInt-1] OF BYTE; {handled dynamically}
FileRec = RECORD
Handle : LongWord; {FileHandle }
RecSize : LongWord; {Record size }
Name : STRING; {(Long) file name }
EAS : POINTER; {extended attributes }
Mode : LONGWORD; {Current file mode }
Reserved : POINTER; {for private extensions}
Block : LONGWORD; {current block in file }
LBlock : LONGWORD; {Last block in file }
Offset : LONGWORD; {Current offset in Block}
LOffset : LONGWORD; {Last Offset in LBlock }
Changed : LONGBOOL; {TRUE if Block has changed}
Buffer : P_FileBuffer; {I/O Buffer }
MaxCacheMem : LONGWORD; {Size of I/O Buffer }
Flags : LONGWORD; {Assign flags $6666 }
Reserved1 : WORD; {dont use }
BufferBytes : WORD; {dont use }
{312 byte til here}
END;
PROCEDURE Assign(VAR f:FILE;CONST s:STRING);
PROCEDURE Rewrite(VAR f:FILE;recsize:LONGWORD);
PROCEDURE Reset(VAR f:FILE;recsize:LONGWORD);
PROCEDURE Close(VAR f:FILE);
PROCEDURE BlockRead(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
PROCEDURE BlockWrite(VAR f:file;VAR Buf;Count:LongWord;VAR result:LONGWORD);
PROCEDURE Rename(VAR f:file;NewName:String);
PROCEDURE Truncate(VAR f:FILE);
PROCEDURE Append(VAR f:Text);
PROCEDURE Seek(VAR f:FILE;n:LONGINT);
FUNCTION SeekEof(Var F :Text):Boolean;
FUNCTION SeekEoln(Var F :Text):Boolean;
FUNCTION FilePos(VAR f:FILE):LONGWORD;
FUNCTION FileSize(VAR f:FILE):LONGWORD;
FUNCTION Eof(VAR f:FILE):BOOLEAN;
FUNCTION Eoln(VAR f:FILE):BOOLEAN;
PROCEDURE Erase(VAR f:FILE);
PROCEDURE SetFileBuf(VAR f:FILE;VAR Buf;BufSize:LONGWORD);
PROCEDURE SetTextBuf(VAR f:TEXT;VAR Buf;BufSize:LONGWORD);
//Functions for manipulating directories
PROCEDURE ChDir(CONST path:STRING);
PROCEDURE GetDir(drive:byte;VAR path:STRING);
PROCEDURE RmDir(CONST dir:STRING);
PROCEDURE MkDir(CONST dir:STRING);
FUNCTION PARAMSTR(item:Byte):STRING;
FUNCTION PARAMCOUNT:Byte;
//Exception Management
TYPE
{ Exceptions }
CONST
SIZE_OF_80387_REGISTERS = 80;
TYPE
PFLOATING_SAVE_AREA=^FLOATING_SAVE_AREA;
FLOATING_SAVE_AREA=RECORD
ControlWord:LONGWORD;
StatusWord:LONGWORD;
TagWord:LONGWORD;
ErrorOffset:LONGWORD;
ErrorSelector:LONGWORD;
DataOffset:LONGWORD;
DataSelector:LONGWORD;
RegisterArea:ARRAY[0..SIZE_OF_80387_REGISTERS-1] OF BYTE;
Cr0NpxState:LONGWORD;
END;
TYPE
PCONTEXT=^CONTEXT;
CONTEXT=RECORD
ContextFlags:LONGWORD;
Dr0:LONGWORD;
Dr1:LONGWORD;
Dr2:LONGWORD;
Dr3:LONGWORD;
Dr6:LONGWORD;
Dr7:LONGWORD;
FloatSave:FLOATING_SAVE_AREA;
SegGs:LONGWORD;
SegFs:LONGWORD;
SegEs:LONGWORD;
SegDs:LONGWORD;
Edi:LONGWORD;
Esi:LONGWORD;
Ebx:LONGWORD;
Edx:LONGWORD;
Ecx:LONGWORD;
Eax:LONGWORD;
Ebp:LONGWORD;
Eip:LONGWORD;
SegCs:LONGWORD;
EFlags:LONGWORD;
Esp:LONGWORD;
SegSs:LONGWORD;
END;
CONST
EXCEPTION_CONTINUABLE = 0; // Continuable exception
EXCEPTION_NONCONTINUABLE = 1; // Noncontinuable exception
EXCEPTION_MAXIMUM_PARAMETERS =15; // maximum number of exception parameters
TYPE
PEXCEPTION_RECORD=^EXCEPTION_RECORD;
EXCEPTION_RECORD=RECORD
ExceptionCode:LONGWORD;
ExceptionFlags:LONGWORD;
ExceptionRecord:PEXCEPTION_RECORD;
ExceptionAddress:POINTER;
NumberParameters:LONGWORD;
ExceptionInformation:ARRAY[0..EXCEPTION_MAXIMUM_PARAMETERS-1] OF LONGWORD;
END;
TYPE
PEXCEPTION_POINTERS=^EXCEPTION_POINTERS;
EXCEPTION_POINTERS=RECORD
ExceptionRecord:PEXCEPTION_RECORD;
ContextRecord:PCONTEXT;
END;
TYPE
Exception=CLASS;
PExcptInfo=^TExcptInfo;
TExcptInfo=RECORD
TryAddr:POINTER;
ExcptAddr:POINTER;
OldEBP,OldESP:LONGWORD;
OldFPUControl:LONGWORD;
ExcptObject:Exception;
ThreadId:LONGWORD;
Next:PExcptInfo;
Last:PExcptInfo;
END;
//base exception record - derive all new exceptions from that !
Exception = CLASS(TObject)
PRIVATE
FMessage: PString;
FUNCTION GetMessage: STRING;
PROCEDURE SetMessage(CONST Value: STRING);
PUBLIC
ReportRecord:EXCEPTION_RECORD;
ExcptNum:LONGWORD;
CameFromRTL:BOOLEAN;
Nested:BOOLEAN;
ExcptAddr:POINTER;
RTLExcptAddr:POINTER;
ContextRecord:CONTEXT;
CONSTRUCTOR Create(CONST Msg: STRING);
DESTRUCTOR Destroy;OVERRIDE;
PROPERTY
Message:STRING read GetMessage write SetMessage;
PROPERTY
MessagePtr: PString read FMessage;
END;
TYPE
//General exception class
ExceptClass = class OF Exception;
//Software generated excpetions
EProcessTerm = CLASS(Exception);
//Hardware generated exceptions
EProcessorException = CLASS(Exception);
EFault = CLASS(EProcessorException);
EGPFault = CLASS(EFault);
EStackFault = CLASS(EFault);
EPageFault = CLASS(EFault);
EInvalidOpCode = CLASS(EFault);
EBreakpoint = CLASS(EProcessorException);
ESingleStep = CLASS(EProcessorException);
//Memory exceptions
EOutOfMemory = CLASS(Exception);
EInvalidPointer = CLASS(Exception);
EInvalidHeap = CLASS(Exception);
//Input/Output exceptions
EInOutError = CLASS(Exception)
PUBLIC
ErrorCode: Integer;
END;
EFileNotFound=CLASS(EInOutError);
EInvalidFileName=CLASS(EInOutError);
ETooManyOpenFiles=CLASS(EInOutError);
EAccessDenied=CLASS(EInOutError);
EEndOfFile=CLASS(EInOutError);
EDiskFull=CLASS(EInOutError);
EInvalidInput=CLASS(EInOutError);
//Integer math exceptions
EIntError = CLASS(Exception);
EDivByZero = CLASS(EIntError);
ERangeError = CLASS(EIntError);
EIntOverflow = CLASS(EIntError);
//Floating point math exceptions
EMathError = CLASS(Exception);
EInvalidOp = CLASS(EMathError);
EZeroDivide = CLASS(EMathError);
EOverflow = CLASS(EMathError);
EUnderflow = CLASS(EMathError);
//type cast exceptions
EInvalidCast = CLASS(Exception);
EConvertError = CLASS(Exception);
// Error functions
VAR
ExitCode:LONGWORD;
ErrorAdr:POINTER;
ExitProc:POINTER;
PROCEDURE RunError(Code:LONGWORD);
PROCEDURE Halt(Code:LONGWORD);
VAR
ApplicationType:BYTE;
//PM Routines
VAR
AppHandle:LONGWORD;
AppQueueHandle:LONGWORD;
DllModule:LONGWORD;
DllTerminating:LONGWORD;
DllInitTermResult:LONGWORD;
ModuleCount:BYTE;
RaiseIOError:BOOLEAN;
PROCEDURE MainDispatchLoop;
PROCEDURE Beep(Freq,duration:LONGWORD);
//TextScreen IO support
VAR
Input,Output:TEXT;
VAR
WindMin: WORD; { Window upper left coordinates }
WindMax: WORD; { Window lower right coordinates }
LastMode: Word; { Current text mode }
TextAttr: BYTE; { Current text attribute }
CONST
{ CRT modes }
BW40 = 0; { 40x25 B/W on Color Adapter }
CO40 = 1; { 40x25 Color on Color Adapter }
BW80 = 2; { 80x25 B/W on Color Adapter }
CO80 = 3; { 80x25 Color on Color Adapter }
Mono = 7; { 80x25 on Monochrome Adapter }
Font8x8 = 256; { Add-in for 8x8 font }
FUNCTION Assigned(p: Pointer): Boolean;
IMPLEMENTATION
VAR
ExcptList:PExcptInfo;
ExcptMutex:LONGWORD;
VAR
MaxWindMin: WORD; { Max Window upper left coordinates }
MaxWindMax: WORD; { Max Window lower right coordinates }
TYPE
PCOORD=^COORD;
COORD=RECORD
X:INTEGER;
Y:INTEGER;
END;
PSMALL_RECT=^SMALL_RECT;
SMALL_RECT=RECORD
Left:INTEGER;
Top:INTEGER;
Right:INTEGER;
Bottom:INTEGER;
END;
PCONSOLE_SCREEN_BUFFER_INFO=^CONSOLE_SCREEN_BUFFER_INFO;
CONSOLE_SCREEN_BUFFER_INFO=RECORD
dwSize:COORD;
dwCursorPosition:COORD;
wAttributes:WORD;
srWindow:SMALL_RECT;
dwMaximumWindowSize:COORD;
END;
PCHAR_INFO=^CHAR_INFO;
CHAR_INFO=RECORD
Char:RECORD
CASE Integer OF
1:(UniCodeChar:WORD);
2:(AsciiChar:CHAR);
END;
Attributes:WORD;
END;
CONST
ENABLE_PROCESSED_INPUT =$0001;
ENABLE_LINE_INPUT =$0002;
ENABLE_ECHO_INPUT =$0004;
ENABLE_WINDOW_INPUT =$0008;
ENABLE_MOUSE_INPUT =$0010;
ENABLE_PROCESSED_OUTPUT =$0001;
ENABLE_WRAP_AT_EOL_OUTPUT =$0002;
IMPORTS
FUNCTION SetFilePointer(hFile:LONGWORD;lDistanceToMove:LONGINT;
VAR lpDistanceToMoveHigh:LONGINT;
dwMoveMethod:LONGWORD):LONGWORD;
APIENTRY; 'KERNEL32' name 'SetFilePointer';
FUNCTION WriteFile(hFile:LONGWORD;CONST lpBuffer;nNumberOfBytesToWrite:LONGWORD;
VAR lpNumberOfBytesWritten:LONGWORD;
VAR lpOverlapped):LONGBOOL;
APIENTRY; 'KERNEL32' name 'WriteFile';
FUNCTION ReadFile(hFile:LONGWORD;VAR lpBuffer;nNumberOfBytesToRead:LONGWORD;
VAR lpNumberOfBytesRead:LONGWORD;
VAR lpOverlapped):LONGBOOL;
APIENTRY; 'KERNEL32' name 'ReadFile';
FUNCTION CreateFile(CONST lpFileName:CSTRING;dwDesiredAccess:LONGWORD;
dwShareMode:LONGWORD;VAR lpSecurityAttributes;
deCreationDisposition,dwFlagsAndAttributes:LONGWORD;
hTemplateFile:LONGWORD):LONGWORD;
APIENTRY; 'KERNEL32' name 'CreateFileA';
FUNCTION CloseHandle(hObject:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'CloseHandle';
FUNCTION SetCurrentDirectory(CONST lpPathName:CSTRING):LONGBOOL;
APIENTRY; 'KERNEL32' name 'SetCurrentDirectoryA';
FUNCTION GetCurrentDirectory(nBufferLength:LONGWORD;VAR lpBuffer:CSTRING):LONGWORD;
APIENTRY; 'KERNEL32' name 'GetCurrentDirectoryA';
FUNCTION RemoveDirectory(CONST lpPathName:CSTRING):LONGBOOL;
APIENTRY; 'KERNEL32' name 'RemoveDirectoryA';
FUNCTION CreateDirectory(CONST lpPathName:CSTRING;
VAR lpSecurityAttributes):LONGBOOL;
APIENTRY; 'KERNEL32' name 'CreateDirectoryA';
FUNCTION MoveFile(CONST lpExistingFileName,lpNewFileName:CSTRING):LONGBOOL;
APIENTRY; 'KERNEL32' name 'MoveFileA';
FUNCTION DeleteFile(CONST lpFileName:CSTRING):LONGBOOL;
APIENTRY; 'KERNEL32' name 'DeleteFileA';
FUNCTION SetEndOfFile(hFile:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'SetEndOfFile';
FUNCTION GetConsoleScreenBufferInfo(hConsoleOutput:LONGWORD;
VAR lpConsoleScreenBufferInfo:CONSOLE_SCREEN_BUFFER_INFO):LONGBOOL;
APIENTRY; 'KERNEL32' name 'GetConsoleScreenBufferInfo';
FUNCTION FillConsoleOutputAttribute(hConsoleOutput:LONGWORD;wAttribute:WORD;
nLength:LONGWORD;dwWriteCoord:LONGWORD;
VAR lpNumberOfAttrsWritten:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'FillConsoleOutputAttribute';
FUNCTION SetConsoleCursorPosition(hConsoleOutput:LONGWORD;dwCursorPosition:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'SetConsoleCursorPosition';
FUNCTION GetStdHandle(nStdHandle:LONGWORD):LONGWORD;
APIENTRY; 'KERNEL32' name 'GetStdHandle';
FUNCTION ReadConsoleOutputAttribute(hConsoleOutput:LONGWORD;VAR lpAttribute:WORD;
nLength:LONGWORD;dwReadCoord:LONGWORD;
VAR lpNumberOfAttrsRead:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'ReadConsoleOutputAttribute';
FUNCTION SetConsoleMode(hConsoleHandle:LONGWORD;dwMode:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'SetConsoleMode';
FUNCTION ScrollConsoleScreenBuffer(hConsoleOutput:LONGWORD;
VAR lpScrollRectangle:SMALL_RECT;
VAR lpClipRectangle:SMALL_RECT;
dwDestinationOrigin:LONGWORD{COORD};
CONST lpFill:CHAR_INFO):LONGBOOL;
APIENTRY; 'KERNEL32' name 'ScrollConsoleScreenBufferA';
FUNCTION WaitForSingleObject(hHandle:LONGWORD;dwMilliseconds:LONGWORD):LONGWORD;
APIENTRY; 'KERNEL32' name 'WaitForSingleObject';
FUNCTION ReleaseMutex(hMutex:LONGWORD):LONGBOOL;
APIENTRY; 'KERNEL32' name 'ReleaseMutex';
FUNCTION CreateMutex(VAR lpMutexAttributes;
bInitialOwner:LONGBOOL;CONST lpName:CSTRING):LONGWORD;
APIENTRY; 'KERNEL32' name 'CreateMutexA';
FUNCTION SetUnhandledExceptionFilter(lpTopLevelFilter:POINTER):POINTER;
APIENTRY; 'KERNEL32' name 'SetUnhandledExceptionFilter';
FUNCTION GetCurrentThreadId:LONGWORD;
APIENTRY; 'KERNEL32' name 'GetCurrentThreadId';
END;
//General functions
FUNCTION Assigned(p: Pointer): Boolean;
BEGIN
Assigned := p <> Nil;
END;
PROCEDURE Check_Is(o:TObject;ClassInfo:TClass);
VAR bo:BOOLEAN;
BEGIN
bo:=o.InheritsFrom(ClassInfo);
ASM
CMPB $bo,1
LEAVE
RETN32 8
END;
END;
PROCEDURE Check_Is_Class(c:TClass;ClassInfo:TClass);
VAR bo:BOOLEAN;
BEGIN
bo:=c.InheritsFrom(ClassInfo);
ASM
CMPB $bo,1
LEAVE
RETN32 8
END;
END;
PROCEDURE Check_As(o:TObject;ClassInfo:TClass);
VAR e:EInvalidCast;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF not o.InheritsFrom(ClassInfo) THEN
BEGIN
e.Create('Invalid type cast (EInvalidCast)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
END;
PROCEDURE OverflowError;
VAR e:EIntOverflow;
Adr:LONGWORD;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
e.Create('Integer Overflow (EIntOverflow)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
VAR MinStack:LONGWORD;
StackSize:LONGWORD;
PROCEDURE StackError(Adr:LONGWORD);
VAR e:EStackFault;
BEGIN
e.Create('Stack overflow (EStackFault)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
PROCEDURE CheckStack(Needed:LONGWORD);
VAR ESP:LONGWORD;
Adr:LONGWORD;
BEGIN
ASM
PUSHAD
MOV $ESP,ESP
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF ESP>MinStack THEN IF ESP<MinStack+StackSize THEN
BEGIN
IF ((ESP-Needed<MinStack)OR(ESP-Needed>MinStack+StackSize))
THEN StackError(Adr);
END;
ASM
POPAD
END;
END;
PROCEDURE RangeCheckError(Adr:LONGWORD);
VAR e:ERangeError;
BEGIN
e.Create('Range check error (ERangeError)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
Raise e;
END;
PROCEDURE CheckRange(U,O,V:LONGINT);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$V
CMP EAX,$U
JL !err_this_xxx
MOV EAX,$V
CMP EAX,$O
JG !err_this_xxx
POP EAX
LEAVE
RETN32 12
!err_this_xxx:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRangeUnsigned(U,O,V:LONGWORD);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$V
CMP EAX,$U
JB !err_this_xxx1
MOV EAX,$V
CMP EAX,$O
JA !err_this_xxx1
POP EAX
LEAVE
RETN32 12
!err_this_xxx1:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRange2(Nr,V:LONGINT);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$Nr
CMP EAX,1
JNE !my_lab1
MOV EAX,$V
CMP EAX,MINSHORTINT
JL !err_this_xxx2
CMP EAX,MAXSHORTINT
JG !err_this_xxx2
jmp !ex_this_xxx
!my_lab1:
CMP EAX,2
JNE !my_lab2
MOV EAX,$V
CMP EAX,MININT
JL !err_this_xxx2
CMP EAX,MAXINT
JG !err_this_xxx2
jmp !ex_this_xxx
!my_lab2:
CMP EAX,4
JNE !ex_this_xxx
MOV EAX,$V
CMP EAX,MINLONGINT
JL !err_this_xxx2
CMP EAX,MAXLONGINT
JG !err_this_xxx2
!ex_this_xxx:
POP EAX
LEAVE
RETN32 8
!err_this_xxx2:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
PROCEDURE CheckRangeUnsigned2(Nr,V:LONGWORD);
VAR Adr:LONGWORD;
BEGIN
ASM
PUSH EAX
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
MOV EAX,$Nr
CMP EAX,1
JNE !my_lab1w
MOV EAX,$V
CMP EAX,MINBYTE
JB !err_this_xxx2w
CMP EAX,MAXBYTE
JA !err_this_xxx2w
jmp !ex_this_xxxw
!my_lab1w:
CMP EAX,2
JNE !my_lab2w
MOV EAX,$V
CMP EAX,MINWORD
JB !err_this_xxx2w
CMP EAX,MAXWORD
JA !err_this_xxx2w
jmp !ex_this_xxxw
!my_lab2w:
CMP EAX,4
JNE !ex_this_xxxw
MOV EAX,$V
CMP EAX,MINLONGWORD
JB !err_this_xxx2w
CMP EAX,MAXLONGWORD
JA !err_this_xxx2w
!ex_this_xxxw:
POP EAX
LEAVE
RETN32 8
!err_this_xxx2w:
POP EAX
PUSHL $Adr
CALLN32 SYSTEM.RangeCheckError
END;
END;
FUNCTION Swap(i:INTEGER):INTEGER;
BEGIN
Swap:=lo(i)*256+hi(i);
END;
VAR
Redirect,RedirectOut,RedirectIn:BOOLEAN;
IMPORTS
PROCEDURE ExitProcess(RetCode:LONGWORD);
'KERNEL32' name 'ExitProcess';
END;
//************************************************************************
//
//
// Memory support management functions
//
//
//************************************************************************
IMPORTS
FUNCTION GetLastError:LONGWORD;
APIENTRY; 'KERNEL32' name 'GetLastError';
FUNCTION HeapCreate(flOptions:LONGWORD;dwInitialSize:LONGWORD;
dwMaximumSize:LONGWORD):POINTER;
APIENTRY; 'KERNEL32' name 'HeapCreate';
FUNCTION HeapDestroy(hHeap:POINTER):LONGBOOL;
APIENTRY; 'KERNEL32' name 'HeapDestroy';
FUNCTION GlobalAlloc(uFlags:LONGWORD;dwBytes:LONGWORD):POINTER;
APIENTRY; 'KERNEL32' name 'GlobalAlloc';
FUNCTION GlobalFree(hMem:POINTER):POINTER;
APIENTRY; 'KERNEL32' name 'GlobalFree';
FUNCTION HeapAlloc(hHeap:POINTER;dwFlags,dwBytes:LONGWORD):POINTER;
APIENTRY; 'KERNEL32' name 'HeapAlloc';
FUNCTION HeapFree(hHeap:POINTER;dwFlags:LONGWORD;lpMem:POINTER):LONGBOOL;
APIENTRY; 'KERNEL32' name 'HeapFree';
PROCEDURE GetSystemTime(VAR lpSystemTime);
APIENTRY; 'KERNEL32' name 'GetSystemTime';
FUNCTION GetMessage(VAR lpMsg;ahwnd,wMsgFilterMin,wMsgFilterMax:LONGWORD):LONGBOOL;
APIENTRY; 'USER32' name 'GetMessageA';
FUNCTION DispatchMessage(VAR lpMsg):LONGINT;
APIENTRY; 'USER32' name 'DispatchMessageA';
END;
PROCEDURE MainDispatchLoop;
VAR msg:RECORD
hwnd:LONGWORD;
message:LONGWORD;
wParam:LONGWORD;
lParam:LONGWORD;
time:LONGWORD;
pt:RECORD x,y:LONGINT; END;
END;
BEGIN
while GetMessage (msg,0, 0, 0) DO DispatchMessage (msg);
END;
PROCEDURE ErrorInvalidPointer(Adr:LONGINT);
VAR e:EInvalidPointer;
BEGIN
e.Create('Invalid pointer operation (EInvalidPointer)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE ErrorOutOfMemory(Adr:LONGINT);
VAR e:EOutOfMemory;
BEGIN
e.Create('Out of memory (EOutOfMemory)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE ErrorInvalidHeap(Adr:LONGINT);
VAR
e:EInvalidHeap;
BEGIN
e.Create('Heap corrupted or destroyed (EInvalidHeap)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
raise e;
END;
PROCEDURE GetAPIMem(VAR p:POINTER;Size:LONGWORD);
VAR Adr:LONGINT;
BEGIN
p:=GlobalAlloc(0,Size); {Allocate fixed memory}
IF p=NIL THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
PROCEDURE FreeAPIMem(p:POINTER;size:LONGWORD);
VAR Adr:LONGINT;
BEGIN
IF GlobalFree(p)<>NIL THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
FUNCTION CreateHeap(size:LONGWORD):POINTER;
VAR
p:POINTER;
BEGIN
p:=HeapCreate(0,8192,0); {Heap growable and serialize}
CreateHeap:=p;
END;
PROCEDURE DestroyHeap(Heap:POINTER);
VAR Adr:LONGINT;
BEGIN
IF not HeapDestroy(Heap) THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
FUNCTION CreateSystemHeap(size:LONGWORD):BOOLEAN;
BEGIN
HeapSize:=Size;
MemAvailBytes:=Size;
HeapOrg:=CreateHeap(size);
HeapPtr:=HeapOrg;
HeapEnd:=HeapOrg;
inc(HeapEnd,size);
FreeList:=NIL;
HeapTop:=HeapPtr;
CreateSystemHeap:=HeapOrg<>NIL;
END;
PROCEDURE DestroySystemHeap;
BEGIN
DestroyHeap(HeapOrg);
HeapOrg:=NIL;
HeapPtr:=NIL;
HeapEnd:=NIL;
FreeList:=NIL;
HeapTop:=NIL;
HeapSize:=0;
END;
PROCEDURE NewSystemHeap; {delete old system heap and create new one}
VAR OldSize:LONGWORD;
BEGIN
{Free old system heap and generate new}
OldSize:=HeapSize;
DestroySystemHeap;
CreateSystemHeap(OldSize);
END;
FUNCTION StdHeapError(size:LONGWORD):INTEGER;
BEGIN
StdHeapError:=0; {Raise Runtime error}
END;
PROCEDURE GETMEM(var pp:Pointer;size:LongWord);
VAR
i:INTEGER;
Adr:LONGINT;
LABEL l;
BEGIN
IF size=0 THEN
BEGIN
pp:=NIL;
exit;
END;
l:
pp:=HeapAlloc(HeapOrg,0,(size+7) AND $FFFFFFF8);
IF pp=NIL THEN
BEGIN
i:=HeapError(size);
CASE i OF
1: pp:=NIL;
2: goto l;
ELSE
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
exit;
END;
IF LONGWORD(pp)>LONGWORD(HeapPtr) THEN HeapPtr:=pp;
dec(MemAvailBytes,(size+7) AND $FFFFFFF8);
END;
PROCEDURE SAVEGETMEM(var pp:Pointer;size:LongWord);
VAR
i:INTEGER;
Adr:LONGINT;
LABEL l;
BEGIN
ASM {!!}
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
l:
pp:=HeapAlloc(HeapOrg,0,(size+7) AND $FFFFFFF8);
IF pp=NIL THEN
BEGIN
i:=HeapError(size);
CASE i OF
1: pp:=NIL;
2: goto l;
ELSE
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
exit;
END;
IF LONGWORD(pp)>LONGWORD(HeapPtr) THEN HeapPtr:=pp;
dec(MemAvailBytes,(size+7) AND $FFFFFFF8);
ASM {!!}
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
PROCEDURE FREEMEM(pp:pointer;size:LongWord);
VAR
i:INTEGER;
Adr:LONGINT;
LABEL l;
BEGIN
IF size=0 THEN exit;
l:
IF not HeapFree(HeapOrg,0,pp) THEN
BEGIN
i:=HeapError(size);
CASE i OF
1: pp:=NIL;
2: goto l;
ELSE
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
exit;
END;
inc(MemAvailBytes,(size+7) AND $FFFFFFF8);
pp:=NIL;
END;
PROCEDURE SAVEFREEMEM(pp:pointer;size:LongWord);
VAR
i:INTEGER;
Adr:LONGINT;
LABEL l;
BEGIN
ASM {!!}
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
l:
IF not HeapFree(HeapOrg,0,pp) THEN
BEGIN
i:=HeapError(size);
CASE i OF
1: pp:=NIL;
2: goto l;
ELSE
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
exit;
END;
inc(MemAvailBytes,(size+7) AND $FFFFFFF8);
pp:=NIL;
ASM {!!}
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION MaxAvail:LongWord;
BEGIN
MaxAvail:=LONGWORD(HeapEnd)-LONGWORD(HeapPtr);
END;
FUNCTION MemAvail:LongWord;
BEGIN
MemAvail:=MemAvailBytes;
END;
PROCEDURE GetSharedMem(VAR pp:Pointer;size:LongWord);
VAR Adr:LONGINT;
BEGIN
pp:=GlobalAlloc($2000,Size); {Allocate fixed shared memory}
IF pp=NIL THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorOutOfMemory(Adr);
END;
END;
PROCEDURE FreeSharedMem(p:pointer;size:LongWord);
VAR Adr:LONGINT;
BEGIN
IF GlobalFree(p)<>NIL THEN
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ErrorInvalidPointer(Adr);
END;
END;
PROCEDURE Mark(VAR p:POINTER);
BEGIN
END;
PROCEDURE Release(VAR p:POINTER);
BEGIN
END;
//************************************************************************
//
//
// Error functions
//
//
//************************************************************************
IMPORTS
FUNCTION MessageBox(ahwnd:LONGWORD;CONST lpText,lpCaption:CSTRING;
uType:LONGWORD):LONGWORD;
APIENTRY; 'USER32' name 'MessageBoxA';
END;
PROCEDURE Halt(Code:LONGWORD);
VAR
cs:CSTRING;
cTitle:CSTRING;
BEGIN
ExitCode:=Code;
IF ExitCode<>0 THEN
BEGIN
IF ApplicationType=1 THEN
BEGIN
cs:='Speed Pascal/2 Runtime error '+tostr(ExitCode);
cTitle:='Runtime error';
MessageBox(0,cs,ctitle,0);
END
ELSE Writeln('Speed Pascal/2 Runtime error ',ExitCode);
END;
ASM
!exloop:
PUSHL *!raddr //Return adress for ExitProc
PUSHL SYSTEM.ExitProc //ExitProc on Stack
RETN32
!raddr:
JMP !exloop //until termination
END;
END;
PROCEDURE HaltIntern(Code:LONGWORD);
VAR
cs:CSTRING;
cTitle:CSTRING;
BEGIN
ExitCode:=Code;
ASM
!exloop_11:
PUSHL *!raddr_11 //Return adress for ExitProc
PUSHL SYSTEM.ExitProc //ExitProc on Stack
RETN32
!raddr_11:
JMP !exloop_11 //until termination
END;
END;
PROCEDURE RunError(Code:LONGWORD);
BEGIN
HaltIntern(Code);
END;
//Exception management
{The standard exception class}
FUNCTION Exception.GetMessage:STRING;
BEGIN
GetMessage:=FMessage^;
END;
PROCEDURE Exception.SetMessage(CONST Value:STRING);
BEGIN
IF FMessage<>NIL THEN
FreeMem(FMessage,length(FMessage^)+1);
GetMem(FMessage,length(value)+1);
FMessage^:=value;
END;
CONSTRUCTOR Exception.Create(CONST msg:STRING);
BEGIN
GetMem(FMessage,length(msg)+1);
FMessage^:=msg;
END;
DESTRUCTOR Exception.Destroy;
BEGIN
IF FMessage<>NIL THEN
FreeMem(FMessage,length(FMessage^)+1);
END;
//Win95 Exception numbers
CONST
STATUS_WAIT_0 =$00000000;
STATUS_ABANDONED_WAIT_0 =$00000080;
STATUS_USER_APC =$000000C0;
STATUS_TIMEOUT =$00000102;
STATUS_PENDING =$00000103;
STATUS_GUARD_PAGE_VIOLATION =$80000001;
STATUS_DATATYPE_MISALIGNMENT =$80000002;
STATUS_BREAKPOINT =$80000003;
STATUS_SINGLE_STEP =$80000004;
STATUS_ACCESS_VIOLATION =$C0000005;
STATUS_IN_PAGE_ERROR =$C0000006;
STATUS_NO_MEMORY =$C0000017;
STATUS_ILLEGAL_INSTRUCTION =$C000001D;
STATUS_NONCONTINUABLE_EXCEPTION =$C0000025;
STATUS_INVALID_DISPOSITION =$C0000026;
STATUS_ARRAY_BOUNDS_EXCEEDED =$C000008C;
STATUS_FLOAT_DENORMAL_OPERAND =$C000008D;
STATUS_FLOAT_DIVIDE_BY_ZERO =$C000008E;
STATUS_FLOAT_INEXACT_RESULT =$C000008F;
STATUS_FLOAT_INVALID_OPERATION =$C0000090;
STATUS_FLOAT_OVERFLOW =$C0000091;
STATUS_FLOAT_STACK_CHECK =$C0000092;
STATUS_FLOAT_UNDERFLOW =$C0000093;
STATUS_INTEGER_DIVIDE_BY_ZERO =$C0000094;
STATUS_INTEGER_OVERFLOW =$C0000095;
STATUS_PRIVILEGED_INSTRUCTION =$C0000096;
STATUS_STACK_OVERFLOW =$C00000FD;
STATUS_CONTROL_C_EXIT =$C000013A;
CONST
EXCEPTION_ACCESS_VIOLATION =STATUS_ACCESS_VIOLATION;
EXCEPTION_DATATYPE_MISALIGNMENT=STATUS_DATATYPE_MISALIGNMENT;
EXCEPTION_BREAKPOINT =STATUS_BREAKPOINT;
EXCEPTION_SINGLE_STEP =STATUS_SINGLE_STEP;
EXCEPTION_ARRAY_BOUNDS_EXCEEDED=STATUS_ARRAY_BOUNDS_EXCEEDED;
EXCEPTION_FLT_DENORMAL_OPERAND =STATUS_FLOAT_DENORMAL_OPERAND;
EXCEPTION_FLT_DIVIDE_BY_ZERO =STATUS_FLOAT_DIVIDE_BY_ZERO;
EXCEPTION_FLT_INEXACT_RESULT =STATUS_FLOAT_INEXACT_RESULT;
EXCEPTION_FLT_INVALID_OPERATION=STATUS_FLOAT_INVALID_OPERATION;
EXCEPTION_FLT_OVERFLOW =STATUS_FLOAT_OVERFLOW;
EXCEPTION_FLT_STACK_CHECK =STATUS_FLOAT_STACK_CHECK;
EXCEPTION_FLT_UNDERFLOW =STATUS_FLOAT_UNDERFLOW;
EXCEPTION_INT_DIVIDE_BY_ZERO =STATUS_INTEGER_DIVIDE_BY_ZERO;
EXCEPTION_INT_OVERFLOW =STATUS_INTEGER_OVERFLOW;
EXCEPTION_PRIV_INSTRUCTION =STATUS_PRIVILEGED_INSTRUCTION;
EXCEPTION_IN_PAGE_ERROR =STATUS_IN_PAGE_ERROR;
EXCEPTION_ILLEGAL_INSTRUCTION =STATUS_ILLEGAL_INSTRUCTION;
EXCEPTION_NONCONTINUABLE_EXCEPTION=STATUS_NONCONTINUABLE_EXCEPTION;
EXCEPTION_STACK_OVERFLOW =STATUS_STACK_OVERFLOW;
EXCEPTION_INVALID_DISPOSITION =STATUS_INVALID_DISPOSITION;
EXCEPTION_GUARD_PAGE =STATUS_GUARD_PAGE_VIOLATION;
CONTROL_C_EXIT =STATUS_CONTROL_C_EXIT;
{ debugger (VIA DosDebug) }
EXCEPTION_INTERNAL_RTL =$E0000000;
{return values}
CONST
EXCEPTION_EXECUTE_HANDLER = 1;
EXCEPTION_CONTINUE_SEARCH = 0;
EXCEPTION_CONTINUE_EXECUTION =-1;
VAR
RegisterInfo:STRING;
PROCEDURE NewExceptionFilter(ExcptInfo:PExcptInfo);
VAR Dummy:PExcptInfo;
BEGIN
ExcptInfo^.Next:=NIL;
ExcptInfo^.ExcptObject:=NIL;
ASM
MOV EDI,$ExcptInfo
ADD EDI,8
MOV EAX,[EBP+0] //old EBP
MOV [EDI+0],EAX
MOV EAX,EBP
ADD EAX,12 //Old ESP
MOV [EDI+4],EAX
FSTCW [EDI+8] //Old FPU Control
END;
WaitForSingleObject(ExcptMutex,$FFFFFFFF);
IF ExcptList=NIL THEN
BEGIN
ExcptList:=ExcptInfo;
ExcptList^.Last:=NIL;
END
ELSE
BEGIN
dummy:=ExcptList;
WHILE dummy^.next<>NIL DO dummy:=dummy^.Next;
dummy^.Next:=ExcptInfo;
dummy^.Next^.Last:=Dummy;
END;
ReleaseMutex(ExcptMutex);
END;
PROCEDURE ReleaseExceptionFilter(ExcptInfo:PExcptInfo);
VAR Dummy:PExcptInfo;
LABEL l;
BEGIN
WaitForSingleObject(ExcptMutex,$FFFFFFFF);
dummy:=ExcptList;
WHILE dummy<>NIL DO
BEGIN
IF dummy=ExcptInfo THEN
BEGIN
IF dummy^.Last=NIL THEN
BEGIN
ExcptList:=dummy^.Next;
IF ExcptList<>NIL THEN ExcptList^.Last:=NIL;
END
ELSE
BEGIN
IF dummy^.Next<>NIL THEN
dummy^.Next^.Last:=dummy^.Last;
dummy^.Last^.Next:=dummy^.Next;
END;
goto l;
END;
dummy:=dummy^.Next;
END;
l:
ReleaseMutex(ExcptMutex);
END;
{The exception handler. Incoming exceptions will come here first}
FUNCTION ExcptHandler(VAR ExceptionInfo:EXCEPTION_POINTERS):LONGINT;APIENTRY;
VAR Dummy:PExcptInfo;
ExcptAddr:POINTER;
Found:PExcptInfo;
Objekt:Exception;
OldESP,OldEBP,OldFPUControl:LONGWORD;
ThreadId:LONGWORD;
LABEL l,l1;
BEGIN
IF ExcptList=NIL THEN
BEGIN
l:
result:=EXCEPTION_CONTINUE_SEARCH; //terminate process
exit;
END
ElSE
BEGIN
IF ExceptionInfo.ExceptionRecord^.ExceptionFlags=EXCEPTION_NONCONTINUABLE
THEN goto l; {dont handle}
ThreadId:=GetCurrentThreadId;
{Search exception handler}
WaitForSingleObject(ExcptMutex,$FFFFFFFF);
ExcptAddr:=ExceptionInfo.ExceptionRecord^.ExceptionAddress;
dummy:=ExcptList;
WHILE dummy^.Next<>NIL DO dummy:=dummy^.Next;
Found:=NIL;
WHILE dummy<>NIL DO
BEGIN
{IF LONGWORD(ExcptAddr)>=LONGWORD(dummy^.TryAddr) THEN
IF LONGWORD(ExcptAddr)<=LONGWORD(dummy^.ExcptAddr) THEN
Found:=dummy;}
IF dummy^.ThreadId=ThreadId THEN
BEGIN
Found:=dummy;
goto l1;
END;
dummy:=dummy^.Last;
END;
l1:
IF Found=NIL THEN
IF ExcptList<>NIL THEN Found:=ExcptList;
ReleaseMutex(ExcptMutex);
IF Found=NIL THEN goto l;
Registerinfo:= #13#10'at CS:EIP ='+
ToHex(LONGWORD(ExceptionInfo.ContextRecord^.SegCS))+':'
+ToHex(LONGWORD(ExcptAddr));
END;
//Handle all hardware exceptions
//all other exceptions will be notified by an exception class
CASE ExceptionInfo.ExceptionRecord^.ExceptionCode OF
EXCEPTION_BREAKPOINT:
Found^.ExcptObject:=EBreakPoint.Create('Breakpoint exception (EBreakPoint) occured'+
RegisterInfo);
EXCEPTION_STACK_OVERFLOW:
Found^.ExcptObject:=EStackFault.Create('Stack fault exception (EStackFault) occured'+
RegisterInfo);
EXCEPTION_ACCESS_VIOLATION:
Found^.ExcptObject:=EGPFault.Create('Access violation exception (EGPFault) occured'+
RegisterInfo);
EXCEPTION_IN_PAGE_ERROR:
Found^.ExcptObject:=EPageFault.Create('Page fault exception (EPageFault) occured'+
RegisterInfo);
EXCEPTION_ILLEGAL_INSTRUCTION,EXCEPTION_PRIV_INSTRUCTION:
Found^.ExcptObject:=EInvalidOpCode.Create('Invalid instruction exception (EInvalidOpCode) occured'+
RegisterInfo);
EXCEPTION_SINGLE_STEP:
Found^.ExcptObject:=ESingleStep.Create('Single step exception (ESingleStep) occured'+
RegisterInfo);
EXCEPTION_INT_DIVIDE_BY_ZERO:
Found^.ExcptObject:=EDivByZero.Create('Integer divide by zero exception (EDivByZero) occured'+
RegisterInfo);
EXCEPTION_INT_OVERFLOW:
Found^.ExcptObject:=EIntOverFlow.Create('Integer overflow exception (EIntOverFlow) occured'+
RegisterInfo);
EXCEPTION_FLT_DIVIDE_BY_ZERO:
Found^.ExcptObject:=EZeroDivide.Create('Float zero divide exception (EZeroDivide) occured'+
RegisterInfo);
EXCEPTION_FLT_INVALID_OPERATION:
Found^.ExcptObject:=EInvalidOp.Create('Float invalid operation exception (EInvalidOp) occured'+
RegisterInfo);
EXCEPTION_FLT_OVERFLOW:
Found^.ExcptObject:=EOverFlow.Create('Float overflow exception (EOverFlow) occured'+
RegisterInfo);
EXCEPTION_FLT_UNDERFLOW:
Found^.ExcptObject:=EUnderFlow.Create('Float underflow exception (EUnderFlow) occured'+
RegisterInfo);
EXCEPTION_FLT_DENORMAL_OPERAND,EXCEPTION_FLT_INEXACT_RESULT,
EXCEPTION_FLT_STACK_CHECK:
Found^.ExcptObject:=EMathError.Create('General float exception (EMathError) occured'+
RegisterInfo);
EXCEPTION_INTERNAL_RTL:
BEGIN
result:=EXCEPTION_CONTINUE_EXECUTION;
exit;
END;
ELSE goto l; {Don't handle}
END; {case}
{Win95 generated exception}
Found^.ExcptObject.ReportRecord:=ExceptionInfo.ExceptionRecord^;
Found^.ExcptObject.ExcptNum:=ExceptionInfo.ExceptionRecord^.ExceptionCode;
Found^.ExcptObject.ContextRecord:=ExceptionInfo.ContextRecord^;
Found^.ExcptObject.ExcptAddr:=ExcptAddr;
{Jump to the label set by try}
ExceptionInfo.ContextRecord^.EAX:=LONGWORD(Found^.ExcptObject);
ExceptionInfo.ContextRecord^.EIP:=LONGWORD(Found^.ExcptAddr);
ExceptionInfo.ContextRecord^.EBP:=Found^.OldEBP;
ExceptionInfo.ContextRecord^.ESP:=Found^.OldESP;
ExceptionInfo.ContextRecord^.FloatSave.ControlWord:=Found^.OldFPUControl;
result:=EXCEPTION_CONTINUE_EXECUTION; //run except handling
END;
IMPORTS
PROCEDURE RaiseExceptionAPI(dwExceptionCode,dwExceptionFlags:LONGWORD;
nNumberOfArguments:LONGWORD;VAR lpArguments);
APIENTRY; 'KERNEL32' name 'RaiseException';
END;
PROCEDURE ExcptRunError(e:Exception);
VAR
s:STRING;
cs:CSTRING;
cTitle:CSTRING;
Arguments:ARRAY[0..1] OF LONGWORD;
BEGIN
try
IF e.CameFromRTL THEN IF not e.Nested THEN
BEGIN
e.Nested:=TRUE;
Arguments[0]:=LONGWORD(e.RTLExcptAddr);
Arguments[1]:=LONGWORD(e.FMessage);
RaiseExceptionAPI(EXCEPTION_INTERNAL_RTL,0,2,Arguments);
END;
finally
e.ExcptAddr:=e.RTLExcptAddr;
end;
IF POINTER(e.ExcptAddr)<>NIL THEN
s:='Exception occured: '+e.Message+' at '+tohex(LONGWORD(e.ExcptAddr))+
#13#10'Program is terminated.'
ELSE
s:='Exception occured: '+e.Message+
#13#10'Program is terminated.';
IF ApplicationType=1 THEN
BEGIN
cs:=s;
cTitle:='Exception occured';
MessageBox(0,cs,ctitle,0);
END
ELSE Writeln(s);
Halt;
END;
PROCEDURE RaiseException(objekt:Exception;adress:LONGWORD);
VAR ExcptAddr:POINTER;
dummy,Found:PExcptInfo;
ThreadId:LONGWORD;
LABEL l1;
BEGIN
IF Adress=0 THEN
BEGIN
ASM
MOV EAX,[EBP+4]
MOV $Adress,EAX
END;
END;
ThreadId:=GetCurrentThreadId;
{Search exception handler}
WaitForSingleObject(ExcptMutex,$FFFFFFFF);
ExcptAddr:=POINTER(Adress);
dummy:=ExcptList;
WHILE dummy^.Next<>NIL DO dummy:=dummy^.Next;
Found:=NIL;
WHILE dummy<>NIL DO
BEGIN
{IF LONGWORD(ExcptAddr)>=LONGWORD(dummy^.TryAddr) THEN
IF LONGWORD(ExcptAddr)<=LONGWORD(dummy^.ExcptAddr) THEN
Found:=dummy;}
IF dummy^.ThreadId=ThreadId THEN
BEGIN
Found:=dummy;
goto l1;
END;
dummy:=dummy^.Last;
END;
l1:
IF Found=NIL THEN
IF ExcptList<>NIL THEN Found:=ExcptList;
ReleaseMutex(ExcptMutex);
IF Found=NIL THEN ExcptRunError(Objekt);
Found^.ExcptObject:=Objekt;
ASM
MOV EAX,$Objekt
MOV EDI,$Found
PUSHL [EDI+8] //old EBP
POP EBP
MOV ESP,[EDI+12] //old ESP
FLDCW [EDI+16] //old FPU Control Word
JMP [EDI+4] //jump into exception handler
END;
END;
PROCEDURE RaiseExceptionAgain(e:Exception);
BEGIN
RaiseException(e,LONGWORD(e.ExcptAddr));
END;
PROCEDURE Beep(Freq,duration:LONGWORD);
BEGIN
ASM
PUSHL $duration
PUSHL $freq
CALLDLL KERNEL32,'Beep'
END;
END;
//************************************************************************
// CLASS support
//************************************************************************
{Constructor for all classes}
CONSTRUCTOR TObject.Create;
BEGIN
InitInstance(POINTER(SELF));
END;
{Destructor for all classes}
DESTRUCTOR TObject.Destroy;
BEGIN
END;
{Frees an instance of a class}
PROCEDURE TObject.Free;
BEGIN
IF POINTER(SELF)<>NIL THEN Self.Destroy;
END;
{frees an Instance of a class}
PROCEDURE TObject.FreeInstance;
BEGIN
{FreeInstance is normally called by the Destructor to
deallocate memory for the object. In Speed-Pascal the
memory deallocation is done by the compiler thus
overriding this method has no effect}
END;
{Gets class information from the ClassInfo structure}
CLASS FUNCTION TObject.GetClassInfo: Pointer;
BEGIN
ASM
MOV EAX,$!ClassInfo
MOV EAX,[EAX+4]
MOV $!FUNCRESULT,EAX
END;
END;
{Returns size of an instance of a class of TObject or a class derived
from TObject from the ClassInfo structure}
CLASS FUNCTION TObject.InstanceSize:LONGWORD;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !InstanceSize_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !InstanceSize_NoInfo
MOV EAX,[EDI+0] //Get class size
!InstanceSize_NoInfo:
MOV $!FUNCRESULT,EAX
END;
END;
{Generates a new instance of a class from the ClassInfo structure
and calls the constructor for that class}
CLASS FUNCTION TObject.NewInstance: TObject;
BEGIN
{NewInstance is normally called by the Constructor to
allocate memory for the object. In Speed-Pascal the
memory allocation is done by the compiler thus
overriding this method has no effect}
END;
{Initializes an Instance from the ClassInfo structure given by Instance}
CLASS FUNCTION TObject.InitInstance(Instance: Pointer): TObject;
BEGIN
{Fill the object with zeros. Object must be initialized with Create !}
inc(Instance,4);
FillChar(Instance^,InstanceSize-4,0);
dec(Instance,4);
InitInstance:=TObject(Instance);
END;
CLASS FUNCTION TObject.ClassName: STRING;
VAR ps:^STRING;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !ClassName_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !ClassName_NoInfo
LEA EDI,[EDI+16] //points to class name
MOV EAX,EDI
!ClassName_NoInfo:
MOV $ps,EAX
END;
IF ps<>NIL THEN ClassName:=ps^
ELSE ClassName:='';
END;
CLASS FUNCTION TObject.ClassUnit:STRING;
VAR ps:^STRING;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //Get Object pointer
CMP EDI,0
JE !ClassUnit_NoInfo
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !ClassUnit_NoInfo
LEA EDI,[EDI+16] //points to class name
MOVZXB EAX,[EDI+0] //overreas class name
ADD EDI,EAX
INC EDI
MOV EAX,EDI
!ClassUnit_NoInfo:
MOV $ps,EAX
END;
IF ps<>NIL THEN ClassUnit:=ps^
ELSE ClassUnit:='';
END;
{Default handler for messages}
PROCEDURE TObject.DefaultHandler(VAR Message);
BEGIN
{Do nothing here !}
END;
{Default frame handler for messages}
PROCEDURE TObject.DefaultFrameHandler(VAR Message);
BEGIN
{Do nothing here !}
END;
{Dispatches dynamic methods}
PROCEDURE TObject.Dispatch(VAR Message);
BEGIN
{Check if there's a DMT entry for the message
The message ID MUST be the first DWORD of Message !!
If an entry is found call the message handler}
ASM
MOV EDI,$Message
MOV EAX,[EDI+0] //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch
!DLoop:
CMP [ESI+0],EAX
JNE !ELoop
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop:
ADD ESI,8 //Next DMT entry
LOOP !DLoop //try to find next
!EndeDispatch:
END; {case}
{other case call the Default handler}
DefaultHandler(Message);
END;
{Dispatches dynamic methods}
PROCEDURE TObject.DispatchCommand(VAR Message;Command:LONGWORD);
BEGIN
{Check if there's a DMT entry for the WM_COMMAND message}
ASM
MOV EDI,$Message
MOV EAX,$Command //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch_2
!DLoop_2:
CMP [ESI+0],EAX
JNE !ELoop_2
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop_2:
ADD ESI,8 //Next DMT entry
LOOP !DLoop_2 //try to find next
!EndeDispatch_2:
END; {case}
{other case call the Default handler}
DefaultHandler(Message);
END;
{Dispatches dynamic methods}
PROCEDURE TObject.FrameDispatch(VAR Message);
BEGIN
{Check if there's a DMT entry for the message
The message ID MUST be the first DWORD of Message !!
If an entry is found call the message handler}
ASM
MOV EDI,$Message
MOV EAX,[EDI+0] //Get message index
MOV EDI,$SELF //Get Object
MOV EDI,[EDI+0] //Get VMT pointer
MOV ESI,[EDI+0] //Get DMT pointer
MOV ECX,[ESI+0] //Get number of DMT entries
ADD ESI,4
CMP ECX,0
JE !EndeDispatch_1
!DLoop_1:
CMP [ESI+0],EAX
JNE !ELoop_1
//Message found
PUSHD $Message //Message Parameter
PUSHD $SELF //SELF Pointer to object
MOV EAX,[ESI+4] //get VMT index
CALLN32 [EDI+EAX*4] //call VMT method
LEAVE
RETN32 8
!ELoop_1:
ADD ESI,8 //Next DMT entry
LOOP !DLoop_1 //try to find next
!EndeDispatch_1:
END; {case}
{other case call the Default handler}
DefaultFrameHandler(Message);
END;
ASSEMBLER
!GetMethodName PROC NEAR32
//INPUT : EAX adress to find
// EDI VMT pointer
//OUTPUT: String adress or NIL in EAX
MOV EDI,[EDI+4] //Get class info pointer
LEA EDI,[EDI+16] //points to class name
MOVZXB EBX,[EDI+0] //get Class name length
INC EDI
ADD EDI,EBX
MOVZXB EBX,[EDI+0] //get Unit name length
INC EDI
ADD EDI,EBX //points on first method adress
!MLoop:
CMPD [EDI+0],0 //end of list ??
JE !MELoop
CMP [EDI+0],EAX //Method found
JNE !MWLoop
//Method found
LEA EAX,[EDI+4] //points to Method name
JMP !MEFLoop
!MWLoop:
ADD EDI,4
MOVZXB EBX,[EDI+0] //get method name length
INC EDI
ADD EDI,EBX //points to next method address
JMP !MLoop //try next
!MELoop:
MOV EAX,0 //not found
!MEFLoop:
RETN32
!GetMethodName ENDP
END;
{returns the Method Name for an adress or an empty string}
CLASS FUNCTION TObject.MethodName(Address: POINTER): STRING;
VAR ps:^STRING;
Class_Info:POINTER;
BEGIN
ps:=NIL; {Default}
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV $Class_Info,EDI //get address to find
!MAgain:
MOV EDI,$Class_Info
MOV EAX,$Address
CALLN32 !GetMethodName //search for method
CMP EAX,0
JE !Nfound
//Method was found
MOV $ps,EAX
JMP !Mfound
!Nfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !MAgain //Try again if parents exist
!Mfound:
END;
IF ps=NIL THEN MethodName:=''
ELSE MethodName:=ps^;
END;
ASSEMBLER
!GetMethodAddress PROC NEAR32
//INPUT : ESI pointer to string to find
// EDI VMT pointer
//OUTPUT: method pointer or NIL in EAX
MOV EDI,[EDI+4] //Get class info pointer
LEA EDI,[EDI+16] //points to class name
MOVZXB EBX,[EDI+0] //get Class name length
INC EDI
ADD EDI,EBX
MOVZXB EBX,[EDI+0] //get Unit name length
INC EDI
ADD EDI,EBX //points on first method adress
MOV CL,[ESI+0] //get method string length
!ALoop:
MOV EDX,EDI //save pointer
MOV EBX,ESI //save pointer
CMPD [EDI+0],0 //end of list ??
JE !AELoop
ADD EDI,4 //onto name
CMP CL,[EDI+0] //length correct
JNE !AWLoop
//length was correct
MOVZX ECX,CL //String length
INC EDI
INC ESI
CLD
REP
CMPSB //Compare strings
JNE !AWLoop
//Method was found
MOV EAX,[EDX+0] //get method adress
JMP !AEFLoop
!AWLoop:
MOV EDI,EDX //get old pointer
MOV ESI,EBX //get old pointer
ADD EDI,4
MOVZXB EAX,[EDI+0] //get method name length
INC EDI
ADD EDI,EAX //points to next method address
MOV CL,[ESI+0]
JMP !ALoop //try next
!AELoop:
MOV EAX,0 //not found
!AEFLoop:
RETN32
!GetMethodAddress ENDP
END;
{returns the adress of a method or NIL}
CLASS FUNCTION TObject.MethodAddress(CONST Name: STRING): POINTER;
VAR
Adr:POINTER;
Class_Info:POINTER;
BEGIN
Adr:=NIL; {Default}
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV $Class_Info,EDI //get address to find
!AAgain_1:
MOV EDI,$Class_Info
MOV ESI,$Name
CALLN32 !GetMethodAddress //search for method
CMP EAX,0
JE !ANfound
//Method was found
MOV $Adr,EAX
JMP !AMfound
!ANfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !AAgain_1 //Try again if parents exist
!AMfound:
END;
MethodAddress:=Adr;
END;
ASSEMBLER
!GetFieldOffset PROC NEAR32
//INPUT : ESI pointer to string to find
// EDI VMT pointer
//OUTPUT: field offset or 0 in EAX
MOV EDI,[EDI+8] //Field info start
MOV AL,[ESI+0] //get method string length
INC ESI
!FLoop:
MOV EDX,EDI //save pointer
MOV EBX,ESI //save pointer
CMPD [EDI+0],0 //end of list ??
JE !FELoop
CMP AL,[EDI+4] //length correct
JNE !FWLoop
//length was correct
MOVZX ECX,AL //String length
ADD EDI,5 //onto first char
CLD
REP
CMPSB //Compare strings
JNE !FWLoop
//Method was found
MOV EAX,[EDX+0] //get method adress
JMP !FEFLoop
!FWLoop:
MOV EDI,EDX //get old pointer
MOV ESI,EBX //get old pointer
ADD EDI,4
MOVZXB EBX,[EDI+0] //get method name length
INC EDI
ADD EDI,EBX //points to next method address
JMP !FLoop //try next
!FELoop:
MOV EAX,0 //not found
!FEFLoop:
RETN32
!GetFieldOffset ENDP
END;
FUNCTION TObject.FieldAddress(Name: STRING): POINTER;
VAR
Adr:POINTER;
Class_Info:POINTER;
BEGIN
Adr:=NIL; {Default}
UpcaseStr(Name);
ASM
MOV EDI,$SELF //get object pointer
MOV EDI,[EDI+0] //get VMT Pointer
MOV EDI,[EDI+4] //get Class info pointer
MOV $Class_Info,EDI //get address to find
!FAgain:
MOV EDI,$Class_Info
LEA ESI,$Name
CALLN32 !GetFieldOffset //search for method
CMP EAX,0
JE !FNfound
//Method was found
MOV EBX,$SELF
MOV $Adr,EBX
ADD $Adr,EAX
JMP !FMfound
!FNfound:
//Method not found, check parent
MOV EDI,$Class_Info //Actual class
MOV EDI,[EDI+4] //Get class info pointer
CMP EDI,0
JE !FMfound //not found
MOV EAX,[EDI+4] //Get parent class adress info
MOV $Class_Info,EAX
CMP EAX,0
JNE !FAgain //Try again if parents exist
!FMfound:
END;
FieldAddress:=Adr;
END;
{returns type of a class}
CLASS FUNCTION TObject.ClassType: TClass;
BEGIN
ASM
MOV EAX,$!ClassInfo
MOV $!FUNCRESULT,EAX
END;
END;
{Returns Parent Class pointer of the Object or NIL}
CLASS FUNCTION TObject.ClassParent: TClass;
BEGIN
ASM
MOV EAX,0
MOV EDI,$!ClassInfo //get Class info pointer
CMP EDI,0
JE !ClassParent_NoInfo
MOV EDI,[EDI+4] //points to Class information
CMP EDI,0
JE !ClassParent_NoInfo
MOV EAX,[EDI+4] //Get Parent Class pointer
!ClassParent_NoInfo:
MOV $!FUNCRESULT,EAX
END;
END;
{returns true if the Class is derived from AClass, otherwise FALSE}
CLASS FUNCTION TObject.InheritsFrom(AClass: TClass): BOOLEAN;
BEGIN
ASM
MOV EDI,$!ClassInfo //get Class info pointer
MOV EAX,$AClass //class to check
MOVD $!FUNCRESULT,0 //Default
!ILoop:
CMP EDI,EAX //is it this class ?
JNE !IWLoop
//The Class was found
MOVD $!FUNCRESULT,1
JMP !IELoop
!IWLoop:
//try parent class
MOV EDI,[EDI+4] //points to class info
MOV EDI,[EDI+4] //get parent info
CMP EDI,0
JNE !ILoop
!IELoop:
END;
END;
{internally: returns true if the Class1 is derived from Class2 otherwise FALSE}
FUNCTION CheckDerived(Class1,Class2: TClass): BOOLEAN;
BEGIN
ASM
MOV EDI,$Class1 //get Class info pointer
MOV EAX,$Class2 //class to check
MOVD $!FUNCRESULT,0 //Default
!ILoop11:
CMP EDI,EAX //is it this class ?
JNE !IWLoop11
//The Class was found
MOVD $!FUNCRESULT,1
JMP !IELoop11
!IWLoop11:
//try parent class
MOV EDI,[EDI+4] //points to class info
MOV EDI,[EDI+4] //get parent info
CMP EDI,0
JNE !ILoop11
!IELoop11:
END;
END;
ASSEMBLER
//Abstract method (causes Runtime Error 210)
SYSTEM.!Abstract PROC NEAR32
PUSHL 210
CALLN32 SYSTEM.RunError
SYSTEM.!Abstract ENDP
END;
//************************************************************************
// LongJmp support
//************************************************************************
FUNCTION SetJmp(VAR JmpBuf:Jmp_Buf):LONGWORD;
BEGIN
ASM
MOV EDI,$JmpBuf
MOV EAX,[EBP+0]
MOV [EDI+0],EAX
MOV EAX,[EBP+4]
MOV [EDI+4],EAX
MOV EAX,EBP
ADD EAX,12
MOV [EDI+8],EAX
MOV ESI,0
db $64 //SEG FS
MOV EAX,[ESI+0]
MOV [EDI+$18],EAX
FSTCW [EDI+$1C]
XOR EAX,EAX
MOV $!FUNCRESULT,EAX
END;
END;
PROCEDURE LongJmp(VAR JmpBuf:Jmp_Buf;RetVal:LONGWORD);
BEGIN
ASM
//MOV EDI,$JmpBuf
//PUSHL 0
//MOV EAX,*ljmpret
//PUSH EAX
//PUSHL [EDI+$18]
//MOV AL,3
//CALLDLL DosCalls,357 //DosUnwindException
ljmpret:
MOV EDI,$JmpBuf
db $db,$e3 //FINIT Init FPU
FWAIT
FLDCW [EDI+$1C]
MOV EAX,$RetVal
AND EAX,EAX
JNZ !rtv0
MOV EAX,1
!rtv0:
PUSHL [EDI+0]
POP EBP
MOV ESP,[EDI+8]
ADD EDI,4
db $0ff,$27 //JMP NEAR32 [EDI+0] --> jump into proc
END;
END;
//***************************************************
// String Support routines
//***************************************************
PROCEDURE UpcaseStr(VAR s:STRING);
BEGIN
ASM
MOV EDI,$s
XOR ECX,ECX
MOV CL,[EDI+0]
OR CL,CL
JE !usend
INC EDI
MOV EBX,*ustab
CLD
!usfilter:
MOV AL,[EDI+0]
XLAT
STOSB
DEC ECX
JNZ !usfilter
!usend:
LEAVE
RETN32 4
ustab:
db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
db 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38
db 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57
db 58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76
db 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96
db 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83
db 84,85,86,87,88,89,90
db 123,124,125,126,127,128,129,130,131,132,133,134,135,136,137
db 138,139,140,141,142,143,144,145,146,147,148,149,150,151,152
db 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167
db 168,169,170,171,172,173,174,175,176,177,178,179,180,181,182
db 183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198
db 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213
db 214,215,216,217,218,219,220,221,222,223,224,225,226,227,228
db 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244
db 245,246,247,248,249,250,251,252,253,254,255
END;
END;
PROCEDURE LongWord2Str(l:LONGWORD;Format:LONGWORD;VAR result:STRING);
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EAX,$l
MOV EBX,10
XOR ECX,ECX
Lw46_1nn:
XOR EDX,EDX
DIV EBX
PUSH DX
INC CX
OR EAX,EAX
JNE Lw46_1nn
MOV ESI,$RESULT
MOVB [ESI+0],0
MOV EDI,ESI
CMP ECX,$Format
JAE Lw47nn
//format the string
MOV EAX,$Format
SUB EAX,ECX
MOV [ESI+0],AL
INC EDI
PUSH ECX
MOV ECX,EAX
MOV AL,32
CLD
REP STOSB //fill up with space
DEC EDI
POP ECX
Lw47nn:
POP AX
ADD AL,48
INCB [ESI+0]
INC EDI
MOV [EDI+0],AL
LOOP Lw47nn
END;
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION GetBoolValue(b:BOOLEAN):STRING;
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
END;
IF b THEN GetBoolValue:='TRUE'
ELSE GetBoolValue:='FALSE';
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
PROCEDURE LongInt2Str(l:LONGINT;Format:LONGWORD;VAR result:STRING);
VAR
IsNeg:BOOLEAN;
BEGIN
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOVB $IsNeg,0
MOV EAX,$l
MOV EBX,10
XOR ECX,ECX
CMP EAX,0
JNL Lw46_1
NEG EAX
MOVB $IsNeg,1
Lw46_1:
XOR EDX,EDX
DIV EBX
PUSH DX
INC CX
OR EAX,EAX
JNE Lw46_1
MOV ESI,$RESULT
MOVB [ESI+0],0
MOV EDI,ESI
MOV EBX,ECX
CMPB $IsNeg,1
JNE !nin1
INC EBX
!nin1:
CMP EBX,$Format
JAE Lw47_1n
//format the string
MOV EAX,$Format
SUB EAX,EBX
MOV [ESI+0],AL
INC EDI
PUSH ECX
MOV ECX,EAX
MOV AL,32
CLD
REP STOSB //fill up with space
DEC EDI
POP ECX
Lw47_1n:
CMPB $IsNeg,1
JNE Lw47
INC EDI
INCB [ESI+0]
MOVB [EDI+0],45 //'-'
Lw47:
POP AX
ADD AL,48
INCB [ESI+0]
INC EDI
MOV [EDI+0],AL
LOOP Lw47
END;
ASM
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
END;
FUNCTION POS(CONST item,source:STRING):BYTE;
VAR
result:BYTE;
BEGIN
ASM
MOV ESI,$item //item
CLD
LODSB
OR AL,AL
JE lab2
MOVZX EAX,AL
MOV EDX,EAX
MOV EDI,$source //source
MOVZXB ECX,[EDI+0]
SUB ECX,EDX
JB lab2
INC ECX
INC EDI
lab1:
LODSB
REPNE
SCASB
JNE lab2
MOV EAX,EDI
MOV EBX,ECX
MOV ECX,EDX
DEC ECX
REPE
CMPSB
JE lab3
MOV EDI,EAX
MOV ECX,EBX
MOV ESI,$item //item
INC ESI
JMP lab1
Lab2:
XOR EAX,EAX
JMP Lab4
lab3:
DEC EAX
SUB EAX,$source //source
Lab4:
MOV $result,AL
END;
POS:=result;
END;
FUNCTION Copy(CONST Source:STRING; Index,Count:INTEGER):STRING;
BEGIN
ASM
MOV ESI,$source //Source string
MOV EDI,$!FuncResult //Destination string
MOVW [EDI+0],0 //Empty String
MOVSXW ECX,$Count //Count
CMP ECX,1
JL !_CopyE
MOVSXW EAX,$Index //Index
CMP EAX,1
JNL !_Copy1
MOV EAX,1 //Index:=1
!_Copy1:
MOVZXB EBX,[ESI+0] //Length of Source
CMP EAX,EBX
JA !_CopyE
MOV EDX,EAX
ADD EDX,ECX //Index+Count
CMP EDX,EBX
JNA !_Copy2
MOV ECX,EBX
SUB ECX,EAX
INC ECX //Count := Length(S)-Index+1
!_Copy2:
MOV [EDI+0],CL
INC EDI
ADD ESI,EAX //first char
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!_CopyE:
END;
END;
FUNCTION ToHex(l:LONGWORD):STRING;
VAR
HexNum:STRING;
result:STRING;
r:LONGWORD;
BEGIN
HexNum:='0123456789ABCDEF';
result:='';
WHILE l>=16 DO
BEGIN
r:=l MOD 16;
l:=l DIV 16;
result:=HexNum[r+1]+result;
END;
result:=HexNum[l+1]+result;
WHILE length(result)<8 DO result:='0'+result;
ToHex:='$'+Result;
END;
PROCEDURE SUBSTR(VAR source:STRING;start,ende:Byte);
BEGIN
ASM
CLD
MOV ESI,$source //Source string
MOV EDI,ESI //Destination string
MOVZXB AX,[ESI+0] //Length of source
MOVZXB ECX,$Start //Index
OR ECX,ECX
JG !_Lab1_1
MOV ECX,1
!_Lab1_1:
ADD ESI,ECX
SUB AX,CX
JB !_Lab3_1
INC AX
MOVZXB CX,$Ende //Count
OR CX,CX
JGE !_Lab2_1
XOR CX,CX
!_Lab2_1:
CMP AX,CX
JBE !_Lab4_1
MOV AX,CX
JMP !_Lab4_1
!_Lab3_1:
XOR AX,AX
!_Lab4_1:
CLD
STOSB
MOVZX ECX,AX
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
END;
END;
PROCEDURE Insert(CONST Source:STRING; VAR S:STRING; Index:INTEGER);
BEGIN
IF Length(Source) = 0 THEN exit;
IF Length(S) = 0 THEN
BEGIN
S := Source;
exit;
END;
IF Index < 1 THEN Index := 1;
IF Index > Length(S) THEN Index := Length(S)+1;
S := copy(S,1,Index-1) + Source + copy(S,Index,Length(S)-Index+1);
END;
{$H+}
PROCEDURE Delete(VAR S:STRING; Index,Count:INTEGER);
BEGIN
IF Index < 1 THEN exit;
IF Index > Length(S) THEN exit;
IF Count < 1 THEN exit;
IF Index+Count > Length(S) THEN Count := Length(S)-Index+1;
S := copy(S,1,Index-1) + copy(S,Index+Count,Length(S)-Index-Count+1);
END;
FUNCTION ConvertStr2Long(VAR s:STRING):LONGINT;
VAR
c:Integer;
result:LONGINT;
BEGIN
VAL(s,result,c);
IF c<>0 THEN
BEGIN
END;
ConvertStr2Long:=result;
END;
{Liefert Extended in ST(0) !!}
PROCEDURE ConvertStr2Extended(VAR s:STRING);
VAR
c:Integer;
result:Extended;
BEGIN
VAL(s,result,c);
IF c<>0 THEN
BEGIN
END;
ASM
FLDT $result
END;
END;
FUNCTION GetStrErrorPos(VAR s:STRING):LONGINT;
VAR t,t1:BYTE;
BEGIN
result:=1;
t:=1;
IF t<=length(s) THEN IF s[t] IN ['+','-'] THEN inc(t);
IF t<=length(s) THEN IF s[t]='$' THEN inc(t);
FOR t1:=t TO length(s) DO
BEGIN
CASE s[t1] OF
'0'..'9':;
ELSE
BEGIN
result:=t1;
exit;
END;
END;
END;
END;
ASSEMBLER
SYSTEM.!Str2Long PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_11:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_11
CMP ECX,0
JE !do_11
DEC ECX
INC EDI
JMP !ndo_11 //skip spaces
!do_11:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_11_1
DEC ECX
POP EDI
JMP !do_11
!do_11_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !nohex
MOVD [EBP-10],16 //Base
CMP ECX,1
JE !qerr
DEC ECX
!nohex:
CMP AL,'-'
JNE !q2
CMP ECX,1
JE !qerr
DEC ECX
MOVB [EBP-6],1
!q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !qerr
CMP AL,57
JNA !noqerr
CMP AL,102
JA !qerr
CMP AL,65
JB !qerr
CMP AL,70
JBE !hexnum
CMP AL,97
JB !qerr
SUB AL,32 //To upper
!hexnum:
CMPD [EBP-10],16
JNE !qerr
SUB AL,7
!noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !q1
!qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !q3
!qqqq:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !q3
NEG EAX
!q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],EAX
LEAVE
RETN32 12
SYSTEM.!Str2Long ENDP
SYSTEM.!Str2Word PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_22:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_22
CMP ECX,0
JE !do_22
DEC ECX
INC EDI
JMP !ndo_22
!do_22:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_22_1
DEC ECX
POP EDI
JMP !do_22
!do_22_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !__nohex
MOVD [EBP-10],16 //Base
CMP ECX,1
JE !__qerr
DEC ECX
!__nohex:
CMP AL,'-'
JNE !__q2
CMP ECX,1
JE !__qerr
DEC ECX
MOVB [EBP-6],1
!__q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!__q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !__qerr
CMP AL,57
JNA !__noqerr
CMP AL,102
JA !__qerr
CMP AL,65
JB !__qerr
CMP AL,70
JBE !__hexnum
CMP AL,97
JB !__qerr
SUB AL,32 //To upper
!__hexnum:
CMPD [EBP-10],16
JNE !__qerr
SUB AL,7
!__noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !__q1
!__qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq1 //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !__q3
!qqqq1:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !__q3
NEG EAX
!__q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],AX
LEAVE
RETN32 12
SYSTEM.!Str2Word ENDP
SYSTEM.!Str2Byte PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
MOV EDI,[EBP+16] //s
MOV CL,[EDI+0] //Länge
MOVZX ECX,CL
!ndo_33:
MOV AL,[EDI+1]
CMP AL,32
JNE !do_33
CMP ECX,0
JE !do_33
DEC ECX
INC EDI
JMP !ndo_33
!do_33:
PUSH EDI
ADD EDI,ECX
CMPB [EDI+0],32
JNE !do_33_1
DEC ECX
POP EDI
JMP !do_33
!do_33_1:
POP EDI
MOVB [EBP-6],0
MOVD [EBP-10],10 //Base
MOV AL,[EDI+1]
ADD EDI,ECX
CMP AL,'$' //Hexadecimal ??
JNE !___nohex
CMP ECX,1
JE !___qerr
MOVD [EBP-10],16 //Base
DEC ECX
!___nohex:
CMP AL,'-'
JNE !___q2
CMP ECX,1
JE !___qerr
DEC ECX
MOVB [EBP-6],1
!___q2:
MOV EBX,1
MOV EAX,0
MOV [EBP-4],EAX
!___q1:
MOV AL,[EDI+0]
DEC EDI
CMP AL,48
JB !___qerr
CMP AL,57
JNA !___noqerr
CMP AL,102
JA !___qerr
CMP AL,65
JB !___qerr
CMP AL,70
JBE !___hexnum
CMP AL,97
JB !___qerr
SUB AL,32 //To upper
!___hexnum:
CMPD [EBP-10],16
JNE !___qerr
SUB AL,7
!___noqerr:
SUB AL,48
MOVZX EAX,AL
MUL EBX
MOV EDX,[EBP-4]
ADD EDX,EAX
MOV [EBP-4],EDX
MOV EAX,EBX
MOV EBX,[EBP-10] //Base
MUL EBX
MOV EBX,EAX
LOOP !___q1
!___qerr:
MOV EDI,[EBP+8] //result
XOR CH,CH
MOV [EDI+0],CX
// failure ??
CMP CX,0
JE !qqqq2 //no error
PUSHL [EBP+16] //s
CALLN32 SYSTEM.GetStrErrorPos
MOV EDI,[EBP+8]
MOV [EDI+0],EAX
MOV EAX,0
JMP !___q3
!qqqq2:
MOV EAX,[EBP-4]
CMPB [EBP-6],1
JNE !___q3
NEG EAX
!___q3:
MOV EDI,[EBP+12] //l
MOV [EDI+0],AL
LEAVE
RETN32 12
SYSTEM.!Str2Byte ENDP
END;
ASSEMBLER
SYSTEM.!AssignStr2Array PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //Destination Array
MOV ESI,[EBP+12] //Source String
MOVZXB ECX,[ESI+0]
INC ESI
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!AssignStr2Array ENDP
SYSTEM.!AssignCStr2Array PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+12] //Source CString
MOV EDI,ESI
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EDI,[EBP+8] //Destination Array
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!AssignCStr2Array ENDP
SYSTEM.!StrCopy PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination String
MOV ESI,[EBP+16] //Source String
MOV ECX,[EBP+8] //Maximum length
LODSB
CMP AL,CL
JBE _L1
MOV AL,CL
_L1:
STOSB
MOVZX ECX,AL
MOV EAX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EAX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP ECX
POP EAX
LEAVE
RETN32 12
SYSTEM.!StrCopy ENDP
SYSTEM.!AssignStr2PChar PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination CString
MOV ESI,[EBP+16] //Source String
MOV ECX,[EBP+8] //Maximum length
LODSB //get length of source string
MOVZX EAX,AL
CMP EAX,ECX
JB _L1_1
MOV EAX,ECX
_L1_1:
MOV ECX,EAX
MOV EDX,EAX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0
STOSB //terminate PChar
POP ESI
POP EDI
POP EDX
POP ECX
POP EAX
LEAVE
RETN32 12
SYSTEM.!AssignStr2PChar ENDP
SYSTEM.!AssignPChar2Str PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+16] //Source CString
MOV EDX,[EBP+8] //Maximum length
MOV EDI,ESI //Source CString
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EAX,ECX //length of source string
DEC EAX //without #0
MOV EDI,[EBP+12] //Destination String
CMP EAX,EDX
JB _L1_2
MOV EAX,EDX //set to maximum length
_L1_2:
MOV ECX,EAX
STOSB //set string length
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 12
SYSTEM.!AssignPChar2Str ENDP
SYSTEM.!CopyArrayStr PROC NEAR32
CLD
MOV EBX,ESP
MOV EDI,[EBX+12] //Destination String
MOV ESI,[EBX+16] //Source Array
MOV ECX,[EBX+8] //Maximum string length
DEC ECX //minus length byte
MOV EAX,[EBX+4] //Array length
CMP AL,CL
JBE _L11
MOV AL,CL
_L11:
STOSB //String length
MOV CL,AL
MOVZX ECX,CL
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
RETN32 16
SYSTEM.!CopyArrayStr ENDP
SYSTEM.!PCharCopy PROC NEAR32
CLD
MOV EBX,ESP
MOV EDI,[EBX+12] //Source
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX
MOV EDX,[EBX+4] //Maximum length
CMP EDX,ECX
JAE _re
MOV ECX,EDX
_re:
MOV ESI,[EBX+12] //Source
MOV EDI,[EBX+8] //Destination
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
RETN32 12
SYSTEM.!PCharCopy ENDP
SYSTEM.!PCharLength PROC NEAR32
MOV EBX,ESP
PUSH EBX
PUSH EDI
PUSH ECX
MOV EDI,[EBX+4] //Source
MOV ECX,$0FFFFFFFF
XOR AL,AL
CLD
REPNE
SCASB
NOT ECX
MOV EAX,ECX
DEC EAX //without #0
POP ECX
POP EDI
POP EBX
RETN32 4
SYSTEM.!PCharLength ENDP
SYSTEM.!StrAdd PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12] //Destination
MOV ESI,[EBP+8] //String to add
MOVZXB ECX,[EDI+0] //length of destination
CLD
LODSB //length of string to add
ADD [EDI+0],AL
JNC _lll1
MOVB [EDI+0],255
MOV AL,CL
NOT AL
_lll1:
ADD EDI,ECX
INC EDI
MOV CL,AL
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StrAdd ENDP
SYSTEM.!PCharAdd PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
CLD
MOV ESI,[EBP+8] //String to add
MOV EDI,[EBP+8] //String to add
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string to add
DEC ECX //without #0
MOV EBX,ECX
MOV EDI,[EBP+12] //Destination
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of destination
DEC ECX //without #0
MOV EDI,[EBP+12] //Destination
ADD EDI,ECX //add length to destination
MOV ECX,EBX //length of string to add
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0
STOSB //terminate PChar
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharAdd ENDP
SYSTEM.!Str2PChar PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,[EBP+8] //String to convert
MOV EDI,ESI
MOVZXB ECX,[ESI+0]
INC ESI
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
MOV AL,0 //terminate PChar
STOSB
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 4
SYSTEM.!Str2PChar ENDP
SYSTEM.!PChar2Str PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //string to convert
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX //used to set len
MOV ESI,[EBP+8]
ADD ESI,ECX //to last character of source
DEC ESI
MOV EDI,ESI
INC EDI //destination is 1 up
STD //move the bytes 1 up
REP
MOVSB
MOV AL,DL //set string length
STOSB
CLD
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32
SYSTEM.!PChar2Str ENDP
SYSTEM.!StringCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH ECX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
MOV ESI,[EBP+8]
LODSB
MOV AH,[EDI+0]
INC EDI
MOV CL,AL
CMP CL,AH
JBE _nl1
MOV CL,AH
_nl1:
OR CL,CL
JE _nl2
MOVZX ECX,CL
CLD
REP
CMPSB
JNE _nl3
_nl2:
CMP AL,AH
_nl3:
POP ESI
POP EDI
POP ECX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StringCmp ENDP
SYSTEM.!PCharCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8]
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12]
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX
MOV EDI,[EBP+12]
MOV ESI,[EBP+8]
CMP EBX,ECX
JNE _nl3_1
_nl1_1:
OR ECX,ECX
JE _nl2_1
CLD
REP
CMPSB
JNE _nl3_1
_nl2_1:
CMP EBX,EDX
_nl3_1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharCmp ENDP
SYSTEM.!StrPCharCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //PChar
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12] //Str
MOVZXB ECX,[EDI]
MOV EDX,ECX
MOV EDI,[EBP+12] //Str
INC EDI
MOV ESI,[EBP+8] //PChar
CMP EBX,ECX
JNE _nl3_1_r1
_nl1_1_r1:
OR ECX,ECX
JE _nl2_1_r1
CLD
REP
CMPSB
JNE _nl3_1_r1
_nl2_1_r1:
CMP EBX,EDX
_nl3_1_r1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!StrPCharCmp ENDP
SYSTEM.!PCharStrCmp PROC NEAR32
CLD
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV EDI,[EBP+8] //Str
MOVZXB ECX,[EDI]
MOV EBX,ECX //used to set len
MOV EDI,[EBP+12] //PChar
CLD
MOV ECX,$0FFFFFFFF
XOR AL,AL
REPNE
SCASB
NOT ECX //length of string
DEC ECX //without #0
MOV EDX,ECX
MOV EDI,[EBP+12] //PChar
MOV ESI,[EBP+8] //Str
INC ESI
CMP EBX,ECX
JNE _nl3_1_r2
_nl1_1_r2:
OR ECX,ECX
JE _nl2_1_r2
CLD
REP
CMPSB
JNE _nl3_1_r2
_nl2_1_r2:
CMP EBX,EDX
_nl3_1_r2:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.!PCharStrCmp ENDP
END;
//**************************************************************************
//
// Random support
//
//**************************************************************************}
CONST
Factor:WORD=$8405;
PROCEDURE Randomize;
VAR
d:RECORD
wYear:WORD;
wMonth:WORD;
wDayOfWeek:WORD;
wDay:WORD;
wHour:WORD;
wMinute:WORD;
wSecond:WORD;
wMilliseconds:WORD;
END;
BEGIN
GetSystemTime(d);
RandSeed:=(((d.wHour SHL 8)+d.wMinute) SHL 16)+
((d.wSecond SHL 8)+d.wMilliseconds);
END;
PROCEDURE NextRandom;
BEGIN
ASM
MOV AX,SYSTEM.RandSeed
MOV BX,SYSTEM.RandSeed+2
MOV CX,AX
MULW SYSTEM.Factor
SHL CX,3
ADD CH,CL
ADD DX,CX
ADD DX,BX
SHL BX,2
ADD DX,BX
ADD DH,BL
MOV CL,5
SHL BX,CL
ADD DH,BL
ADD AX,1
ADC DX,0
MOV SYSTEM.RandSeed,AX
MOV SYSTEM.RandSeed+2,DX
END;
END;
FUNCTION RANDOM(value:word):word;
BEGIN
ASM
CALLN32 SYSTEM.NextRandom
MOV CX,DX
MOV BX,$value
MUL BX
MOV AX,CX
MOV CX,DX
MUL BX
ADD AX,CX
ADC DX,0
MOV AX,DX
MOV $!FUNCRESULT,AX
END;
END;
FUNCTION FloatRandom:EXTENDED;
BEGIN
result:=Random(8192)/8192;
END;
//************************************************************************
//
//
// Direct Memory access support
//
//
//************************************************************************
PROCEDURE Move(CONST source; VAR dest; size:LONGWORD);ASSEMBLER;
ASM
MOV ESI,$Source
MOV EDI,$Dest
MOV ECX,$Size
CMP ESI,EDI
JE !MoveEnd
JA !MoveForw
MOV EBX,ESI
ADD EBX,ECX
CMP EBX,EDI // test overlapping
JBE !MoveForw
STD
ADD ESI,ECX
DEC ESI
ADD EDI,ECX
DEC EDI
REP
MOVSB
CLD
JMP !MoveEnd
!MoveForw:
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!MoveEnd:
END;
PROCEDURE SaveMove(VAR source; VAR dest; size:LONGWORD);ASSEMBLER;
ASM
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
MOV ESI,$Source
MOV EDI,$Dest
MOV ECX,$Size
CMP ESI,EDI
JE !MoveEnd_1
JA !MoveForw_1
MOV EBX,ESI
ADD EBX,ECX
CMP EBX,EDI // test overlapping
JBE !MoveForw_1
STD
ADD ESI,ECX
DEC ESI
ADD EDI,ECX
DEC EDI
REP
MOVSB
CLD
JMP !MoveEnd_1
!MoveForw_1:
CLD
MOV EDX,ECX
SHR ECX,2
REP
MOVSD
MOV ECX,EDX
AND ECX,3
REP
MOVSB
!MoveEnd_1:
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
END;
PROCEDURE CompareMem(VAR Buf1,Buf2;Size:LONGWORD);
BEGIN
ASM
CLD
MOV ESI,$Buf1
MOV EDI,$Buf2
MOV ECX,$Size
CLD
REP
CMPSB
END;
END;
PROCEDURE FILLCHAR(VAR dest;size:LongWord;value:byte);ASSEMBLER;
ASM
CLD
//Note: Stack is dword aligned !
MOV EDI,$Dest //Destination pointer
MOV ECX,$Size //count
CMP ECX,0
JE !ex_fillc
MOV AL,$Value //Value
MOV AH,AL
PUSH AX
PUSH AX
POP EAX
MOV EDX,ECX
SHR ECX,2
REP
STOSD
MOV ECX,EDX
AND ECX,3
REP
STOSB
!ex_fillc:
END;
//Set Support
ASSEMBLER
SYSTEM.TestInSet32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Set (32 Byte)
MOV AX,[EBP+12] //Byte or char value
MOV BX,16
XOR EDX,EDX
DIV BX //Calculate Word position
SHL AX,1
MOVZX EAX,AX
ADD EDI,EAX
MOV AX,DX //Bit Position [0..15]
SHL AX,1
MOVZX EAX,AX
MOV EBX,*SetTab_11
ADD EBX,EAX
MOV AX,[EBX+0] //Bit value
MOV BX,[EDI+0] //Old Value
AND AX,BX
CMP AX,0
JE !tis1 //not found
MOV AX,0 //test successful
CMP AX,0
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
!tis1:
MOV AX,1 //item not found
CMP AX,0
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SetTab_11 dw 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768
SYSTEM.TestInSet32 ENDP
SYSTEM.SetAssign32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ECX,8
MOV EAX,0
CLD
REP
STOSD
MOV EDI,[EBP+8] //Ziel
MOV ECX,[EBP+12] //Parameter count
CMP CX,0
JE !NSAs //only clear set
MOVZX ECX,CX
LEA ESI,[EBP+16] //Points to first parameter
!plo:
PUSH ECX
MOV ECX,[ESI+0] //Get parameter repeat
CMP ECX,0
JG !rr4
JE !NSAs
MOVSX ECX,CX
INC ECX
SUB ECX,[ESI+4]
JLE !NSAs
!rr4:
MOV EAX,[ESI+4] //Get value of parameter
ADD ESI,8 //to next parameter for next loop
!plo_rep:
XOR AH,AH
PUSH AX //store parameter value
MOV BX,16
XOR EDX,EDX
DIV BX //Calculate Word position
SHL AX,1
MOVZX EAX,AX
ADD EDI,EAX
MOV AX,DX //Bit Position [0..15]
SHL AX,1
MOVZX EAX,AX
MOV EBX,*SetTab
ADD EBX,EAX
MOV AX,[EBX+0]
MOVZX EAX,AX
MOV BX,[EDI+0] //Old Value
OR AX,BX
MOV [EDI+0],AX //Store new value
MOV EDI,[EBP+8] //Ziel
POP AX //get parameter repeat
INC AX //next parameter if it is parameter..parameter
LOOP !plo_rep
POP ECX
LOOP !plo //until all parameters processed
!NSAs:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8 //Return to caller
SetTab dw 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768
SYSTEM.SetAssign32 ENDP
SYSTEM.SetOr32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ESI,[EBP+12]
MOV ECX,8
!SAndl_1:
MOV EAX,[ESI+0]
OR EAX,[EDI+0]
MOV [EDI+0],EAX
ADD ESI,4
ADD EDI,4
LOOP !SAndl_1
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.SetOr32 ENDP
SYSTEM.TempSetOr32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
CMP ECX,0
JE !EndSetOr
LEA ESI,[EBP+16] //First Parameter
!TSAl_1:
PUSHL [ESI+4] //Value
MOV EAX,[ESI+0] //repeat count
//CMP EAX,0
//JG !rr1
//JE !EndSetOr2 //Error
//MOVSX EAX,AX
//INC EAX
//SUB EAX,[ESI+4]
//JLE !EndSetOr2 //Error
!rr1:
PUSH EAX //repeat count
ADD ESI,8
LOOP !TSAl_1
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
PUSH ECX
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!EndSetOr2:
MOV EAX,[EBP-36] //Old ESP
MOV ESP,EAX
LEA EAX,[EBP-32]
PUSH EAX
MOV EAX,[EBP+8] //Ziel
PUSH EAX
CALLN32 SYSTEM.SetOr32
!EndSetOr:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetOr32 ENDP
SYSTEM.SetAnd32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8] //Ziel
MOV ESI,[EBP+12]
MOV ECX,8
!SAndl:
MOV EAX,[ESI+0]
AND EAX,[EDI+0]
MOV [EDI+0],EAX
ADD ESI,4
ADD EDI,4
LOOP !SAndl
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.SetAnd32 ENDP
SYSTEM.TempSetAnd32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
CMP ECX,0
JNE !TSAW
MOV EDI,[EBP+8] //Ziel
MOV ECX,8
MOV EAX,0
CLD
REP
STOSD
JMP !TempSetAndE
!TSAW:
LEA ESI,[EBP+16] //First Parameter
!TSAl:
PUSHL [ESI+4] //value
MOV EAX,[ESI+0] //repeat count
//CMP EAX,0
//JG !rr2
//JE !TempSetAndE2 //Error
//MOVSX EAX,AX
//INC EAX
//SUB EAX,[ESI+4]
//JLE !TempSetAndE2 //Error
!rr2:
PUSH EAX //repeat count
ADD ESI,8
LOOP !TSAl
MOV CL,[EBP+12] //Count
MOVZX ECX,CL
PUSH ECX
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!TempSetAndE2:
MOV EAX,[EBP-36] //old ESP
MOV ESP,EAX
LEA EAX,[EBP-32]
PUSH EAX
MOV EAX,[EBP+8] //Ziel
PUSH EAX
CALLN32 SYSTEM.SetAnd32
!TempSetAndE:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetAnd32 ENDP
SYSTEM.TempSetCompare32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,36
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV [EBP-36],ESP
MOV EDI,[EBP+8] //Ziel
MOV ECX,[EBP+12] //Count
LEA ESI,[EBP+16] //First Parameter
CMP ECX,0 //empty set
JNE !TCSAl_2
//test empty set
MOV EAX,0
MOV ECX,8
CLD
REPE
SCASD
CMP ECX,0
JMP !ex_comp
!TCSAl_2:
PUSHL [ESI+4] //Value
MOV EAX,[ESI+0]
//CMP EAX,0
//JG !rr3
//JE !ex_comp2 //Error
//MOVSX EAX,AX
//SUB EAX,[ESI+4]
//JLE !ex_comp2 //Error
!rr3:
PUSH EAX //Repeat count
ADD ESI,8
LOOP !TCSAl_2
PUSHL [EBP+12] //Count
LEA EAX,[EBP-32]
PUSH EAX
CALLN32 SYSTEM.SetAssign32
!ex_comp2:
MOV EAX,[EBP-36] //old ESP
MOV ESP,EAX
CLD
LEA ESI,[EBP-32]
MOV EDI,[EBP+8]
MOV ECX,32
CLD
REP
CMPSB
!ex_comp:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 8
SYSTEM.TempSetCompare32 ENDP
SYSTEM.NegateSet32 PROC NEAR32
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EDI,[EBP+8]
MOV ECX,8
!NS_l:
MOV EAX,[EDI+0]
NOT EAX
MOV [EDI+0],EAX
ADD EDI,4
LOOP !NS_l
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
LEAVE
RETN32 4
SYSTEM.NegateSet32 ENDP
END;
//************************************************************************
//
//
// VMT and object handling support
//
//
//************************************************************************
{$IFOPT D-}
{$D+}
{$ELSE}
{$DEFINE WASDEBUG}
{$ENDIF}
ASSEMBLER
SYSTEM.!VMTCall PROC NEAR32
MOV EBX,ESP
MOV EDI,[EBX+4]
MOV EDI,[EDI+0]
CMP EDI,0
JNE !VmtWeiter
MOV EDI,[EBX+4]
CMPD [EDI+4],0
JNE !VmtConstructor
PUSHL 214
CALLN32 SYSTEM.RunError
!VmtConstructor:
MOV EDI,[EDI+4]
!VmtWeiter:
LEA EDI,[EDI+EAX*4]
JMP [EDI+0]
SYSTEM.!VMTCall ENDP
END;
{$IFNDEF WASDEBUG}
{$D-}
{$ENDIF}
{$UNDEF WASDEBUG}
//************************************************************************
//
//
// Floating point support
//
//
//************************************************************************
PROCEDURE SetTrigMode(mode:BYTE);
BEGIN
CASE Mode OF
Rad:IsNotRad:=FALSE;
Deg:
BEGIN
ToRad:=0.01745329262;
FromRad:=57.29577951;
IsNotRad:=TRUE;
END;
Gra:
BEGIN
ToRad:=0.01570796327;
FromRad:=63.66197724;
IsNotRad:=TRUE;
END;
END; {case}
END;
ASSEMBLER
SYSTEM.!FormatStr PROC NEAR32 //Format in AL, String in EDI
//Format the string
CMP AL,0
JE !LLw47_1
MOV AH,[EDI+0] //Length of string
CMP AH,AL
JAE !LLw47_1 //No format to do
SUB AL,AH //Calculate spaces to add
ADD [EDI+0],AL //Set length to new value
PUSH EDI
MOVZX EBX,AH //old length of string
ADD EDI,EBX //End of string
MOVZX EBX,AL //Count of spaces to add
MOV ESI,EDI
ADD EDI,EBX //add count of spaces
MOVZX ECX,AH //Count (Length of string) to ECX
INC ECX //and #0
STD //From backwards
REP
MOVSB
MOV ECX,EBX
MOV AL,32 //Space
POP EDI //Pop it
PUSH EDI
INC EDI
CLD
REP
STOSB
POP EDI
MOVZXB EAX,[EDI+0]
INC EDI
ADD EDI,EAX
CLD
!LLw47_1:
RETN32
SYSTEM.!FormatStr ENDP
SYSTEM.!RadArc PROC NEAR32 //Converts ST(0) to Rad
CMPB SYSTEM.IsNotRad,1
JNE !!!_l80
FLDT SYSTEM.ToRad
FMULP ST(1),ST
!!!_l80:
RETN32
SYSTEM.!RadArc ENDP
SYSTEM.!NormRad PROC NEAR32 //Converts ST(0) to actual TrigMode
CMPB SYSTEM.IsNotRad,1
JNE !!!_l81
FLDT SYSTEM.FromRad
FMULP ST(1),ST
!!!_l81:
RETN32
SYSTEM.!NormRad ENDP
SYSTEM.!Calculate PROC NEAR32
//Input EDI String
//CX Count
//Output Value in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,4
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
!!!weiter1:
MOV AL,[EDI+0]
SUB AL,$3a
ADD AL,$0a
JNB !!!ex
XOR AH,AH
MOV [EBP-2],AX
FILDD SYSTEM.C10
FMULP ST(1),ST
FILDW [EBP-2]
FADDP ST(1),ST
FWAIT
INC EDI
DEC CX
CMP CX,0
JE !!!ex
JMP !!!weiter1
!!!ex:
LEAVE
RETN32
SYSTEM.!Calculate ENDP
SYSTEM.!DivTab PROC NEAR32
dw 0,0,0,32768,16383,0,0,0 //1
dw 0,0,0,40960,16386,0,0,0 //10
dw 0,0,0,51200,16389,0,0,0 //100
dw 0,0,0,64000,16392,0,0,0 //1000
dw 0,0,0,40000,16396,0,0,0 //10^4
dw 0,0,0,50000,16399,0,0,0 //10^5
dw 0,0,0,62500,16402,0,0,0 //10^6
dw 0,0,32768,39062,16406,0,0,0 //10^7
dw 0,0,8192,48828,16409,0,0,0 //10^8
SYSTEM.!DivTab ENDP
SYSTEM.!Power10Tab PROC NEAR32
db 0,0,0,0,0,$20,$bc,$be,$19,$40 //1.0E+8
db 0,0,0,4,$bf,$c9,$1b,$8e,$34,$40 //1.0E+16
db $9e,$b5,$70,$2b,$a8,$ad,$c5,$9d,$69,$40 //1.0E+32
db $d5,$a6,$cf,$0ff,$49,$1f,$78,$c2,$d3,$40 //1.0E+64
db $e0,$8c,$e9,$80,$c9,$47,$ba,$93,$a8,$41 //1.0E+128
db $8e,$de,$0f9,$9d,$0fb,$eb,$7e,$aa,$51,$43 //1.0E+256
db $c7,$91,$0e,$a6,$ae,$a0,$19,$e3,$a3,$46 //1.0E+512
db $17,$0c,$75,$81,$86,$75,$76,$c9,$48,$4d //1.0E+1024
db $e5,$5d,$3d,$c5,$5d,$3b,$8b,$9e,$92,$5a //1.0E+2048
db $9b,$97,$20,$8a,2,$52,$60,$c4,$25,$75 //1.0E+4096
SYSTEM.!Power10Tab ENDP
SYSTEM.!MaxMulTab PROC NEAR32
db $9b,$97,$20,$8a,2,$52,$60,$c4,$25,$75 //1.0E+4096
SYSTEM.!MaxMulTab ENDP
SYSTEM.!DivMul10 PROC NEAR32
//Input: BX Count of divides/mult by 10
// AL 0-mult 1-divide
MOV CX,BX
AND CX,7 //31 only values 0..31
MOV ESI,@SYSTEM.!DivTab
MOVZX ECX,CX
SHL ECX,1
SHL ECX,1
SHL ECX,1
SHL ECX,1
ADD ESI,ECX
FLDT [ESI+0] //1..10^32 laden
SHR BX,1
SHR BX,1
SHR BX,1 //divide numbers by 8
MOV ESI,@SYSTEM.!Power10Tab
CMP BX,0
JE !!!process
!!!Power10:
SHR BX,1
JNB !!!mm //until a bit is set
FLDT [ESI+0]
FMULP ST(1),ST
!!!mm:
ADD ESI,10
CMP BX,0
JNE !!!Power10
!!!process:
CMP AL,1
JNE !!!_mul
FDIVP ST(1),ST
RETN32
!!!_mul:
FMULP ST(1),ST
RETN32
SYSTEM.!DivMul10 ENDP
SYSTEM.!Str2Float PROC NEAR32
//Input EDI String to convert
// CX Length of this string
//Output Floating point value in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,6 //for Control word and sign
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTCW [EBP-2] //Store control word
FWAIT
FCLEX //Clear exceptions
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FLDZ //Load +0.0
MOVB [EBP-4],0 //sign is positive
MOVW [EBP-6],0 //count of numbers after point
!!!again:
CMP CX,0 //String has zero length ?
JE !!!Error
MOV AL,[EDI+0] //load character
CMP AL,43 //'+'
JNE !!!not_plus
//Sign '+' was detected
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!weiter
!!!not_plus:
CMP AL,45 //'-'
JNE !!!not_minus
//Sign '-' was detected
MOVB [EBP-4],1 //Sign is negative
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!weiter
!!!not_minus:
CMP AL,32
JNE !!!weiter
INC EDI
DEC CX
JMP !!!again
!!!weiter:
CALLN32 SYSTEM.!Calculate //Calculate numbers before point
CMP CX,0
JNE !!!a_exp
CMPB [EBP-4],1
JNE !!!no_exp
FCHS
FWAIT //change sign
JMP !!!no_exp
!!!a_exp:
//Look for .
MOV AL,[EDI+0]
CMP AL,'.'
JNE !!!Change
DEC CX
INC EDI
PUSH CX
CALLN32 SYSTEM.!Calculate //Calculate numbers after point
POP BX
SUB BX,CX
MOV [EBP-6],BX //Count of numbers after point
!!!Change:
//in ST(0) is now an integer value
//[EBP-6] contains the current numbers after the point
CMPB [EBP-4],1
JNE !!!not_neg
FCHS
FWAIT //change sign
!!!not_neg:
//Check for exponent
CMP CX,0
JE !!!no_exp
MOV AL,[EDI+0]
CMP AL,'e'
JE !!!exp
CMP AL,'E'
JNE !!!no_exp
!!!exp:
//an exponent was detected
INC EDI
DEC CX
CMP CX,0
JE !!!Error
FLDZ //Load +0.0
MOVB [EBP-4],0 //sign is positive
MOV AL,[EDI+0]
CMP AL,'-'
JNE !!!no_minus
MOVB [EBP-4],1 //sign is negative
INC EDI
DEC CX
CMP CX,0
JE !!!Error
JMP !!!Calc
!!!no_minus:
CMP AL,43 //'+'
JNE !!!calc
INC EDI
DEC CX
CMP CX,0
JE !!!Error
!!!calc:
CALLN32 SYSTEM.!Calculate
FISTPW SYSTEM.Exponent //Store integer value and pop
MOV BX,SYSTEM.Exponent
MOV AL,0 //Mult
CMPB [EBP-4],1
JNE !!!make
MOV AL,1 //Divide if Exponent negative
!!!make:
PUSH CX
CALLN32 SYSTEM.!DivMul10
POP CX
!!!no_exp:
CMP CX,0
JNE !!!Error //invalid chars
MOV BX,[EBP-6]
MOV AL,1 //Divide
CALLN32 SYSTEM.!DivMul10
JMP !!!ok
!!!Error:
MOVW SYSTEM.IoResult,1 //FPU error
!!!ok:
LEAVE
RETN32
SYSTEM.!Str2Float ENDP
SYSTEM.!Str2Real PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2Float
MOV EDI,[EBP+12]
FSTPD [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex1
MOVW [EDI+0],1
!!__fex1:
LEAVE
RETN32 12
SYSTEM.!Str2Real ENDP
SYSTEM.!Str2Double PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2Float
MOV EDI,[EBP+12]
FSTPQ [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex11
MOVW [EDI+0],1
!!__fex11:
LEAVE
RETN32 12
SYSTEM.!Str2Double ENDP
SYSTEM.!Str2Extended PROC NEAR32
PUSH EBP
MOV EBP,ESP
MOV EDI,[EBP+16]
MOV CL,[EDI+0]
INC EDI
XOR CH,CH
CALLN32 SYSTEM.!Str2FLoat
MOV EDI,[EBP+12]
FSTPT [EDI+0]
MOV EDI,[EBP+8] //Result
MOVW [EDI+0],0
CMPW SYSTEM.FPUResult,0
JE !!__fex111
MOVW [EDI+0],1
!!__fex111:
LEAVE
RETN32 12
SYSTEM.!Str2Extended ENDP
SYSTEM.!ValReal PROC NEAR32
//Input EDI : Destination String
//AX Kommastellen
//BX Len oder 17h
//Floatvalue in ST(0)
PUSH EBP
MOV EBP,ESP
SUB ESP,264
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
$result EQU [EBP-256]
$len EQU [EBP-258]
$comma EQU [EBP-260]
$s EQU [EBP-264]
MOV $comma,AX
CMP BX,0
JA !!6666
MOV BX,1
!!6666:
CMP BX,254 //$17
JB !!6666_1
MOV BX,$17
!!6666_1:
MOV $len,BX
MOV $s,EDI
MOV CX,$comma
OR CX,CX
JNS !!37ea
MOV CX,8
SUB CX,$len
CMP CX,$0FFFE
JLE !!37ea
MOV CX,$0FFFE
!!37ea:
LEA EDI,$result
CALLN32 SYSTEM.!Real2Str1 //Get string in EDI and length in CX
MOV ESI,EDI
MOV EDI,$s
MOV DX,255
MOV AX,$len
CMP AX,CX
JNL !!3812
MOV AX,CX
!!3812:
CLD
STOSB
SUB AX,CX
JE !!3820
PUSH CX
MOVZX ECX,AX
MOV AL,$20
REP
STOSB
POP CX
!!3820:
MOVZX ECX,CX
REP
MOVSB
LEAVE
RETN32
SYSTEM.!ValReal ENDP
SYSTEM.!!!!!Help1 PROC NEAR32
FWAIT
FSTCW [EBP-2]
FWAIT
FCLEX
FLDCW SYSTEM.FpuControl
FWAIT
FSTPT [EBP-$14]
XOR EDX,EDX
CMP CX,$12
JLE !!311a
MOV CX,$12
!!311a:
CMP CX,$0FFEE
JNL !!3122
MOV CX,$0FFEE
!!3122:
RETN32
SYSTEM.!!!!!Help1 ENDP
SYSTEM.!!!!!Help2 PROC NEAR32
MOV [EBP-$0c],AX
FLDT [EBP-$14]
SUB AX,$3FFF
XOR EDX,EDX
MOV DX,$4D10
IMUL DX
MOV [EBP-8],DX
MOV AX,$11
SUB AX,DX
CALLN32 SYSTEM.!Div_Mul10
FRNDINT
MOV ESI,*Tabx1
FLDT [ESI+0]
FCOMP ST(1)
FSTSW [EBP-4]
FWAIT
RETN32
Tabx1:
db 0,0,$40,$76,$3a,$6b,$0b,$de,$3a,$40
SYSTEM.!!!!!Help2 ENDP
SYSTEM.!!!!!Help3 PROC NEAR32
MOV AL,$45
STOSB
MOV AL,$2b
MOV DX,[EBP-8]
OR DX,DX
JNS !!3280
MOV AL,$2d
NEG DX
!!3280:
STOSB
MOV EAX,$640a
XCHG DX,AX
DIV DH
MOV DH,AH
DB $66
CBW
DIV DL
ADD AX,$3030
STOSW
MOV AL,DH
DB $66
CBW
DIV DL
ADD AX,$3030
STOSW
RETN32
SYSTEM.!!!!!Help3 ENDP
SYSTEM.!Real2Str1 PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,$28
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EDI
CALLN32 SYSTEM.!!!!!Help1
CLD
NOP
FWAIT
MOV [EBP-6],CX
MOV AX,[EBP-$0c]
MOV [EBP-$0a],AX
AND AX,$7FFF
JE !!315c
CMP AX,$7FFF
JNE !!3165
CMPW [EBP-$0e],$8000
JE !!3149
MOV AX,$414e
STOSW
MOV AL,$4e
STOSB
JMP !!3299
!!3149:
CMPW [EBP-$0a],0
JNS !!3152
MOV AL,$2d
STOSB
!!3152:
MOV AX,$4e49
STOSW
MOV AL,$46
STOSB
JMP !!3299
!!315c:
MOV [EBP-8],AX
MOV [EBP-$28],AL
JMP !!3216
!!3165:
CALLN32 SYSTEM.!!!!!Help2
TESTW [EBP-4],$4100
JE !!31a1
INCW [EBP-8]
FILDD SYSTEM.C10
FDIVP ST(1),ST
!!31a1:
PUSH EBP
POP ESI
FBSTPT [ESI-$14]
MOV ESI,9
LEA EBX,[EBP-$28]
MOV CL,4
FWAIT
!!31af:
PUSH EDI
LEA EDI,[EBP-$15]
ADD EDI,ESI
MOV AL,[EDI+0]
POP EDI
MOV AH,AL
SHR AL,CL
AND AH,$0F
ADD AX,$3030
MOV [EBX+0],AX
ADD EBX,2
DEC ESI
JNE !!31af
MOV [EBX+0],SI
CMPW [EBP-6],0
JL !!31d8
CMPW [EBP-8],$24
JL !!31d8
MOVW [EBP-6],$0FFEE
!!31d8:
MOV SI,[EBP-6]
OR SI,SI
JS !!31eb
ADD SI,[EBP-8]
INC SI
JNS !!31ed
MOVB [EBP-$28],0
JMP !!3216
!!31eb:
NEG SI
!!31ed:
CMP SI,$12
JNB !!3216
MOVZX ESI,SI
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
CMPB [EDI+0],$35
MOVB [EDI+0],0
POP EDI
JB !!3216
!!31fc:
DEC SI
JS !!320e
MOVZX ESI,SI
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INCB [EDI+0]
CMPB [EDI+0],$39
POP EDI
JBE !!3216
PUSH EDI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOVB [EDI+0],0
POP EDI
JMP !!31fc
!!320e:
INCW [EBP-8]
MOVW [EBP-$28],$31
!!3216:
XOR ESI,ESI
MOV DX,[EBP-6]
OR DX,DX
JS !!3254
CMPW [EBP-$0a],0
JNS !!3228
MOV AL,$2d
STOSB
!!3228:
MOV CX,[EBP-8]
OR CX,CX
JNS !!3234
MOV AL,$30
STOSB
JMP !!323b
!!3234:
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOV AL,[EDI+0]
INC SI
POP EDI
OR AL,AL
JNE !!32b6
MOV AL,$30
DEC SI
!!32b6:
STOSB
DEC CX
JNS !!3234
!!323b:
OR DX,DX
JE !!3299
MOV AL,$2e
STOSB
!!3242:
INC CX
JE !!324b
!!3245:
MOV AL,$30
STOSB
DEC DX
JNE !!3242
!!324b:
DEC DX
JS !!3299
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
MOV AL,[EDI+0]
INC SI
POP EDI
OR AL,AL
JNE !!32b6_1a
MOV AL,$30
DEC SI
!!32b6_1a:
STOSB
JMP !!324b
!!3254:
MOV AL,$20
CMPW [EBP-$0a],0
JNS !!325e
MOV AL,$2d
!!325e:
STOSB
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INC SI
MOV AL,[EDI+0]
POP EDI
OR AL,AL
JNE !!32b6_1b
MOV AL,$30
DEC SI
!!32b6_1b:
STOSB
INC DX
JE !!3270
MOV AL,$2e
STOSB
!!3269:
PUSH EDI
MOVZX ESI,SI
LEA EDI,[EBP-$28]
ADD EDI,ESI
INC SI
MOV AL,[EDI+0]
POP EDI
OR AL,AL
JNE !!32b6_1c
MOV AL,$30
DEC SI
!!32b6_1c:
STOSB
INC DX
JNE !!3269
!!3270:
CALLN32 SYSTEM.!!!!!Help3
!!3299:
MOV ECX,EDI
POP EDI
SUB ECX,EDI
FCLEX //Clear Exceptions
FLDCW [EBP-2]
FWAIT
LEAVE
RETN32
{*Tab1:
db 0,0,40h,76h,3ah,6bh,0bh,deh,3ah,40h}
SYSTEM.!Real2Str1 ENDP
SYSTEM.!Div_Mul10 PROC NEAR32
CMP AX,$1000
JLE !!3382
PUSH ESI
MOV ESI,@SYSTEM.!MaxMulTab
FLDT [ESI+0]
POP ESI
FMULP ST(1),ST
SUB AX,$1000
!!3382:
CMP AX,$0F000
JNL !!3393
PUSH ESI
MOV ESI,@SYSTEM.!MaxMulTab
FLDT [ESI+0]
POP ESI
FDIVP ST(1),ST
ADD AX,$1000
!!3393:
MOV BX,AX
OR AX,AX
JE !!33d4
JNS !!339d
NEG AX
!!339d:
MOV SI,AX
AND SI,7
MOVZX ESI,SI
SHL ESI,1
SHL ESI,1
SHL ESI,1
SHL ESI,1
PUSH EDI
MOV EDI,@SYSTEM.!DivTab
ADD EDI,ESI
FLDT [EDI+0]
POP EDI
SHR AX,1
SHR AX,1
SHR AX,1
MOV ESI,@SYSTEM.!Power10Tab
JMP !!33c5
!!33b7:
SHR AX,1
JNB !!33c2
FLDT [ESI+0]
FMULP ST(1),ST
!!33c2:
ADD ESI,10
!!33c5:
OR AX,AX
JNE !!33b7
OR BX,BX
JS !!33d1
FMULP ST(1),ST
!!33d0:
RETN32
!!33d1:
FDIVP ST(1),ST
!!33d4:
RETN32
SYSTEM.!Div_Mul10 ENDP
SYSTEM.!Real2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDD [EDI+0] //Load real value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOVZXB EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 12
SYSTEM.!Real2Str ENDP
SYSTEM.!Double2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDQ [EDI+0] //Load double value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOV EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 12
SYSTEM.!Double2Str ENDP
SYSTEM.!Extended2Str PROC NEAR32 //Format in [EBP+16]
PUSH EBP
MOV EBP,ESP
PUSH EDI
PUSH ESI
MOV EDI,[EBP+12]
FLDT [EDI+0] //Load extended value
MOV EDI,[EBP+8]
MOV EAX,[EBP+16] //Nachkommastellen (FFFFh alle)
MOV EBX,[EBP+20] //Format value
CALLN32 SYSTEM.!ValReal
MOV AL,[EBP+20] //Format value
MOV EDI,[EBP+8]
CALLN32 SYSTEM.!FormatStr
POP ESI
POP EDI
LEAVE
RETN32 16
SYSTEM.!Extended2Str ENDP
SYSTEM.!WriteExtended PROC NEAR32 //Writes extended in ST
PUSH EBP
MOV EBP,ESP
SUB ESP,260
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-260]
PUSHL [EBP+12] //Format
PUSHL [EBP+8] //Nachkommas
LEA EAX,[EBP-260]
PUSH EAX
LEA EAX,[EBP-250]
PUSH EAX
CALLN32 SYSTEM.!Extended2Str
LEA EAX,[EBP-250]
PUSH EAX
PUSHL 0 //[EBP+8] ??? //Format value
CALLN32 SYSTEM.StrWrite
LEAVE
RETN32 8
SYSTEM.!WriteExtended ENDP
SYSTEM.!FPULoadLong PROC NEAR32
PUSH EBP
MOV EBP,ESP
FILDD [EBP+8]
LEAVE
RETN32 4
SYSTEM.!FPULoadLong ENDP
SYSTEM.!Sin PROC NEAR32 //calculate SIN in ST(0)
CALLN32 SYSTEM.!RadArc
FSIN
RETN32
SYSTEM.!Sin ENDP
SYSTEM.!Cos PROC NEAR32 //calculate COS in ST(0)
CALLN32 SYSTEM.!RadArc
FCOS
RETN32
SYSTEM.!Cos ENDP
SYSTEM.!Tan PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Sin
FLDT [EBP-10]
CALLN32 SYSTEM.!Cos
FTST
FSTSW [EBP-12]
FWAIT
MOV AH,[EBP-11]
SAHF
JNE !!!_l50
FSTP ST(0)
FSTP ST(0)
FLDZ
MOVW SYSTEM.FPUResult,2
JMP !!!_l51
!!!_l50:
FDIVP ST(1),ST
!!!_l51:
POP EAX
LEAVE
RETN32
SYSTEM.!Tan ENDP
SYSTEM.!Cot PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Cos
FLDT [EBP-10]
CALLN32 SYSTEM.!Sin
FTST
FSTSW [EBP-12]
FWAIT
MOV AH,[EBP-11]
SAHF
JNE !!!_l53
FSTP ST(0)
FSTP ST(0)
FLDZ
MOVW SYSTEM.FPUResult,2
JMP !!!_l54
!!!_l53:
FDIVP ST(1),ST
!!!_l54:
POP EAX
LEAVE
RETN32
SYSTEM.!Cot ENDP
SYSTEM.!ArcTan PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,4
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH ECX
MOVW SYSTEM.FPUResult,0
FXAM //Type of ST(0)
FWAIT
FSTSW [EBP-2]
MOV AH,[EBP-1]
SAHF
XCHG CX,AX
JB !!!_l30
JNE !!!_l31
JMP !!!_l32
!!!_l30:
JE !!!_l32
JNP !!!_l32
FSTP ST(0)
FLDT SYSTEM.fl3
JMP !!!_l33
!!!_l31:
FABS
FLD1
FCOM ST(1)
FWAIT
FSTSW [EBP-2]
MOV AH,[EBP-1]
SAHF
JNE !!!_l34
FCOMPP
FLDT SYSTEM.fl2
JMP !!!_l33
!!!_l34:
JNB !!!_l35
FXCH ST(1)
!!!_l35:
FPATAN
JNB !!!_l33
FLDT SYSTEM.fl3
FSUBP ST(1),ST
XOR CH,2
!!!_l33:
TEST CH,2
JE !!!_l32
FCHS
FWAIT
!!!_l32:
CALLN32 SYSTEM.!NormRad
POP ECX
POP EAX
LEAVE
RETN32
SYSTEM.!ArcTan ENDP
SYSTEM.!Sqrt PROC NEAR32
FSQRT
RETN32
SYSTEM.!Sqrt ENDP
SYSTEM.!ln PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLDLN2
FXCH ST(1)
FXAM
FWAIT
FSTSW [EBP-10]
MOV AH,[EBP-9]
SAHF
JB !!!_l20
JE !!!_l21
TEST AH,2
JE !!!_l22
!!!_l21:
FSTP ST(0)
JMP !!!_l23
!!!_l20:
FSTP ST(0)
JE !!!_l24
JNP !!!_l24
!!!_l23:
FSTP ST(0)
FLDD SYSTEM.fl1
!!!_l24:
FTST
JMP !!!_l29
!!!_l22:
FLD ST(0)
FSTPT [EBP-10]
CMPW [EBP-2],$3fff
JNE !!!_l25
CMPW [EBP-4],$8000
JNE !!!_l25
FLD1
FSUBP ST(1),ST
FYL2XP1
JMP !!!_l29
!!!_l25:
FYL2X
!!!_l29:
POP EAX
LEAVE
RETN32
SYSTEM.!ln ENDP
SYSTEM.!Exp PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,16
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
PUSH EBX
PUSH ECX
MOVW SYSTEM.FPUResult,0
FLDL2E
FXCH ST(1)
FXAM
FWAIT
FSTSW [EBP-6]
FXCH ST(1)
MOV AH,[EBP-5]
SAHF
XCHG BX,AX
JB !!!_l40
JNE !!!_l41
FSTP ST(0)
FSTP ST(0)
FLD1
JMP !!!_l43
!!!_l40:
FSTP ST(0)
JE !!!_l44
JNP !!!_l44
!!!_l48:
FSTP ST(0)
FLDD SYSTEM.fl4
!!!_l44:
FTST
JMP !!!_l43
!!!_l41:
FMULP ST(1),ST
FABS
FLDD SYSTEM.fl5
FXCH ST(1)
FSTPT [EBP-16]
FLDT [EBP-16]
FCOMPP
FWAIT
FSTSW [EBP-6]
FLDT [EBP-16]
TESTB [EBP-5],$41
JE !!!_l46
F2XM1
FLD1
FADDP ST(1),ST
FWAIT
JMP !!!_l47
!!!_l46:
FLD1
FLD ST(1)
FWAIT
FSTCW [EBP-6]
FSCALE
ORB [EBP-5],$0f
FLDCW [EBP-6]
FWAIT
FRNDINT
ANDB [EBP-5],$0f3
FLDCW [EBP-6]
FWAIT
FISTD [EBP-4]
FXCH ST(1)
FCHS
FXCH ST(1)
FSCALE
FSTP ST(1)
FSUBP ST(1),ST
CMPW [EBP-2],0
JG !!!_l48
F2XM1
FLD1
FADDP ST(1),ST
FWAIT
MOV CX,[EBP-4]
SHR CX,1
MOV [EBP-4],CX
JNB !!!_l49
FLDT SYSTEM.fl6
FMULP ST(1),ST
!!!_l49:
FILDW [EBP-4]
FXCH ST(1)
FSCALE
FSTP ST(1)
!!!_l47:
TEST BH,2
JE !!!_l43
FLD1
FDIVRP ST(1),ST
!!!_l43:
POP ECX
POP EBX
POP EAX
LEAVE
RETN32
SYSTEM.!Exp ENDP
SYSTEM.!Frac PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-10]
FLDT [EBP-10]
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FLDT [EBP-10]
FXCH ST(1)
FSUBP ST(1),ST
LEAVE
RETN32
SYSTEM.!Frac ENDP
SYSTEM.!Int PROC NEAR32
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
RETN32
SYSTEM.!Int ENDP
SYSTEM.!Round PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FSTPT [EBP-10]
FLDT [EBP-10]
CALLN32 SYSTEM.!Frac
FLDT [EBP-10]
FADDP ST(1),ST
CALLN32 SYSTEM.!Trunc
LEAVE
RETN32
SYSTEM.!Round ENDP
SYSTEM.!Trunc PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,10
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
FCLEX
FLDCW SYSTEM.FPURound //Load control word
FWAIT
FRNDINT
FCLEX
FLDCW SYSTEM.FPUControl //Load control word
FWAIT
FISTPD [EBP-10]
MOV EAX,[EBP-10]
LEAVE
RETN32
SYSTEM.!Trunc ENDP
SYSTEM.!Sqr PROC NEAR32
FLD St(0)
FMULP ST(1),ST
RETN32
SYSTEM.!Sqr ENDP
SYSTEM.!ArcSin PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLD St(0)
FABS
FLD1
FCOMPP
FWAIT
FSTSW [EBP-12]
MOV AH,[EBP-11]
SAHF
JB !!!_l60
JNE !!!_l62
//ArcSin(1.0)=w*pi/2
FLDT SYSTEM.fl7 //1.5707...
FMULP ST(1),ST
JMP !!!_l61
!!!_l62:
FLD St(0)
FSTPT [EBP-10]
FLD St(0)
FMULP ST(1),ST
FLD1
FSUBP ST(1),ST
FSQRT
FLDT [EBP-10]
FXCH ST(1)
FDIVP ST(1),ST
CALLN32 SYSTEM.!ArcTan
JMP !!!_l61
!!!_l60:
MOVW SYSTEM.FPUResult,3
!!!_l61:
CALLN32 SYSTEM.!NormRad
POP EAX
LEAVE
RETN32
SYSTEM.!ArcSin ENDP
SYSTEM.!ArcCos PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ArcSin
FLDT SYSTEM.fl7 //PI/2
FXCH ST(1)
FSUBP ST(1),ST
CALLN32 SYSTEM.!NormRad
RETN32
SYSTEM.!ArcCos ENDP
SYSTEM.!ArcCot PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ArcTan
FLDT SYSTEM.fl7 //PI/2
FXCH ST(1)
FSUBP ST(1),ST
CALLN32 SYSTEM.!NormRad
RETN32
SYSTEM.!ArcCot ENDP
SYSTEM.!Sinh PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!Exp
FLD St(0)
FLD1
FXCH ST(1)
FDIVP ST(1),ST
FXCH ST(1)
FSUBP ST(1),ST
FLDT SYSTEM.fl8
FMULP ST(1),ST
RETN32
SYSTEM.!Sinh ENDP
SYSTEM.!Cosh PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!Exp
FLD St(0)
FLD1
FXCH ST(1)
FDIVP ST(1),ST
FADDP ST(1),ST
FWAIT
FLDT SYSTEM.fl8
FMULP ST(1),ST
RETN32
SYSTEM.!Cosh ENDP
SYSTEM.!Tanh PROC NEAR32
MOVW SYSTEM.FPUResult,0
FLDT SYSTEM.fl9 //2.0
FMULP ST(1),ST
CALLN32 SYSTEM.!Exp
FLD1
FADDP ST(1),ST
FWAIT
FLDT SYSTEM.fl9 //2.0
FXCH ST(1)
FDIVP ST(1),ST
FLD1
FSUBP ST(1),ST
RETN32
SYSTEM.!Tanh ENDP
SYSTEM.!Coth PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,12
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
PUSH EAX
MOVW SYSTEM.FPUResult,0
FLD St(0)
FSTPT [EBP-10]
CALLN32 SYSTEM.!Sinh
FTST
FWAIT
FSTSW [EBP-12]
MOV AH,[EBP-11]
SAHF
JE !!!_l70
FLDT [EBP-10]
CALLN32 SYSTEM.!Cosh
FXCH ST(1)
FDIVP ST(1),ST
JMP !!!_l71
!!!_l70:
MOVW SYSTEM.FPUResult,4
!!!_l71:
POP EAX
LEAVE
RETN32
SYSTEM.!Coth ENDP
SYSTEM.!lg PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ln
FLDT SYSTEM.fl10
FDIVP ST(1),ST
RETN32
SYSTEM.!lg ENDP
SYSTEM.!lb PROC NEAR32
MOVW SYSTEM.FPUResult,0
CALLN32 SYSTEM.!ln
FLDT SYSTEM.fl11
FDIVP ST(1),ST
RETN32
SYSTEM.!lb ENDP
SYSTEM.!ReadReal PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Real
LEAVE
RETN32 4
SYSTEM.!ReadReal ENDP
SYSTEM.!ReadDouble PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Double
LEAVE
RETN32 4
SYSTEM.!ReadDouble ENDP
SYSTEM.!ReadExtended PROC NEAR32
PUSH EBP
MOV EBP,ESP
SUB ESP,262
DB $89,$04,$24 //Perform stack probe MOV [ESP],EAX
LEA EAX,[EBP-260]
PUSH EAX
CALLN32 SYSTEM.StrRead
LEA EAX,[EBP-260]
PUSH EAX
PUSHL [EBP+8]
LEA EAX,[EBP-262]
PUSH EAX
CALLN32 SYSTEM.!Str2Extended
LEAVE
RETN32 4
SYSTEM.!ReadExtended ENDP
END;
{**************************************************************************
*
* Screen IO
*
**************************************************************************}
//TextScreen IO support
TYPE ProcVar=PROCEDURE;
PROCEDURE TPMScreenInOutClass.Error;
BEGIN
MessageBox(0,'Win95 GUI linker target does not support textscreen I/O'#13+
'Use the Unit WINCRT if you wish to use'#13
'textscreen I/O within GUI applications','Error',0);
Halt(0);
END;
PROCEDURE TPMScreenInOutClass.WriteStr(CONST s:STRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.WriteCStr(CONST s:CSTRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.WriteLF;
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.ReadLF(VAR s:STRING);
BEGIN
Error;
END;
PROCEDURE TPMScreenInOutClass.GotoXY(x,y:BYTE);
BEGIN
Error;
END;
PROCEDURE TScreenInOutClass.WriteStr(CONST s:STRING);
VAR
actual:LONGWORD;
by,by1:LONGWORD;
Handle:LONGWORD;
b:BYTE;
ff:^FileRec;
s1,s2:STRING;
x,y:LONGINT;
Fill:WORD;
csbi:CONSOLE_SCREEN_BUFFER_INFO;
coPos:COORD;
sr:SMALL_RECT;
ci:CHAR_INFO;
LABEL l,l1;
BEGIN
ff:=@Output;
Handle:=ff^.Handle;
IF RedirectOut THEN goto l1;
s1:=s;
b:=Pos(#13#10,s1);
WHILE b<>0 DO
BEGIN
s2:=s1;
s1:=copy(s1,1,b-1);
WriteStr(s1);
s1:=#13#10;
WriteFile(ff^.Handle,s1[1],length(s1),actual,NIL);
GetConsoleScreenBufferInfo(ff^.Handle,csbi);
y:=csbi.dwCursorPosition.Y+1;
IF y-1>Hi(WindMax) THEN
BEGIN
{Scroll window}
Fill:= TextAttr;
sr.Left:=lo(WindMin);
sr.Right:=lo(WindMax)+1;
sr.Top:=hi(WindMin)+1;
sr.Bottom:=hi(WindMax);
coPos.X:=lo(WindMin);
coPos.Y:=hi(WindMin);
ci.Char.AsciiChar:=#32;
ci.Attributes:=Fill;
ScrollConsoleScreenBuffer(ff^.Handle,sr,NIL,LONGWORD(coPos),ci);
dec(y);
END;
GotoXY(1,y-Hi(WindMin));
s1:=copy(s2,b+2,length(s2)-(b+1));
b:=Pos(#13#10,s1);
END;
GetConsoleScreenBufferInfo(ff^.Handle,csbi);
x:=csbi.dwCursorPosition.X+1;
IF length(s1)>(Lo(WindMax)-Lo(WindMin)-
(x-lo(WindMin)))+1 THEN
BEGIN
by:=(Lo(WindMax)-Lo(WindMin)-(x-lo(WindMin)))+2;
by1:=length(s1)-by;
l:
WriteFile(ff^.Handle,s1[1],by,actual,NIL);
s1:=copy(s1,by+1,length(s1)-by);
IF ((WindMin<>MaxWindMin)OR(WindMax<>MaxWindMax)) THEN WriteLF;
GetConsoleScreenBufferInfo(ff^.Handle,csbi);
x:=csbi.dwCursorPosition.X+1;
IF length(s1)>(Lo(WindMax)-Lo(WindMin)-(x-lo(WindMin)))+1 THEN
BEGIN
by:=(Lo(WindMax)-Lo(WindMin)-(x-lo(WindMin)))+2;
by1:=length(s1)-by;
goto l;
END;
WriteFile(ff^.Handle,s1[1],by1,actual,NIL);
exit;
END;
l1:
WriteFile(ff^.Handle,s1[1],length(s1),actual,NIL);
END;
PROCEDURE TScreenInOutClass.WriteCStr(CONST s:CSTRING);
VAR
c:STRING;
b:LONGWORD;
pc:^CSTRING;
LABEL l;
BEGIN
pc:=@s;
l:
b:=Length(pc^);
IF b<255 THEN
BEGIN
c:=pc^;
WriteStr(c);
END
ELSE
BEGIN
move(pc^,c[1],255);
c[0]:=#255;
inc(pc,255);
WriteStr(c);
goto l;
END;
END;
PROCEDURE TScreenInOutClass.WriteLF;
VAR y:BYTE;
Fill:WORD;
coPos:COORD;
csbi:CONSOLE_SCREEN_BUFFER_INFO;
ff:^FileRec;
Actual:LONGWORD;
sr:SMALL_RECT;
ci:CHAR_INFO;
s:STRING;
BEGIN
s:=#13#10;
ff:=@Output;
WriteFile(ff^.Handle,s[1],length(s),actual,NIL);
GetConsoleScreenBufferInfo(ff^.Handle,csbi);
y:=csbi.dwCursorPosition.Y+1;
IF y-1>Hi(WindMax) THEN
BEGIN
{Scroll window}
Fill:= TextAttr;
{Scroll window}
sr.Left:=lo(WindMin);
sr.Right:=lo(WindMax);
sr.Top:=hi(WindMin)+1;
sr.Bottom:=hi(WindMax);
coPos.X:=lo(WindMin);
coPos.Y:=hi(WindMin);
ci.Char.AsciiChar:=#32;
ci.Attributes:=Fill;
ScrollConsoleScreenBuffer(ff^.Handle,sr,NIL,LONGWORD(coPos),ci);
dec(y);
END;
GOTOXY(1,y-Hi(WindMin));
END;
PROCEDURE TScreenInOutClass.ReadLF(VAR s:STRING);
VAR ff:^FileRec;
Actual:LONGWORD;
BEGIN
ff:=@Input;
ReadFile(ff^.Handle,s[1],255,Actual,NIL);
s[0]:=chr(Actual);
IF s[length(s)]=#10 THEN dec(s[0]);
IF s[length(s)]=#13 THEN dec(s[0]);
END;
PROCEDURE TScreenInOutClass.GotoXY(x,y:BYTE);
VAR coPos:COORD;
ff:^FileRec;
BEGIN
X:=X-1+Lo(WindMin);
Y:=Y-1+Hi(WindMin);
IF (X<=Lo(WindMax))and(Y<=Hi(WindMax)) THEN
BEGIN
ff:=@Output;
coPos.X:=X;
coPos.Y:=Y;
SetConsoleCursorPosition(ff^.Handle,LONGWORD(coPos));
END;
END;
PROCEDURE StrWrite(CONST s:STRING;format:LONGWORD);
VAR ss:STRING;
p:^STRING;
BEGIN
IF Format+Length(s)>255 THEN Format:=255-length(s);
IF format>length(s) THEN
BEGIN
format:=format-length(s);
ss[0]:=chr(format+length(s));
fillchar(ss[1],format,32);
p:=@s;
move(p^[1],ss[format+1],length(s));
ScreenInOut.WriteStr(ss);
END
ELSE ScreenInOut.WriteStr(s);
END;
PROCEDURE CStrWrite(CONST s:CSTRING;format:LONGWORD);
VAR ss:CSTRING;
p:^CSTRING;
l:LONGWORD;
BEGIN
l:=length(s);
IF ((format>l)AND(l+format<255)) THEN
BEGIN
format:=format-l;
fillchar(ss[0],format,32);
p:=@s;
move(p^[0],ss[format],l+1);
ScreenInOut.WriteCStr(ss);
END
ELSE ScreenInOut.WriteCStr(s);
END;
PROCEDURE WriteLine;
BEGIN
ScreenInOut.WriteLF;
END;
PROCEDURE ReadLine;
VAR
s:STRING;
BEGIN
ScreenInOut.ReadLF(s);
END;
PROCEDURE StrRead(VAR s:STRING);
BEGIN
ScreenInOut.ReadLF(s);
END;
CONST
Typ_String = 1;
Typ_Char = 2;
Typ_Number = 3;
PROCEDURE GetNextStr(VAR s,Ziel:STRING;Typ:LONGWORD);
VAR t:BYTE;
LABEL l;
BEGIN
IF s='' THEN
BEGIN
StrRead(s);
s:=s+#13#10;
END;
Ziel:='';
CASE Typ OF
Typ_String:
BEGIN
{copy whole}
IF s=#13#10 THEN Ziel:=''
ELSE
BEGIN
Ziel:=Copy(s,1,length(s)-2);
s:=#13#10;
END;
END;
Typ_Char:
BEGIN
Ziel:=s[1];
Delete(s,1,1);
END;
Typ_Number:
BEGIN
l:
IF length(s)<3 THEN {am Zeilenende ??}
BEGIN
StrRead(s);
s:=s+#13#10;
END;
{Skip spaces}
IF s[1]=#32 THEN
BEGIN
Delete(s,1,1);
goto l;
END;
FOR t:=1 TO length(s) DO
BEGIN
CASE s[t] OF
#9,#13,#10,#32: {Trennzeichen}
BEGIN
Ziel:=Copy(s,1,t-1);
Delete(s,1,t-1); {Trenner nicht mit löschen}
exit;
END;
END; {case}
END;
END;
END; {case}
END;
//************************************************************************
//
// File IO
//
//
//************************************************************************
VAR
FileBufSize:LONGWORD; {Standard file buffer size (32768 bytes}
PROCEDURE Assign(VAR f:FILE;CONST s:String);
VAR ff:^FileRec;
BEGIN
ff:=@f;
fillchar(f,sizeof(f),0);
ff^.Name:=s; {Assign name to file variable}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
ff^.MaxCacheMem:=FileBufSize; {Initial bufsize}
ff^.Buffer:=NIL;
IF ff^.MaxCacheMem<16 THEN ff^.MaxCacheMem:=16;
IOResult:=0; {Clear IOResult variable}
END;
PROCEDURE InvalidFileNameError(Adr:LONGINT);
VAR
e:EInvalidFileName;
BEGIN
e.Create('Invalid file name (EInvalidFileName)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
e.ErrorCode:=206; {filename exceeds range}
RAISE e;
END;
PROCEDURE InOutError(Code,Adr:LONGWORD);
VAR
e:EInOutError;
BEGIN
e.Create('Input/Output error (EInOutError)');
e.ErrorCode:=code;
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
RAISE e;
END;
CONST
{Modes for FileBlockIO}
ReadMode = 1;
WriteMode = 2;
PROCEDURE FileBlockIO(VAR f:FILE;BlockNr:LONGWORD;Mode:LONGWORD;
VAR result:LONGWORD);
VAR
l:LONGWORD;
po:LONGWORD;
temp:LONGWORD;
ff:^FileRec;
BEGIN
ff:=@f;
IOResult:=0;
IF ff^.changed THEN
BEGIN
ff^.changed:=FALSE;
FileBlockIO(f,ff^.block,WriteMode,Temp);
IF IOResult<>0 THEN exit;
END;
IF blocknr=ff^.LBlock THEN l:=ff^.LOffset
ELSE l:=ff^.MaxCacheMem;
po:=ff^.MaxCacheMem*blocknr;
Temp:=SetFilePointer(ff^.Handle,po,NIL,0); //Seek from file begin
IF Temp=$ffffffff THEN
BEGIN
IoResult:=GetLastError;
exit;
END;
IF l>0 THEN
BEGIN
CASE Mode OF
WriteMode:
BEGIN
IF not WriteFile(ff^.Handle,ff^.Buffer^,l,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
END;
END;
ReadMode:
BEGIN
IF not ReadFile(ff^.Handle,ff^.Buffer^,l,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
END;
END;
END; {case}
END;
END;
FUNCTION FileFileSize(VAR f:FILE):LONGWORD;
VAR
ff:^FileRec;
Temp,Temp1,Temp2:LONGWORD;
BEGIN
ff:=@f;
IOResult:=0;
Temp:=SetFilePointer(ff^.Handle,0,NIL,1); //get current pos
IF Temp=$ffffffff THEN
BEGIN
IOResult:=GetLastError;
exit;
END;
Temp1:=SetFilePointer(ff^.Handle,0,NIL,2); //get length
IF Temp1=$ffffffff THEN
BEGIN
IOResult:=GetLastError;
exit;
END;
Temp2:=SetFilePointer(ff^.Handle,Temp2,NIL,0); //restore position
IF Temp2=$ffffffff THEN
BEGIN
IOResult:=GetLastError;
exit;
END;
FileFileSize:=Temp1;
END;
FUNCTION FileFilePos(VAR f:FILE):LONGWORD;
VAR
ff:^FileRec;
Temp:LONGWORD;
BEGIN
ff:=@f;
IOResult:=0;
Temp:=SetFilePointer(ff^.Handle,0,NIL,1);
IF Temp=$ffffffff THEN
BEGIN
IOResult:=GetLastError;
exit;
END;
FileFilePos:=Temp;
END;
VAR OpenedFiles:ARRAY[1..51] OF LONGWORD; {Handles for opened files}
OpenedFilesCount:BYTE;
PROCEDURE Rewrite(VAR f:FILE;recsize:LONGWORD);
VAR
action:LONGWORD;
ff:^FileRec;
c:CSTRING;
e:EFileNotFound;
Size,Temp:LONGWORD;
SaveIOError:BOOLEAN;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IOResult:=0;
ff:=@f;
ff^.RecSize:=recsize;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle<>$ffffffff THEN
BEGIN
{Close file first}
SaveIoError:=RaiseIOError;
RaiseIOError:=FALSE;
Close(f);
RaiseIoError:=SaveIoError;
(*IOResult:=85; {File already assigned}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
END;
ff^.Buffer:=NIL;
c:=ff^.Name;
{for rewrite no extended attributes can be determined - use reset !}
ff^.Handle:=CreateFile(c,FileMode AND not 3,FileMode AND 3,NIL,2,$00000080,0);
IF ff^.Handle=-1 THEN
BEGIN
IOResult:=GetLastError;
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN
BEGIN
e.Create('File not found (EFileNotFound)');
e.ErrorCode:=IoResult;
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
RAISE e;
END
ELSE exit;
END;
ff^.Mode:=FileMode;
ff^.Reserved1:=0;
{Set the buffer values}
size:=FileFileSize(f);
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF OpenedFilesCount<50 THEN inc(OpenedFilesCount);
OpenedFiles[OpenedFilesCount]:=ff^.Handle;
getmem(ff^.Buffer,ff^.MaxCacheMem);
ff^.LBlock:=size DIV ff^.MaxCacheMem;
ff^.LOffset:=size MOD ff^.MaxCacheMem;
FileBlockIO(f,0,readmode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Block:=0;
ff^.Offset:=0;
END;
PROCEDURE Reset(VAR f:FILE;recsize:LONGWORD);
VAR
action:LONGWORD;
ff:^FileRec;
c:CSTRING;
p:POINTER;
e:EFileNotFound;
size,Temp:LONGWORD;
SaveIoError:BOOLEAN;
Adr:LONGINT;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IOResult:=0;
ff:=@f;
ff^.RecSize:=recsize;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle<>$ffffffff THEN
BEGIN
{Close file first}
SaveIoError:=RaiseIOError;
RaiseIOError:=FALSE;
Close(f);
RaiseIoError:=SaveIoError;
(*IOResult:=85; {File already assigned}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
END;
ff^.Buffer:=NIL;
c:=ff^.Name;
{open and read extended attributes}
ff^.Handle:=CreateFile(c,FileMode AND not 3,FileMode AND 3,NIL,3,$00000080,0);
IF ff^.Handle=-1 THEN
BEGIN
IOResult:=GetLastError;
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN
BEGIN
e.Create('File not found (EFileNotFound)');
e.CameFromRTL:=TRUE;
e.RTLExcptAddr:=POINTER(Adr);
e.ErrorCode:=IoResult;
RAISE e;
END
ELSE exit;
END;
ff^.EAS:=NIL;
ff^.Mode:=FileMode;
ff^.Reserved1:=0;
{Set the buffer values}
size:=FileFileSize(f);
IF IOResult<>0 THEN
BEGIN
ff^.Handle:=$ffffffff;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF OpenedFilesCount<50 THEN inc(OpenedFilesCount);
OpenedFiles[OpenedFilesCount]:=ff^.Handle;
getmem(ff^.Buffer,ff^.MaxCacheMem);
ff^.LBlock:=size DIV ff^.MaxCacheMem;
ff^.LOffset:=size MOD ff^.MaxCacheMem;
FileBlockIO(f,0,readmode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Block:=0;
ff^.Offset:=0;
END;
PROCEDURE Close(VAR f:FILE);
VAR
ff:^FileRec;
Temp:LONGWORD;
t:BYTE;
Adr:LONGINT;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IF not CloseHandle(ff^.Handle) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Mode:=0; {closed}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
exit;
END;
IOResult:=0;
{Write buffer to file}
IF ff^.changed THEN
BEGIN
ff^.changed:=FALSE;
FileBlockIO(F,ff^.block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
FOR t:=1 TO OpenedFilesCount DO
BEGIN
IF OpenedFiles[t]=ff^.Handle THEN
BEGIN
move(OpenedFiles[t+1],OpenedFiles[t],(50-t)*4);
dec(OpenedFilesCount);
goto l;
END;
END;
l:
IF not CloseHandle(ff^.Handle) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.Mode:=0; {closed}
ff^.Flags:=$6666; {File successfully assigned}
ff^.Handle:=$ffffffff; {No valid handle}
{free file buffers}
IF ff^.Buffer<>NIL THEN FreeMem(ff^.Buffer,ff^.MaxCacheMem);
ff^.Buffer:=NIL;
END;
PROCEDURE CloseAllOpenedFiles;
VAR t:BYTE;
BEGIN
FOR t:=1 TO OpenedFilesCount DO CloseHandle(OpenedFiles[t]);
OpenedFilesCount:=0;
END;
PROCEDURE Seek(VAR f:FILE;n:LONGINT);
VAR
ff:^FileRec;
result:LONGWORD;
pBlock:LONGWORD;
POffset:LONGWORD;
Temp:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
n:=n*ff^.RecSize;
CASE SeekMode OF
Seek_Current:inc(n,FilePos(f)*ff^.RecSize); //Seek_Current
Seek_End:inc(n,FileSize(f)*ff^.RecSize); //Seek_End
END;
IOResult:=0;
pblock:=n DIV ff^.maxcachemem;
poffset:=n MOD ff^.maxcachemem;
IF n>ff^.loffset+ff^.maxcachemem*ff^.lblock THEN
BEGIN
IF ff^.Mode AND (fmOutput OR fmInOut)<>0 THEN
BEGIN
ff^.loffset:=poffset;
ff^.lblock:=pblock;
END
ELSE
BEGIN
IOResult:=38; {Illegal pos}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
IF pblock<>ff^.block THEN
BEGIN
FileBlockIO(f,pblock,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
ff^.offset:=poffset;
ff^.block:=pblock;
END;
FUNCTION FilePos(var f:file):LongWord;
VAR
ff:^FileRec;
result:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IOResult:=0;
result:=ff^.block*ff^.maxcachemem+ff^.offset;
FilePos:=result DIV ff^.RecSize;
END;
FUNCTION Eof(var f:file):Boolean;
VAR
old,size:LONGWORD;
ff:^FIleRec;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Reserved1 AND 1=1 THEN
BEGIN
eof:=TRUE;
exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IOResult:=0;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
size:=FileFileSize(f);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF ((f=Input)OR(f=Output)) THEN
BEGIN
Eof:=FALSE;
exit;
END
ELSE
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END
ELSE
BEGIN
Eof:=Size=FileFilePos(f);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
exit;
END;
IOResult:=0;
Eof:=(ff^.offset=ff^.loffset)AND(ff^.block=ff^.lblock);
END;
FUNCTION Eoln(VAR F:Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
Offset:LONGINT;
Value:BYTE;
SaveIoError:BOOLEAN;
Res:LONGWORD;
t:BYTE;
s:STRING;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF eof(f) THEN
BEGIN
result:=TRUE;
exit;
END;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
Seek(f,FilePos(f)-1);
RaiseIOError:=SaveIOError;
IF Res=0 THEN Value:=26; {EOF}
END;
END
ELSE value:=fi^.Buffer^[Offset];
IF value IN [13,10,26] THEN result:=TRUE
ELSE result:=FALSE;
END;
FUNCTION FileSize(var f:file):LongWord;
VAR
old,old1,result:LONGWORD;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IOResult:=0;
result:=ff^.lblock*ff^.maxcachemem+ff^.loffset;
FileSize:=result DIV ff^.RecSize;
END;
PROCEDURE Truncate(VAR f:FILE);
VAR
l:LONGWORD;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF not SetEndOfFile(ff^.Handle) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.lOffset:=ff^.Offset;
ff^.lBlock:=ff^.Block;
END;
PROCEDURE Append(VAR f:Text);
VAR
l:LONGWORD;
saveseek:LONGWORD;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
Reset(f,1);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
l:=Filesize(f);
IF ioresult=0 THEN
BEGIN
SaveSeek:=seekmode;
seekmode:=0; {from file begin}
Seek(f,l);
seekmode:=saveseek;
END
ELSE
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE ChDir(CONST path:STRING);
VAR c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
c:=path;
IF not SetCurrentDirectory(c) THEN
BEGIN
IoResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE GetDir(drive:byte;VAR path:STRING);
VAR
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
IF Drive<>0 THEN
BEGIN
IOresult:=1; //not supported yet
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
GetCurrentDirectory(255,c);
path:=c;
END;
PROCEDURE RmDir(CONST dir:STRING);
VAR
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
c:=Dir;
IF not RemoveDirectory(c) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE MkDir(CONST dir:STRING);
VAR
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
c:=dir;
IF not CreateDirectory(c,NIL) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE FileExpand(VAR f:FILE);
VAR
ff:^FileRec;
BEGIN
ff:=@f;
inc(ff^.LOffset);
IF ff^.LOffset=ff^.MaxCacheMem THEN
BEGIN
inc(ff^.LBlock);
ff^.LOffset:=0;
END;
END;
VAR
BlockReadResult,BlockWriteResult:LONGWORD;
PROCEDURE BlockRead(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
VAR
ff:^FileRec;
pp:P_FileBuffer;
t,t1:LONGWORD;
Temp:LONGWORD;
Offset,Size:LONGWORD;
OldBlock,OldOfs:LONGINT;
MaxCacheMem:LONGWORD;
Adr:LONGINT;
BEGIN
IF Count=0 THEN
BEGIN
result:=0;
exit;
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
pp:=@Buf;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IF not ReadFile(ff^.Handle,pp^,Count*ff^.RecSize,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
exit;
END;
result:=0;
Offset:=ff^.Offset;
Size:=Count*ff^.RecSize;
MaxCacheMem:=ff^.MaxCacheMem;
IF Size>MaxCacheMem THEN
BEGIN
{Block ist größer als Cache}
IF (ff^.Block*MaxCacheMem)+Offset+Size>(ff^.LBlock*MaxCacheMem)+ff^.LOffset THEN
Size:=((ff^.LBlock*MaxCacheMem)+ff^.LOffset)-
((ff^.Block*MaxCacheMem)+Offset);
IF ff^.Changed THEN
BEGIN
ff^.Changed:=FALSE;
OldBlock:=ff^.LBlock; {temporaray save}
OldOfs:=ff^.LOffset;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=Offset;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.LBlock:=OldBlock;
ff^.LOffset:=OldOfs;
END
ELSE
BEGIN
Temp:=SetFilePointer(ff^.Handle,
(ff^.Block*MaxCacheMem)+Offset,NIL,0);
IF Temp=$ffffffff THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
IF not ReadFile(ff^.Handle,Buf,Size,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
size:=result; {tatsächlich gelesen}
{set file buffer}
Temp:=Offset+size;
t:=Temp MOD MaxCacheMem;
IF size<MaxCacheMem THEN
BEGIN
move(pp^[size-t],ff^.Buffer^,t);
inc(ff^.Block,Temp DIV MaxCacheMem);
ff^.Offset:=t;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
END
ELSE
BEGIN
{nächsten Block lesen}
ff^.Changed:=FALSE;
inc(ff^.Block,Temp DIV MaxCacheMem);
FileBlockIO(f,ff^.block,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.offset:=t;
END;
IF ff^.Block>ff^.LBlock THEN
BEGIN
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
END;
result:=result DIV ff^.RecSize;
exit;
END;
IF ff^.block=ff^.LBlock THEN
BEGIN
IF Offset+size<ff^.LOffset THEN
BEGIN
{im letzten Block}
move(ff^.Buffer^[Offset],pp^,size);
inc(ff^.Offset,size);
inc(result,size);
result:=result DIV ff^.RecSize;
exit;
END;
END
ELSE
BEGIN
{irgendwo vor dem letzten Block}
IF Offset+Size<MaxCacheMem THEN
BEGIN
move(ff^.Buffer^[Offset],pp^,size);
inc(ff^.Offset,size);
inc(result,size);
result:=result DIV ff^.RecSize;
exit;
END;
END;
ff^.reserved1:=ff^.reserved1 and not 1;
FOR t:=1 TO Size DO
BEGIN
IF eof(f) THEN
BEGIN
result:=result DIV ff^.RecSize;
exit;
END;
pp^[t-1]:=ff^.Buffer^[ff^.offset];
inc(ff^.offset);
inc(result);
IF ff^.offset=maxcachemem THEN
BEGIN
FileBlockIO(f,ff^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
ff^.offset:=0;
inc(ff^.block);
END;
END;
result:=result DIV ff^.RecSize;
END;
PROCEDURE BlockWrite(VAR f:file;var Buf;Count:LongWord;VAR result:LONGWORD);
VAR
ff:^FileRec;
pp:P_FileBuffer;
t,t1,Temp:LONGWORD;
value:BYTE;
size:LONGWORD;
Offset:LONGWORD;
OldBlock,OldOfs:LONGINT;
Adr:LONGINT;
LABEL l,l1;
BEGIN
IF Count=0 THEN
BEGIN
result:=0;
exit;
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
pp:=@Buf;
IOResult:=0;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF ff^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF ff^.Buffer=NIL THEN
BEGIN
IF not WriteFile(ff^.Handle,pp^,Count*ff^.RecSize,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
exit;
END;
result:=0;
IOResult:=0;
size:=Count*ff^.RecSize;
Offset:=ff^.Offset;
IF ff^.block=ff^.LBlock THEN
BEGIN
IF Offset=ff^.LOffset THEN
BEGIN
{am ende der Datei (im letzten Block und an LOffset)}
IF Offset+size<ff^.MaxCacheMem THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(ff^.LOffset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END
ELSE
BEGIN
{Groesse geht über alten Block hinaus}
l:
ff^.Changed:=FALSE;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
l1:
IF not WriteFile(ff^.Handle,Buf,Size,result,NIL) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
size:=result; {Tatsächlich geschrieben}
{set file buffer}
Temp:=Offset+size;
t:=Temp MOD ff^.MaxCacheMem;
move(pp^[size-t],ff^.Buffer^,t);
inc(ff^.Block,Temp DIV ff^.MaxCacheMem);
ff^.Offset:=t;
{we are at the end of the file}
ff^.LBlock:=ff^.Block;
ff^.LOffset:=ff^.Offset;
result:=result DIV ff^.RecSize;
exit;
END;
END
ELSE
BEGIN
{im letzten Block aber nicht an LOffset}
IF Offset+size<ff^.LOffset THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END;
{ELSE goto l;}
END;
END
ELSE
BEGIN
{irgendwo vor dem letzten Block}
IF Offset+Size<ff^.MaxCacheMem THEN
BEGIN
move(pp^,ff^.Buffer^[Offset],size);
inc(ff^.Offset,size);
inc(result,size);
ff^.Changed:=TRUE;
result:=result DIV ff^.RecSize;
exit;
END;
END;
(* IF Offset+Size>(ff^.LBlock*ff^.MaxCacheMem)+ff^.LOffset THEN
BEGIN
ff^.Changed:=FALSE;
OldBlock:=ff^.LBlock; {temporaray save}
OldOfs:=ff^.LOffset;
ff^.LBlock:=ff^.Block;
ff^.LOffset:=Offset;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult)
ELSE exit;
END;
ff^.LBlock:=OldBlock;
ff^.LOffset:=OldOfs;
goto l1;
END;*)
ff^.reserved1:=ff^.reserved1 and not 1;
FOR t:=1 TO size DO
BEGIN
value:=pp^[t-1];
IF value<>ff^.Buffer^[ff^.offset] THEN
BEGIN
ff^.Buffer^[ff^.offset]:=value;
ff^.Changed:=TRUE;
END;
IF EOF(f) THEN
BEGIN
ff^.changed:=TRUE;
FileExpand(f);
END;
inc(ff^.Offset);
inc(Result);
IF ff^.Offset=ff^.MaxCacheMem THEN
BEGIN
ff^.Changed:=FALSE;
{alten Block Schreiben}
FileBlockIO(f,ff^.Block,WriteMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
{neuen Block lesen}
ff^.Offset:=0;
inc(ff^.Block);
FileBlockIO(f,ff^.Block,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
END;
result:=result DIV ff^.RecSize;
END;
PROCEDURE Rename(VAR f:file;NewName:String);
VAR
c,c1:CSTRING;
ff:^FileRec;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
c:=NewName;
c1:=ff^.Name;
IF not MoveFile(c1,c) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE Erase(VAR f:file);
VAR
ff:^FileRec;
c:CSTRING;
Adr:LONGINT;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ff:=@f;
IF ff^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
c:=ff^.name;
IF not DeleteFile(c) THEN
BEGIN
IOResult:=GetLastError;
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE SetFileBuf(VAR f:FILE;VAR Buf;BufSize:LONGWORD);
BEGIN
IF BufSize<4096 THEN BufSize:=4096;
END;
PROCEDURE SetTextBuf(VAR f:TEXT;VAR Buf;BufSize:LONGWORD);
BEGIN
if BufSize>16*1024 then SetFileBuf(F,Buf,BufSize);
END;
PROCEDURE StrWriteText({VAR f:FILE}CONST s:STRING;format:LONGWORD);
VAR
fi:^FILE;
ss:STRING;
fillup:BYTE;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
END;
IF Format+Length(s)>255 THEN Format:=255-length(s);
IF format>length(s) THEN
BEGIN
fillup:=format-length(s); {erst soviele Leerzeichen}
fillchar(ss[0],fillup,32);
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,ss[0],fillup);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
{must do this in ASM because s is constant parameter}
ASM
PUSHL $fi
MOV EDI,$s
INC EDI
PUSH EDI
DEC EDI
MOVZXB EAX,[EDI+0]
PUSH EAX
PUSHL OFFSET(SYSTEM.BlockWriteResult)
CALLN32 SYSTEM.BlockWrite
END;
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE CStrWriteText({VAR f:FILE}CONST s:CSTRING;format:LONGWORD);
VAR
ss:STRING;
l:LONGWORD;
fi:^FILE;
fillup:BYTE;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
END;
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
l:=length(s);
IF Format+l>255 THEN Format:=255-l;
IF format>l THEN
BEGIN
fillup:=format-l;
fillchar(ss[0],fillup,32);
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,ss[0],fillup);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
{must do this in ASM because s is constant parameter}
ASM
PUSHL $fi
PUSHL $s
PUSHL $l
PUSHL OFFSET(SYSTEM.BlockWriteResult)
CALLN32 SYSTEM.BlockWrite
END;
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
{Float value is in ST(0) !}
PROCEDURE WriteExtendedText({VAR f:FILE}Format1,Format2:LONGWORD);
VAR
float:EXTENDED;
fi:^FILE;
s:STRING;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
FSTPT $float
PUSHL $Format1
PUSHL $Format2 //Nachkommas
LEA EAX,$float
PUSH EAX
LEA EAX,$s
PUSH EAX
CALLN32 SYSTEM.!Extended2Str
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,s[1],length(s));
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE WritelnText(VAR f:FILE);
VAR
w:WORD;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
{Write #13#10}
w:=$0a0d;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(f,w,2);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE WriteText(VAR f:FILE);
BEGIN
{do nothing here - just pop f}
END;
PROCEDURE FileWrite({VAR f:FILE)}VAR Buf;size:LONGWORD);
VAR
fi:^FILE;
fr:^FileRec;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
MOV $fr,EAX
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockWrite(fi^,Buf,size DIV fr^.RecSize);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
PROCEDURE FileRead({VAR f:FILE;}VAR Buf;size:LONGWORD);
VAR
fi:^FILE;
fr:^FileRec;
Adr:LONGINT;
SaveIO:BOOLEAN;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+16] //VAR f:FILE
MOV $fi,EAX
MOV $fr,EAX
END;
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(fi^,Buf,size DIV fr^.RecSize);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
END;
FUNCTION SeekEoln(VAR F:Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
Offset:LONGINT;
Value:BYTE;
SaveIoError:BOOLEAN;
Res:LONGWORD;
t:BYTE;
s:STRING;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF eof(f) THEN
BEGIN
result:=TRUE;
exit;
END;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
Seek(f,FilePos(f)-1);
RaiseIOError:=SaveIOError;
IF Res=0 THEN Value:=26; {EOF}
END;
END
ELSE value:=fi^.Buffer^[Offset];
IF value IN [13,10,26] THEN result:=TRUE
ELSE
BEGIN
IF not (value IN [9,32]) THEN result:=FALSE
ELSE {must read the line}
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
Offset:=FilePos(f);
Readln(f,s);
Seek(f,Offset);
RaiseIOError:=SaveIOError;
result:=TRUE;
FOR t:=1 TO length(s) DO
IF not (s[t] IN [#9,#32]) THEN result:=FALSE;
END;
END;
END;
FUNCTION SeekEof(Var F :Text):Boolean;
VAR
Adr:LONGINT;
fi:^FileRec;
OldFP:LONGWORD;
ch:Char;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
OldFP := FilePos(F);
WHILE not Eof(F) DO
BEGIN
Read(F,ch);
IF not (ch IN [#32,#9,#13,#10]) THEN break;
END;
Result := Eof(f);
Seek(F,OldFP);
END;
PROCEDURE TextRead({VAR f:TEXT;VAR Ziel;}VAR s:STRING;Typ,MaxLen:LONGWORD);
VAR
fi:^FileRec;
fi2:^TEXT;
Offset,Ende,t,Temp,Res,Res1:LONGWORD;
Count:WORD;
Value:BYTE;
SaveIoError:BOOLEAN;
Adr:LONGINT;
LABEL l,skip;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
ASM
MOV EAX,[EBP+24] //VAR f:TEXT
MOV $fi,EAX
MOV $fi2,EAX
END;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
IF eof(fi2^) THEN
BEGIN
(*IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
CASE Typ OF
1:s:=''; {String}
2:s:=chr(26); {Char}
3:s:=''; {Number}
ELSE s:='';
END; {case}
exit;
END;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Count:=0;
s:='';
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
l:
FOR t:=Offset TO Ende-1 DO
BEGIN
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
fi^.BufferBytes:=0;
END
ELSE
BEGIN
SaveIOError:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(fi2^,Value,1,Res);
RaiseIOError:=SaveIOError;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF Res=0 THEN Value:=26; {EOF}
fi^.BufferBytes:=1 OR (Value SHL 8);
END;
END
ELSE value:=fi^.Buffer^[t];
IF value=26 {EOF} THEN
BEGIN
{SaveIoError:=RaiseIoError;
RaiseIOError:=FALSE;
Seek(fi2^,FileSize(fi2^));
RaiseIOError:=SaveIoError;}
fi^.Reserved1:=fi^.Reserved1 OR 1; {mark EOF}
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
IF s='' THEN s:=#26;
inc(fi^.Offset);
fi^.BufferBytes:=0;
exit;
END;
CASE Typ OF
1: {String}
BEGIN
CASE value OF
13,10:
BEGIN
IF Count>255 THEN Count:=255;
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END; {case}
END;
2: {Char}
BEGIN
s[1]:=chr(Value);
s[0]:=#1;
IF fi^.Buffer<>NIL THEN inc(fi^.Offset)
ELSE fi^.BufferBytes:=0;
IF fi^.Offset=Ende THEN
BEGIN
IF Eof(fi2^) THEN exit;
{Ende erreicht --> erweitern}
IF fi^.Buffer=NIL THEN exit;
FileBlockIO(fi2^,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
exit;
END;
3: {Number}
BEGIN
CASE value OF
13,10,32,9:
BEGIN
IF Count=0 THEN goto skip; {skip preceding chars}
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END; {case}
END;
END; {case}
inc(Count);
IF Count<256 THEN IF Count<=MaxLen THEN s[Count]:=chr(value);
skip:
inc(fi^.Offset);
fi^.BufferBytes:=0;
IF Count>=MaxLen THEN
BEGIN
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
END;
IF eof(fi2^) THEN
BEGIN
(*IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;*)
IF Count>255 THEN Count:=255;
s[0]:=chr(Count);
exit;
END;
{Ende erreicht --> erweitern}
IF fi^.Buffer<>NIL THEN
BEGIN
FileBlockIO(fi2^,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
IF eof(fi2^) THEN
BEGIN
IOResult:=38; {Handle EOF}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
goto l;
END;
PROCEDURE TextReadLF(VAR f:TEXT);
VAR
fi:^FileRec;
Offset,Ende,t,Temp,Res:LONGWORD;
Value:BYTE;
Read13,Read10:BOOLEAN;
Adr:LONGINT;
SaveIO:BOOLEAN;
LABEL l;
BEGIN
ASM
MOV EAX,[EBP+4]
SUB EAX,5
MOV $Adr,EAX
END;
fi:=@f;
IF fi^.flags<>$6666 THEN
BEGIN
IF RaiseIOError THEN InvalidFileNameError(Adr)
ELSE
BEGIN
IOResult:=206;
exit;
END;
END;
IF fi^.Handle=$ffffffff THEN
BEGIN
IOResult:=6; {Invalid handle}
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.reserved1:=fi^.reserved1 and not 1;
IF Eof(f) THEN exit;
Offset:=fi^.Offset;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
Read13:=FALSE;
Read10:=FALSE;
fi^.reserved1:=fi^.reserved1 and not 1;
l:
FOR t:=Offset TO Ende-1 DO
BEGIN
IF fi^.Buffer=NIL THEN
BEGIN
IF lo(fi^.BufferBytes)=1 THEN
BEGIN
Value:=Hi(fi^.BufferBytes);
fi^.BufferBytes:=0;
END
ELSE
BEGIN
SaveIO:=RaiseIOError;
RaiseIOError:=FALSE;
BlockRead(f,Value,1,Res);
RaiseIOError:=SaveIO;
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
IF Res=0 THEN Value:=26; {EOF}
fi^.BufferBytes:=1 OR (Value SHL 8);
END;
END
ELSE value:=fi^.Buffer^[t];
CASE value OF
26: {EOF}
BEGIN
fi^.Reserved1:=fi^.Reserved1 OR 1; {mark EOF}
exit;
END;
13:
BEGIN
IF ((Read13)OR(Read10)) THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
Read13:=TRUE;
END;
10:
BEGIN
IF Read10 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
IF f=Input THEN IF Read13 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
Read10:=TRUE;
END;
ELSE
BEGIN
IF Read13 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
IF Read10 THEN
BEGIN
fi^.BufferBytes:=0;
exit;
END;
END;
END; {case}
inc(fi^.Offset);
fi^.BufferBytes:=0;
END;
IF Eof(f) THEN exit;
{Ende erreicht --> erweitern}
IF fi^.Buffer<>NIL THEN
BEGIN
FileBlockIO(f,fi^.block+1,ReadMode,Temp);
IF IOResult<>0 THEN
BEGIN
IF RaiseIOError THEN InOutError(IOResult,Adr)
ELSE exit;
END;
fi^.offset:=0;
inc(fi^.block);
END;
IF eof(f) THEN exit;
IF fi^.Block<>fi^.LBlock THEN Ende:=fi^.MaxCacheMem
ELSE Ende:=fi^.LOffset;
Offset:=fi^.Offset;
IF fi^.Buffer=NIL THEN
BEGIN
Offset:=0;
Ende:=256;
END;
goto l;
END;
PROCEDURE ReadLnText(VAR source:TEXT);
BEGIN
TextReadLF(source);
END;
ASSEMBLER
SYSTEM.!ParaInfo PROC NEAR32 //(AL=Function - 1 count of parameters to CL
// 2 Pointer to parameter CL to ESI
//Input:argument start in ESI
MOV BX,0 //we start with parameter 0
CMP AL,2 //get parameter name ?
JNE !no_name
PUSH ESI
CMP CL,0 //parameter 0 required ?
JE !no_args
POP ESI
!no_name:
//Overread the EXE file name
CLD
PUSH AX
!rrloop:
LODSB
CMP AL,32
JNE !rrloop
POP AX
CMP AL,2 //get parameter name ?
JE !get_argname
MOV CL,255 //impossible parameter
!get_argname:
XOR CH,CH
MOV BX,1 //now finally we start with parameter 1
LODSB
//check whether the first character is a separator
CMP AL,' '
JE !aagain
CMP AL,0 //is this already the end -->Urrgh !
JNE !al2
PUSHL 0 //The (nonexistent) parameters -->Throw it away guy !
MOV BL,0 //No parameters
JMP !no_args
!al2:
DEC ESI //restore old position
!aagain:
PUSH ESI //save last adress
CMP CL,BL //is the parameter reached ??
JE !no_args
!readloop:
LODSB
CMP AL,0
JE !no_args1 //No more arguments detected
//check all separators possible
CMP AL,' '
JE !separator
//No separator --> normal character
JMP !readloop
!separator:
//Check whether more separators follow
LODSB
CMP AL,' '
JE !one_more
CMP AL,0 //A zero parameter is stupid
JNE !no_more
POP EAX //Clear stack
PUSHL 0 //The (nonexistent) parameter -->Throw it away guy !
JMP !no_args
!one_more:
JMP !separator
!no_more:
DEC ESI
INC BX //Increment parameter count
POP EAX //clear stack
JMP !aagain
!no_args1:
//Argument index was invalid
POP ESI //Clear Stack
PUSHL 0 //Pointer to parameter is NIL
!no_args:
MOV CL,BL //Parameter count
POP ESI //Adress of last parameter
RETN32
SYSTEM.!ParaInfo ENDP
END;
FUNCTION PARAMSTR(item:Byte):STRING;
VAR s,s1:STRING;
BEGIN
ParamStr:=''; {Clear}
ASM
MOV CL,$item //index to CL
MOV AL,2 //Get Parameter name
MOV ESI,SYSTEM.ArgStart
CALLN32 SYSTEM.!ParaInfo
MOV EDI,[EBP+8] //Result string
MOVB [EDI+0],0 //Result string is empty
LEA EDI,$s //result string
XOR AL,AL //Stringlen to 0
STOSB
CMP ESI,0 //Parameter invalid ?
JE _Lpe
CLD
LEA EDI,$s //result string
XOR AL,AL //Stringlen to 0
STOSB
MOV CL,0 //Len is 0
__lp1:
LODSB
//Check all separators
CMP AL,' '
JE __Lps
CMP AL,0 //Last parameter
JE __Lps
INC CL
//No separator --> save
STOSB
JMP __lp1
__Lps:
LEA EDI,$s //Result string
MOV [EDI+0],CL //set Stringlen
_lpe:
END;
IF item=0 THEN
BEGIN
IF Length(s)>0 THEN IF s[1]='"' THEN Delete(s,1,1);
IF s[length(s)]='"' THEN dec(s[0]);
IF pos('.',s)=0 THEN s:=s+'.EXE';
IF pos('\',s)=0 THEN
BEGIN
getdir(0,s1);
IF s1[length(s1)]='\' THEN dec(s1[0]);
s:=s1+'\'+s;
END;
END;
ParamStr:=s;
END;
FUNCTION PARAMCOUNT:Byte;
BEGIN
ASM
MOV AL,1 //get parametercount
MOV ESI,SYSTEM.ArgStart
CALLN32 SYSTEM.!ParaInfo
MOV AL,CL
XOR AH,AH
MOV $!FUNCRESULT,AX
END;
END;
//************************************************************************
//
//
// System initialization section
//
//
//************************************************************************
PROCEDURE InitScreenInOut;
VAR VioModule:LONGWORD;
s:CSTRING;
Size,Value:WORD;
csbi:CONSOLE_SCREEN_BUFFER_INFO;
ff:^FileRec;
co:COORD;
Actual:LONGWORD;
LABEL l;
BEGIN
ScreenInOut.Create;
ff:=@Output;
GetConsoleScreenBufferInfo(ff^.Handle,csbi);
WITH csbi DO
BEGIN
IF dwSize.X = 40 THEN LastMode := CO40
ELSE LastMode := CO80;
IF dwSize.Y > 25 THEN Inc(LastMode,Font8x8);
END;
WindMin := 0;
WindMax := csbi.dwSize.X - 1 + (csbi.dwSize.Y - 1) SHL 8;
MaxWindMin :=WindMin;
MaxWindMax :=WindMax;
co.X:=1;
co.Y:=1;
ReadConsoleOutputAttribute(ff^.Handle,Value,2,LONGWORD(co),Actual);
TextAttr := Hi(Value) AND $7F;
ff:=@Input;
SetConsoleMode(ff^.Handle,ENABLE_PROCESSED_INPUT OR ENABLE_LINE_INPUT OR
ENABLE_ECHO_INPUT OR ENABLE_WINDOW_INPUT OR ENABLE_MOUSE_INPUT OR
ENABLE_PROCESSED_OUTPUT OR ENABLE_WRAP_AT_EOL_OUTPUT);
END;
PROCEDURE InitScreenInOutPM;
VAR
c:TPMScreenInOutClass;
BEGIN
c.Create;
ScreenInOut:=TScreenInOutClass(c);
END;
TYPE
PSCUFileFormat=^TSCUFileFormat;
TSCUFileFormat=RECORD
Version:STRING[5];
ObjectOffset,ObjectLen:LONGINT;
NameTableOffset,NameTableLen:LONGINT;
ResourceOffset,ResourceLen:LONGINT;
ObjectCount:LONGINT;
UseEntry:LONGINT; {used by project management}
NextEntry:POINTER;
END;
PROCEDURE AddSCUData(Data:PSCUFileFormat);
BEGIN
Data^.NextEntry:=SCUPointer;
SCUPointer:=Data;
END;
VAR ArgStart:POINTER;
EnvStart:POINTER;
CONST
C10:LONGWORD=10;
FPUControl:WORD=$133f;
FPURound:WORD=$1f3f;
Exponent:WORD=0;
fl1:ARRAY[0..3] OF BYTE=(0,$42,$c0,$ff);
fl2:ARRAY[0..9] OF BYTE=($35,$c2,$68,$21,$a2,$da,$0f,$c9,$fe,$3f); //0.7853...
fl3:ARRAY[0..9] OF BYTE=($35,$c2,$68,$21,$a2,$da,$0f,$c9,$ff,$3f);
fl4:ARRAY[0..3] OF BYTE=(0,$4a,$c0,$ff);
fl5:ARRAY[0..3] OF BYTE=(0,0,0,$3f);
fl6:ARRAY[0..9] OF BYTE=($85,$64,$de,$f9,$33,$f3,4,$b5,$ff,$3f);
fl7:ARRAY[0..9] OF BYTE=($48,$7e,$2a,$92,$a2,$da,$0f,$c9,$ff,$3f); //PI/2
fl8:ARRAY[0..9] OF BYTE=(0,0,0,0,0,0,0,$80,$fe,$3f); //0.5
fl9:ARRAY[0..9] OF BYTE=(0,0,0,0,0,0,0,$80,0,$40); //2.0
fl10:ARRAY[0..9] OF BYTE=($83,$ab,$4b,$ac,$dd,$8d,$5d,$93,0,$40); //ln(10)
fl11:ARRAY[0..9] OF BYTE=($7e,$c0,$68,$77,$0d,$18,$72,$b1,$fe,$3f); //ln(2)
PROCEDURE ExitAll;
BEGIN
ExitProcess(ExitCode);
END;
IMPORTS
FUNCTION GetCommandLine:PChar;
APIENTRY; 'KERNEL32' name 'GetCommandLineA';
FUNCTION GetModuleHandle(CONST lpModuleName:CSTRING):LONGWORD;
APIENTRY; 'KERNEL32' name 'GetModuleHandleA';
END;
PROCEDURE SystemInit(HeapSize,TheStackSize:LONGWORD);
VAR ff:^FileRec;
ESP:LONGWORD;
BEGIN
ASM
MOV $ESP,ESP
END;
StackSize:=TheStackSize;
MinStack:=(ESP-StackSize)+16384;
ExcptList:=NIL;
ArgStart:=GetCommandLine;
AppHandle:=GetModuleHandle(NIL);
RedirectIn:=FALSE;
RedirectOut:=FALSE;
Redirect:=FALSE;
ExitProc:=@ExitAll;
ASM
//Initialize FPU
FINIT
FCLEX
FLDCW SYSTEM.FPUControl
FWAIT
//correct arguments
//CALLN32 SYSTEM.!CorrectArgList
END;
FileBufSize:=32760; {Standard file buffer size}
ff:=@Input;
ff^.Handle:=GetStdHandle(-10); {Handle to standard input}
ff^.RecSize:=1;
ff^.Name:='';
ff^.EAS:=NIL;
ff^.Flags:=$6666;
ff^.Mode:=0;
ff^.Buffer:=NIL;
ff^.MaxCacheMem:=0;
ff^.Offset:=0;
ff^.LOffset:=0;
ff^.Block:=0;
ff^.LBlock:=0;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
ff:=@Output;
ff^.Handle:=GetStdHandle(-11); {Handle to standard output}
ff^.RecSize:=1;
ff^.Name:='';
ff^.EAS:=NIL;
ff^.Flags:=$6666;
ff^.Mode:=0;
ff^.Buffer:=NIL;
ff^.MaxCacheMem:=0;
ff^.Offset:=0;
ff^.LOffset:=0;
ff^.Block:=0;
ff^.LBlock:=0;
ff^.Reserved1:=0;
ff^.BufferBytes:=0;
HeapError:=StdHeapError;
IF not CreateSystemHeap(HeapSize*1024) THEN RunError(218);
OpenedFilesCount:=0;
IOResult:=0;
FileMode:=fmInOut;
SeekMode:=0; {File begin}
SetTrigMode(rad);
ExcptMutex:=CreateMutex(NIL,FALSE,NIL);
SetUnhandledExceptionFilter(@ExcptHandler);
ScreenInOut.Create;
END;
PROCEDURE SystemEnd;
BEGIN
Halt(0);
END;
{$D+}
BEGIN
END.
{$ENDIF}