const\r
bufsize=4096;\r
eoltype_none=0;\r
+ eoltype_any=0;\r
eoltype_cr=1;\r
eoltype_lf=2;\r
eoltype_crlf=3;\r
\r
type\r
treadtxt=class(tobject)\r
+ private\r
+ buf:array[0..bufsize-1] of byte;\r
+ numread:integer;\r
+ bufpointer:integer;\r
+ currenteol,preveol:integer;\r
+ fileeof,reachedeof:boolean;\r
+ fdetectedeol:integer;\r
+ procedure checkandread;\r
public\r
sourcestream:tstream;\r
destroysourcestream:boolean;\r
+ allowedeol:integer;\r
constructor create(asourcestream: tstream; adestroysourcestream:boolean);\r
constructor createf(filename : string);\r
\r
function readline:ansistring;\r
function eof:boolean;\r
destructor destroy; override;\r
- private\r
- buf:array[0..bufsize-1] of byte;\r
- numread:integer;\r
- bufpointer:integer;\r
- currenteol,preveol:integer;\r
- fileeof,reachedeof:boolean;\r
- eoltype:integer;\r
- procedure checkandread;\r
+ property detectedeol : integer read fdetectedeol;\r
end;\r
-\r
+ \r
implementation\r
\r
constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);\r
\r
constructor treadtxt.createf(filename: string);\r
begin\r
- create(tfilestream.create(filename,fmOpenRead),true);\r
+ create(tfilestream.create(filename,fmOpenRead or fmShareDenyWrite),true);\r
end;\r
\r
\r
function treadtxt.readline;\r
var\r
a,b,c,d:integer;\r
+ prevchar : integer;\r
+ trimchar : boolean;\r
begin\r
-\r
+ prevchar := 0;\r
result := '';\r
repeat\r
checkandread;\r
b := numread-1;\r
-\r
+ trimchar := false;\r
{core search loop begin}\r
d := -1;\r
for a := bufpointer to b do begin\r
c := buf[a];\r
- if (c = 10) or (c = 13) then begin\r
- d := a;\r
- break;\r
+ //check if the character can possibly be a line ending before getting\r
+ //into the more complex checks that depend on eol type\r
+ if (c = 10) or (c = 13) then case allowedeol of\r
+ eoltype_any: begin\r
+ d := a;\r
+ break;\r
+ end;\r
+ eoltype_cr: begin\r
+ if (c = 13) then begin\r
+ d := a;\r
+ break;\r
+ end;\r
+ end;\r
+ eoltype_lf: begin\r
+ if (c = 10) then begin\r
+ d := a;\r
+ break;\r
+ end;\r
+ end;\r
+ eoltype_crlf: begin\r
+ if (c = 10) and (prevchar= 13) then begin\r
+ d := a;\r
+ trimchar := true;\r
+ break;\r
+ end;\r
+ prevchar := c;\r
+ end;\r
+ else begin\r
+ raise exception.create('undefined eol type set');\r
+ end;\r
end;\r
+ prevchar := c;\r
end;\r
{core search loop end}\r
\r
currenteol := buf[d];\r
\r
{end of line before end of buffer}\r
- if (currenteol = 10) and (preveol = 13) then begin\r
+ if (currenteol = 10) and (preveol = 13) and (bufpointer = d) then begin\r
{it's the second EOL char of a DOS line ending, don't cause a line}\r
bufpointer := d+1;\r
- eoltype := eoltype_crlf;\r
+ fdetectedeol := eoltype_crlf;\r
end else begin\r
- if eoltype = eoltype_none then begin\r
- if (currenteol = 10) then eoltype := eoltype_lf else eoltype := eoltype_cr;\r
+ if fdetectedeol = eoltype_none then begin\r
+ if (currenteol = 10) then fdetectedeol := eoltype_lf else fdetectedeol := eoltype_cr;\r
end; \r
b := d-bufpointer;\r
- setlength(result,c+b);\r
- move(buf[bufpointer],result[c+1],b);\r
- bufpointer := d+1;\r
+ if trimchar then begin\r
+ setlength(result,c+b-1);\r
+ move(buf[bufpointer],result[c+1],b-1);\r
+ bufpointer := d+1;\r
+ end else begin\r
+ setlength(result,c+b);\r
+ move(buf[bufpointer],result[c+1],b);\r
+ bufpointer := d+1;\r
+ end;\r
\r
{EOF check}\r
if fileeof then begin\r