[Back to FILES SWAG index] [Back to Main SWAG index] [Original]
(************************************************************************)
(* *)
(* Program ex. to : "Tips & Tricks in Turbo Pascal", SysTime 1993 *)
(* *)
(* By : Martin Israelsen *)
(* *)
(* Title : BUFFER.PAS *)
(* *)
(* Chapter : 5 *)
(* *)
(* Description : Quicker than Turbo fileread *)
(* *)
(************************************************************************)
(*$I-*) (* Iocheck off *)
(*$F+*) (* Force FAR call *)
(*$V-*) (* Relaxed VAR check *)
(*$R-*) (* Range check off *)
(*$S-*) (* Stack check off *)
(*$Q-*) (* Overflow off *)
(*$D-*) (* Debug off *)
(*$L-*) (* Linenumber off *)
Unit
Buffer;
Interface
Type
PByte = ^Byte;
PWord = ^Word;
PLong = ^Longint;
PByteArr = ^TByteArr;
TByteArr = Array[1..64000] Of Byte;
PfStr = String[100];
PBuffer = ^TBuffer;
TBuffer = Record
BufFil : File;
BufPtr : PByteArr;
BufSize,
BufIndex,
BufUsed : Word;
BufFPos,
BufFSize : Longint;
End;
Function BufferInit(Var Br: PBuffer; MemSize: Word;
FilName: PfStr): Boolean;
Procedure BufferClose(Var Br: PBuffer);
Function BufferGetByte(Br: PBuffer): Byte;
Function BufferGetByteAsm(Br: PBuffer): Byte;
Function BufferGetWord(Br: PBuffer): Word;
Procedure BufferGetBlock(Br: PBuffer; Var ToAdr; BlockSize: Word);
Function BufferGetStringAsm(Br: PBuffer): String;
Function BufferEof(Br: PBuffer): Boolean;
Implementation
(*$I-,F+*)
Function BufferInit(Var Br: PBuffer; MemSize: Word;
FilName: PfStr): Boolean;
Begin
BufferInit:=False;
(* Check if there's enough memory *)
If MemSize<500 Then Exit;
If MaxAvail<Sizeof(TBuffer)+MemSize+32 Then Exit;
New(Br);
With BR^ Do
Begin
BufSize:=MemSize; BufIndex:=1; BufFPos:=0;
(* Open the filen. Exit if there's an error *)
Assign(BufFil,Filname); Reset(BufFil,1);
If IoResult<>0 Then
Begin
Dispose(Br);
Exit;
End;
(* Ok, the file is there, and there's enough *)
(* memory. So allocate the memory and read *)
(* as much as possible *)
GetMem(BufPtr,BufSize);
BlockRead(BufFil,BufPtr^,BufSize,BufUsed);
BufFSize:=FileSize(BufFil); Inc(BufFPos,BufUsed);
End;
BufferInit:=True;
End;
Procedure BufferClose(Var Br: PBuffer);
Begin
With Br^ Do
Begin
Close(BufFil);
Freemem(BufPtr,BufSize);
End;
Dispose(Br);
End;
Procedure BufferCheck(Br: PBuffer; ReqBytes: Word);
Var
W,Rest: Word;
Begin
With Br^ Do
Begin
If (BufIndex+ReqBytes>BufUsed) And (BufUsed=BufSize) Then
Begin
Rest:=Succ(BufSize-BufIndex);
Move(BufPtr^[BufIndex],BufPtr^[1],Rest);
BufIndex:=1;
BlockRead(BufFil,BufPtr^[Succ(Rest)],BufSize-Rest,W);
BufUsed:=Rest+W; Inc(BufFPos,W);
End;
End;
End;
Function BufferGetByte(Br: PBuffer): Byte;
Begin
With Br^ Do
Begin
BufferCheck(Br,1);
BufferGetByte:=BufPtr^[BufIndex];
Inc(BufIndex);
End;
End;
Function BufferGetByteAsm(Br: PBuffer): Byte; Assembler;
Asm
Les Di,Br (* ES:DI -> BRecPtr *)
Mov Ax,Es:[Di.TBuffer.BufIndex] (* Check wheather the buffer should be updated *)
Cmp Ax,Es:[Di.TBuffer.BufUsed]
Jle @@NoBufCheck (* If not jump on *)
Push Word Ptr Br[2] (* Push BR to BufferCheck *)
Push Word Ptr Br
Mov Ax,0001 (* Check for one byte *)
Push Ax (* Push it *)
Push CS (* Push CS, and make a *)
Call Near Ptr BufferCheck (* NEAR call - it's quicker *)
Les Di,Br (* ES:DI-> BRecPtr *)
@@NoBufCheck:
Mov Bx,Es:[Di.TBuffer.BufIndex] (* BufferIndex in BX *)
Inc Es:[Di.TBuffer.BufIndex] (* Inc BufferIndex directly *)
Les Di,Es:[Di.TBuffer.BufPtr] (* ES:DI -> BufPtr *)
Xor Ax,Ax (* Now get the byte *)
Mov Al,Byte Ptr Es:[Di+Bx-1]
End;
Function BufferGetWord(Br: PBuffer): Word;
Begin
With Br^ Do
Begin
BufferCheck(Br,2);
BufferGetWord:=PWord(@BufPtr^[BufIndex])^;
Inc(BufIndex,2);
End;
End;
Procedure BufferGetBlock(Br: PBuffer; Var ToAdr; BlockSize: Word);
Begin
With Br^ Do
Begin
BufferCheck(Br,BlockSize);
Move(BufPtr^[BufIndex],ToAdr,BlockSize);
Inc(BufIndex,BlockSize);
End;
End;
Function BufferGetStringAsm(Br: PBuffer): String; Assembler;
Asm
Push Ds
Les Di,Br (* es:di -> Br *)
Mov Bx,Es:[Di.TBuffer.BufUsed] (* check for buffercheck *)
Sub Bx,Es:[Di.TBuffer.BufIndex]
Cmp Bx,257
Jae @NoBufCheck (* Jump on if not *)
Push Word Ptr Br[2]
Push Word Ptr Br
Mov Ax,257
Push Ax
Push Cs
Call Near Ptr BufferCheck
Les Di,Br
@NoBufCheck:
Mov Bx,Es:[Di.TBuffer.BufIndex] (* Get index in buffer *)
Dec Bx (* Adjust for 0 *)
Les Di,Es:[Di.TBuffer.BufPtr] (* Point to the buffer *)
Add Di,Bx (* Add Index *)
Push Di (* Save currect position *)
Mov Al,$0a (* Search for CR = 0ah *)
Mov Cx,$ff (* max. 255 chars *)
Cld (* Remember *)
RepNz Scasb (* and do the search *)
Jz @Fundet (* Jump if we found one *)
Mov Cx,0 (* Otherwise set length to 0 *)
@Fundet:
Sub Cx,$ff (* Which will be recalculated *)
Neg Cx (* to nomal length *)
Dec Cx (* Dec, to avoid CR *)
Push Es (* DS:SI->Buffer *)
Pop Ds
Pop Si
Les Di,@Result (* ES:DI->result string *)
Mov Ax,Cx
Stosb (* Set length *)
Shr Cx,1 (* Copy the string *)
Rep MovSw
Adc Cx,Cx
Rep MovSb
Pop Ds (* Restore DS *)
Les Di,Br (* ES:DI->Br *)
Inc Ax (* Inc Ax, point to LF *)
Add Es:[Di.TBuffer.BufIndex],Ax (* and set BufferIndex *)
End;
Function BufferEof(Br: PBuffer): Boolean;
Begin
With Br^ Do
BufferEof:=(BufIndex>BufUsed) And (BufFPos=BufFSize);
End;
End.
[Back to FILES SWAG index] [Back to Main SWAG index] [Original]