[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]
Unit TextUtil;
{ Written by Wilbert Van.Leijen and posted in the Pascal Echo }
Interface
Function TextFilePos(Var f : Text) : LongInt;
Function TextFileSize(Var f : Text) : LongInt;
Procedure TextSeek(Var f : Text; n : LongInt);
Implementation
Uses Dos;
{$R-,S- }
Procedure GetFileMode; Assembler;
Asm
CLC
CMP ES:[DI].TextRec.Mode, fmInput
JE @1
MOV [InOutRes], 104 { 'File not opened For reading' }
xor AX, AX { Zero out Function result }
xor DX, DX
STC
@1:
end; { GetFileMode }
Function TextFilePos(Var f : Text) : LongInt; Assembler;
Asm
LES DI, f
CALL GetFileMode
JC @1
xor CX, CX { Get position of File Pointer }
xor DX, DX
MOV BX, ES:[DI].TextRec.handle
MOV AX, 4201h
inT 21h { offset := offset-Bufend+BufPos }
xor BX, BX
SUB AX, ES:[DI].TextRec.Bufend
SBB DX, BX
ADD AX, ES:[DI].TextRec.BufPos
ADC DX, BX
@1:
end; { TextFilePos }
Function TextFileSize(Var f : Text) : LongInt; Assembler;
Asm
LES DI, f
CALL GetFileMode
JC @1
xor CX, CX { Get position of File Pointer }
xor DX, DX
MOV BX, ES:[DI].TextRec.handle
MOV AX, 4201h
inT 21h
PUSH DX { Save current offset on the stack }
PUSH AX
xor DX, DX { Move File Pointer to Eof }
MOV AX, 4202h
inT 21h
POP SI
POP CX
PUSH DX { Save Eof position }
PUSH AX
MOV DX, SI { Restore old offset }
MOV AX, 4200h
inT 21h
POP AX { Return result}
POP DX
@1:
end; { TextFileSize }
Procedure TextSeek(Var f : Text; n : LongInt); Assembler;
Asm
LES DI, f
CALL GetFileMode
JC @2
MOV CX, Word Ptr n+2 { Move File Pointer }
MOV DX, Word Ptr n
MOV BX, ES:[DI].TextRec.Handle
MOV AX, 4200h
inT 21h
JNC @1 { Carry flag = reading past Eof }
MOV [InOutRes], AX
JMP @2
{ Force read next time }
@1: MOV AX, ES:[DI].TextRec.Bufend
MOV ES:[DI].TextRec.BufPos, AX
@2:
end; { TextSeek }
end. { TextUtil }
{ With the aid of that Unit you could save the position of each line
in the Text File to an Array of LongInt as you read them. You can also
open a temporary File, a File of LongInt, where each Record would simply
represent the offset of that line in the Text File. if you need to go
back in the Text, simply read the offset of the line where you which to
restart reading. Suppose you are on line 391 and you decide to go back
say, 100 lines, simply do a Seek(MyIndex, CurrentLine-100). then use the
TextSeek Procedure to seek to that position in the Text File and start
reading again, taking into acount that you allready read those lines so
you either re-Write the offsets to your index File, which won't hurt
since you will just be overwriting the Records With the same values
again or simply skip writing the offsets Until you reach a point where
NEW lines that haven't yet been read are reached. Save any new offset as
you read Forward.
With this method you can go back-wards as well as Forwards. In fact
if you first read the File, saving all offsets Until the end, you can
offer the user to seek to any line number.
When you read new lines or seek backwards, simply flush any lines
from memory. or maybe you could decide to keep a predetermined number of
lines in memory say 300. When ever the user asks to read Forward or
backwards, simply flush the 100 first or Last line, depending on the
direction the user wants to go, and read 100 new lines from the Text
File.
Maybe the best approach to be sure of sufficient memory is to
determine how many lines will fit. Suppose you limit line lengths to 255
caracters. Determine how many will fit in a worse Case scenario. Create
as many 255 caracter Strings as will fit. divide that number of lines by
4. Say you managed to create 1000 Strings of 255 caracters. divided by 4
is 250. So set a limit to 750 Strings to be safe and make any disk
accesses in bundles of 250 Lines.
You can also keep the line offsets in memory in Arrays but you will
be limited to 65520 / 8 = 16380 lines. Make that two Arrays stored on
the heap and you've got yourself enough space to store 32760 line
offsets which at 255 caracters by line would be an 8.3 Meg File.
}
[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]