📄 ststrms.pas
字号:
procedure TStAnsiTextStream.atsSetLineEndCh(aValue : AnsiChar);
begin
if ((FBufOfs + FBufPos) = 0) then begin
FLineEndCh := aValue;
atsResetLineIndex;
end;
end;
{-----------------------------------------------------------------------------}
procedure TStAnsiTextStream.atsSetLineLen(aValue : integer);
begin
if (aValue <> FixedLineLength) and ((FBufOfs + FBufPos) = 0) then begin
{validate the new length first}
if (aValue < 1) or (aValue > 1024) then
RaiseStError(EStBufStreamError, stscBadLineLength);
{set the new value; note that if there is no terminator we need to
free the old line buffer, and then allocate a new one}
if (LineTerminator = ltNone) then
FreeMem(FFixedLine, FixedLineLength);
FLineLen := aValue;
if (LineTerminator = ltNone) then
GetMem(FFixedLine, FixedLineLength);
atsResetLineIndex;
end;
end;
{-----------------------------------------------------------------------------}
procedure TStAnsiTextStream.bsInitForNewStream;
begin
inherited bsInitForNewStream;
atsResetLineIndex;
end;
{-----------------------------------------------------------------------------}
function TStAnsiTextStream.ReadLine : string;
var
CurPos : longint;
EndPos : longint;
Len : longint;
StLen : longint;
begin
atsGetLine(CurPos, EndPos, Len);
if (LineTerminator = ltNone) then begin
{at this point, Len will either equal FixedLineLength, or it will
be less than it because we read the last line of all and it was
short}
StLen := FixedLineLength;
SetLength(Result, StLen);
if (Len < StLen) then
FillChar(Result[Len+1], StLen-Len, ' ');
end
else {LineTerminator is not ltNone} begin
SetLength(Result, Len);
end;
{read the line}
if Len > 0 then begin
Seek(CurPos, soFromBeginning);
Read(Result[1], Len);
end
else {it's a blank line }
Result := '';
Seek(EndPos, soFromBeginning);
end;
{-----------------------------------------------------------------------------}
function TStAnsiTextStream.ReadLineArray(aCharArray : PAnsiChar;
aLen : TStMemSize)
: TStMemSize;
var
CurPos : longint;
EndPos : longint;
Len : longint;
StLen : longint;
begin
atsGetLine(CurPos, EndPos, Len);
if (LineTerminator = ltNone) then begin
{at this point, Len will either equal FixedLineLength, or it will
be less than it because we read the last line of all and it was
short}
StLen := FixedLineLength;
if (StLen > aLen) then
StLen := aLen;
if (Len < StLen) then
FillChar(aCharArray[Len], StLen-Len, ' ');
Result := StLen;
end
else {LineTerminator is not ltNone} begin
if (Len > aLen) then
Len := aLen;
Result := Len;
end;
Seek(CurPos, soFromBeginning);
Read(aCharArray[0], Len);
Seek(EndPos, soFromBeginning);
end;
{-----------------------------------------------------------------------------}
function TStAnsiTextStream.ReadLineZ(aSt : PAnsiChar; aMaxLen : TStMemSize) : PAnsiChar;
var
CurPos : longint;
EndPos : longint;
Len : longint;
StLen : longint;
begin
Result := aSt;
atsGetLine(CurPos, EndPos, Len);
if (LineTerminator = ltNone) then begin
{at this point, Len will either equal FixedLineLength, or it will
be less than it because we read the last line of all and it was
short}
StLen := FixedLineLength;
if (StLen > aMaxLen) then
StLen := aMaxLen;
if (Len < StLen) then
FillChar(Result[Len], StLen-Len, ' ');
Result[StLen] := #0;
end
else {LineTerminator is not ltNone} begin
if (Len > aMaxLen) then
Len := aMaxLen;
Result[Len] := #0;
end;
Seek(CurPos, soFromBeginning);
Read(Result[0], Len);
Seek(EndPos, soFromBeginning);
end;
{-----------------------------------------------------------------------------}
function TStAnsiTextStream.SeekNearestLine(aOffset : longint) : longint;
var
CurLine : longint;
CurOfs : longint;
CurPos : longint;
EndPos : longint;
Len : longint;
i : longint;
Done : boolean;
L, R, M : integer;
begin
{if the offset we want is for the current line, reposition at the
current line offset, return the current line number and exit}
if (aOffset = FLineCurOfs) then begin
Seek(FLineCurOfs, soFromBeginning);
Result := FLineCurrent;
Exit;
end;
{if the offset requested is less than or equal to zero, just
position at line zero (ie, the start of the stream)}
if (aOffset <= 0) then begin
Seek(0, soFromBeginning);
FLineCurrent := 0;
FLineCurOfs := 0;
Result := 0;
Exit;
end;
{if the offset requested is greater than or equal to the size of the
stream, position at the end of the stream (note that if we don't
know the number of lines in the stream yet, FLineCount is set to
-1 and we can't take this shortcut because we need to return the
true value)}
if (FLineCount >= 0) and (aOffset >= FSize) then begin
Seek(0, soFromEnd);
FLineCurrent := FLineCount;
FLineCurOfs := FSize;
Result := FLineCount;
Exit;
end;
{if the offset requested is greater than the top item in the
line index, we shall have to build up the index until we get to the
line we require, or just beyond}
if (aOffset > longint(FLineIndex[FLineInxTop+1])) then begin
{position at the last known line offset}
CurLine := longint(FLineIndex[FLineInxTop]);
CurOfs := longint(FLineIndex[FLineInxTop+1]);
Seek(CurOfs, soFromBeginning);
Done := false;
{continue reading lines in chunks of FLineInxStep and add an index
entry for each chunk}
while not Done do begin
for i := 0 to pred(FLineInxStep) do begin
atsGetLine(CurPos, EndPos, Len);
inc(CurLine);
CurOfs := EndPos;
if (EndPos = FSize) then begin
Done := true;
Break;
end;
end;
if Done then
FLineCount := CurLine
else begin
inc(FLineInxTop, 2);
if (FLineInxTop = (LineIndexCount * 2)) then begin
{we've exhausted the space in the index: rescale}
FLineInxTop := FLineInxTop div 2;
for i := 0 to pred(FLineInxTop) do begin
if Odd(i) then
FLineIndex.Exchange((i*2)-1, i)
else
FLineIndex.Exchange(i*2, i);
end;
FLineInxStep := FLineInxStep * 2;
end;
FLineIndex[FLineInxTop] := pointer(CurLine);
FLineIndex[FLineInxTop+1] := pointer(CurOfs);
if (aOffset <= CurOfs) then
Done := true;
end;
end;
end;
{we can now work out where the nearest item in the index is to the
line we require}
L := 1;
R := FLineInxTop+1;
while (L <= R) do begin
M := (L + R) div 2;
if not Odd(M) then
inc(M);
if (aOffset < longint(FLineIndex[M])) then
R := M - 2
else if (aOffset > longint(FLineIndex[M])) then
L := M + 2
else begin
FLineCurrent := longint(FLineIndex[M-1]);
FLineCurOfs := longint(FLineIndex[M]);
Seek(FLineCurOfs, soFromBeginning);
Result := FLineCurrent;
Exit;
end;
end;
{the item at L-2 will have the nearest smaller offset than the
one we want, hence the nearest smaller line is at L-3; start here
and read through the stream forwards}
CurLine := longint(FLineIndex[L-3]);
Seek(longint(FLineIndex[L-2]), soFromBeginning);
while true do begin
atsGetLine(CurPos, EndPos, Len);
inc(CurLine);
if (EndPos > aOffset) then begin
FLineCurrent := CurLine - 1;
FLineCurOfs := CurPos;
Seek(CurPos, soFromBeginning);
Result := CurLine - 1;
Exit;
end
else if (CurLine = FLineCount) or (EndPos = aOffset) then begin
FLineCurrent := CurLine;
FLineCurOfs := EndPos;
Seek(EndPos, soFromBeginning);
Result := CurLine;
Exit;
end;
end;
end;
{-----------------------------------------------------------------------------}
function TStAnsiTextStream.SeekLine(aLineNum : longint) : longint;
var
CurLine : longint;
CurOfs : longint;
CurPos : longint;
EndPos : longint;
Len : longint;
i : longint;
Done : boolean;
L, R, M : integer;
begin
{if the line number we want is the current line, reposition at the
current line offset, return the current line number and exit}
if (aLineNum = FLineCurrent) then begin
Seek(FLineCurOfs, soFromBeginning);
Result := FLineCurrent;
Exit;
end;
{if the line number requested is less than or equal to zero, just
position at line zero (ie, the start of the stream)}
if (aLineNum <= 0) then begin
Seek(0, soFromBeginning);
FLineCurrent := 0;
FLineCurOfs := 0;
Result := 0;
Exit;
end;
{if the line number requested is greater than or equal to the line
count, position at the end of the stream (note that if we don't
know the number of lines in the stream yet, FLineCount is set to
-1)}
if (FLineCount >= 0) and (aLineNum > FLineCount) then begin
Seek(0, soFromEnd);
FLineCurrent := FLineCount;
FLineCurOfs := FSize;
Result := FLineCount;
Exit;
end;
{if the line number requested is greater than the top item in the
line index, we shall have to build up the index until we get to the
line we require, or just beyond}
if (aLineNum > longint(FLineIndex[FLineInxTop])) then begin
{position at the last known line offset}
CurLine := longint(FLineIndex[FLineInxTop]);
CurOfs := longint(FLineIndex[FLineInxTop+1]);
Seek(CurOfs, soFromBeginning);
Done := false;
{continue reading lines in chunks of FLineInxStep and add an index
entry for each chunk}
while not Done do begin
for i := 0 to pred(FLineInxStep) do begin
atsGetLine(CurPos, EndPos, Len);
inc(CurLine);
CurOfs := EndPos;
if (EndPos = FSize) then begin
Done := true;
Break;
end;
end;
if Done then
FLineCount := CurLine
else begin
inc(FLineInxTop, 2);
if (FLineInxTop = (LineIndexCount * 2)) then begin
{we've exhausted the space in the index: rescale}
FLineInxTop := FLineInxTop div 2;
for i := 0 to pred(FLineInxTop) do begin
if Odd(i) then
FLineIndex.Exchange((i*2)-1, i)
else
FLineIndex.Exchange(i*2, i);
end;
FLineInxStep := FLineInxStep * 2;
end;
FLineIndex[FLineInxTop] := pointer(CurLine);
FLineIndex[FLineInxTop+1] := pointer(CurOfs);
if (aLineNum <= CurLine) then
Done := true;
end;
end;
end;
{we can now work out where the nearest item in the index is to the
line we require}
L := 0;
R := FLineInxTop;
while (L <= R) do begin
M := (L + R) div 2;
if Odd(M) then
dec(M);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -