--- /dev/null
+{ Copyright (C) 2009 Bas Steendijk and Peter Green\r
+ For conditions of distribution and use, see copyright notice in zlib_license.txt\r
+ which is included in the package\r
+ ----------------------------------------------------------------------------- }\r
+\r
+unit readtxt2;\r
+\r
+interface\r
+\r
+{\r
+readtxt, version 2\r
+by beware\r
+\r
+this can be used to read a text file exposed as a tstream line by line.\r
+automatic handling of CR, LF, and CRLF line endings, and readout of detected line ending type.\r
+fast: 1.5-2 times faster than textfile readln in tests.\r
+}\r
+\r
+uses\r
+ classes,sysutils;\r
+\r
+const\r
+ bufsize=4096;\r
+ eoltype_none=0;\r
+ eoltype_cr=1;\r
+ eoltype_lf=2;\r
+ eoltype_crlf=3;\r
+\r
+type\r
+ treadtxt=class(tobject)\r
+ public\r
+ sourcestream:tstream;\r
+ destroysourcestream:boolean;\r
+ constructor create(asourcestream: tstream; adestroysourcestream:boolean);\r
+ constructor createf(filename : string);\r
+\r
+ function readline:string;\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
+ end;\r
+\r
+implementation\r
+\r
+constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);\r
+begin\r
+ inherited create;\r
+ sourcestream := asourcestream;\r
+ destroysourcestream := adestroysourcestream;\r
+\r
+ if sourcestream.Position >= sourcestream.size then fileeof := true;\r
+ bufpointer := bufsize;\r
+ destroysourcestream := false;\r
+end;\r
+\r
+constructor treadtxt.createf(filename : string);\r
+begin\r
+ create(tfilestream.create(filename,fmOpenRead),true);\r
+end;\r
+\r
+\r
+function treadtxt.readline;\r
+var\r
+ a,b,c,d:integer;\r
+begin\r
+\r
+ result := '';\r
+ repeat\r
+ if bufpointer >= bufsize then begin\r
+ numread := sourcestream.read(buf,bufsize);\r
+ bufpointer := 0;\r
+ if sourcestream.Position >= sourcestream.size then fileeof := true;\r
+ end;\r
+ b := numread-1;\r
+\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
+ end;\r
+ end;\r
+ {core search loop end}\r
+ \r
+ c := length(result);\r
+ if (d = -1) then begin\r
+ {ran out of buffer before end of line}\r
+ b := numread-bufpointer;\r
+ setlength(result,c+b);\r
+ move(buf[bufpointer],result[c+1],b);\r
+ bufpointer := numread;\r
+ if numread < bufsize then begin\r
+ reachedeof := true;\r
+ exit;\r
+ end;\r
+ end else begin\r
+\r
+ preveol := currenteol;\r
+ currenteol := buf[d];\r
+\r
+ {end of line before end of buffer}\r
+ if (currenteol = 10) and (preveol = 13) 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
+ end else begin\r
+ if eoltype = eoltype_none then begin\r
+ if (currenteol = 10) then eoltype := eoltype_lf else eoltype := 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
+\r
+ {EOF check}\r
+ if fileeof then begin\r
+ if (bufpointer >= numread) then reachedeof := true;\r
+ if (currenteol = 13) and (bufpointer = numread-1) then if (buf[bufpointer] = 10) then reachedeof := true;\r
+ end; \r
+\r
+ exit;\r
+ end;\r
+ end;\r
+ until false;\r
+end;\r
+\r
+function treadtxt.eof:boolean;\r
+begin\r
+\r
+ result := ((bufpointer >= bufsize) and fileeof) or reachedeof;\r
+end;\r
+\r
+destructor treadtxt.destroy;\r
+begin\r
+ if destroysourcestream then if assigned(sourcestream) then sourcestream.destroy;\r
+ inherited destroy;\r
+end;\r
+\r
+end.\r
--- /dev/null
+{ Copyright (C) 2009 Bas Steendijk and Peter Green\r
+ For conditions of distribution and use, see copyright notice in zlib_license.txt\r
+ which is included in the package\r
+ ----------------------------------------------------------------------------- }\r
+\r
+\r
+program testreadtxt2;\r
+uses readtxt2, classes;\r
+\r
+var\r
+ t: treadtxt;\r
+ f: file;\r
+procedure writestring(var f: file; s : string);\r
+begin\r
+ blockwrite(f,s[1],length(s));\r
+end;\r
+\r
+begin\r
+ assignfile(f,'mixed.txt');\r
+ rewrite(f,1);\r
+ writestring(f,'DOS'#13#10);\r
+ writestring(f,'UNIX'#10);\r
+ writestring(f,'MAC'#13);\r
+ writestring(f,'NONE');\r
+ closefile(f);\r
+ t := treadtxt.createf('mixed.txt');\r
+ if t.readline = 'DOS' then writeln('DOS success') else writeln('DOS fail');\r
+ if t.readline = 'UNIX' then writeln('UNIX success') else writeln('UNIX fail');\r
+ if t.readline = 'MAC' then writeln('MAC success') else writeln('MAC fail');\r
+ if t.readline = 'NONE' then writeln('NONE success') else writeln('NONE fail');\r
+ t.destroy;\r
+ {$ifdef win32}\r
+ //make things a little easier to test in the delphi GUI\r
+ readln;\r
+ {$endif}\r
+end.\r