(************************************************************************) (* *) (* 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 MaxAvail0 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.