1 { Copyright (C) 2009 Bas Steendijk and Peter Green
\r 
   2   For conditions of distribution and use, see copyright notice in zlib_license.txt
\r 
   3   which is included in the package
\r 
   4   ----------------------------------------------------------------------------- }
\r 
  14 this can be used to read a text file exposed as a tstream line by line.
\r 
  15 automatic handling of CR, LF, and CRLF line endings, and readout of detected line ending type.
\r 
  16 fast: 1.5-2 times faster than textfile readln in tests.
\r 
  31   treadtxt=class(tobject)
\r 
  33     buf:array[0..bufsize-1] of byte;
\r 
  36     currenteol,preveol:integer;
\r 
  37     fileeof,reachedeof:boolean;
\r 
  38     fdetectedeol:integer;
\r 
  39     procedure checkandread;
\r 
  41     sourcestream:tstream;
\r 
  42     destroysourcestream:boolean;
\r 
  44     constructor create(asourcestream: tstream; adestroysourcestream:boolean);
\r 
  45     constructor createf(filename : string);
\r 
  47     function readline:ansistring;
\r 
  48     function eof:boolean;
\r 
  49     destructor destroy; override;
\r 
  50     property detectedeol : integer read fdetectedeol;
\r 
  55 constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);
\r 
  58   sourcestream := asourcestream;
\r 
  59   destroysourcestream := adestroysourcestream;
\r 
  61   //if sourcestream.Position >= sourcestream.size then fileeof := true;
\r 
  62   bufpointer := bufsize;
\r 
  65 constructor treadtxt.createf(filename: string);
\r 
  67   create(tfilestream.create(filename,fmOpenRead or fmShareDenyWrite),true);
\r 
  71 procedure treadtxt.checkandread;
\r 
  73   if bufpointer >= numread then begin
\r 
  74     numread := sourcestream.read(buf,bufsize);
\r 
  76     if numread = 0 then fileeof := true;
\r 
  81 function treadtxt.readline;
\r 
  93     {core search loop begin}
\r 
  95     for a := bufpointer to b do begin
\r 
  97       //check if the character can possibly be a line ending before getting
\r 
  98       //into the more complex checks that depend on eol type
\r 
  99       if (c = 10) or (c = 13) then case allowedeol of
\r 
 105           if (c = 13) then begin
\r 
 111           if (c = 10) then begin
\r 
 116         eoltype_crlf: begin
\r 
 117           if (c = 10) and (prevchar= 13) then begin
\r 
 125           raise exception.create('undefined eol type set');
\r 
 130     {core search loop end}
\r 
 132     c := length(result);
\r 
 133     if (d = -1) then begin
\r 
 134       {ran out of buffer before end of line}
\r 
 135       b := numread-bufpointer;
\r 
 136       setlength(result,c+b);
\r 
 137       move(buf[bufpointer],result[c+1],b);
\r 
 138       bufpointer := numread;
\r 
 139       if fileeof then begin
\r 
 140         {we reached the end of the file, return what we have}
\r 
 141         reachedeof := true;
\r 
 146       preveol := currenteol;
\r 
 147       currenteol := buf[d];
\r 
 149       {end of line before end of buffer}
\r 
 150       if (currenteol = 10) and (preveol = 13) and (bufpointer = d) then begin
\r 
 151         {it's the second EOL char of a DOS line ending, don't cause a line}
\r 
 153         fdetectedeol := eoltype_crlf;
\r 
 155         if fdetectedeol = eoltype_none then begin
\r 
 156           if (currenteol = 10) then fdetectedeol := eoltype_lf else fdetectedeol := eoltype_cr;
\r 
 159         if trimchar then begin
\r 
 160           setlength(result,c+b-1);
\r 
 161           move(buf[bufpointer],result[c+1],b-1);
\r 
 164           setlength(result,c+b);
\r 
 165           move(buf[bufpointer],result[c+1],b);
\r 
 170         if fileeof then begin
\r 
 171           if (bufpointer >= numread) then reachedeof := true;
\r 
 172           if (currenteol = 13) and (bufpointer = numread-1) then if (buf[bufpointer] = 10) then reachedeof := true;
\r 
 181 function treadtxt.eof:boolean;
\r 
 184   result := ((bufpointer >= numread) and fileeof) or reachedeof;
\r 
 187 destructor treadtxt.destroy;
\r 
 189   if destroysourcestream then if assigned(sourcestream) then sourcestream.destroy;
\r