freebsd fixups
[lcore.git] / readtxt2.pas
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
5 \r
6 unit readtxt2;\r
7 \r
8 interface\r
9 \r
10 {\r
11 readtxt, version 2\r
12 by beware\r
13 \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
17 }\r
18 \r
19 uses\r
20   classes,sysutils;\r
21 \r
22 const\r
23   bufsize=4096;\r
24   eoltype_none=0;\r
25   eoltype_cr=1;\r
26   eoltype_lf=2;\r
27   eoltype_crlf=3;\r
28 \r
29 type\r
30   treadtxt=class(tobject)\r
31   public\r
32     sourcestream:tstream;\r
33     destroysourcestream:boolean;\r
34     constructor create(asourcestream: tstream; adestroysourcestream:boolean);\r
35     constructor createf(filename : string);\r
36 \r
37     function readline:string;\r
38     function eof:boolean;\r
39     destructor destroy; override;\r
40   private\r
41     buf:array[0..bufsize-1] of byte;\r
42     numread:integer;\r
43     bufpointer:integer;\r
44     currenteol,preveol:integer;\r
45     fileeof,reachedeof:boolean;\r
46     eoltype:integer;\r
47   end;\r
48 \r
49 implementation\r
50 \r
51 constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);\r
52 begin\r
53   inherited create;\r
54   sourcestream := asourcestream;\r
55   destroysourcestream := adestroysourcestream;\r
56 \r
57   if sourcestream.Position >= sourcestream.size then fileeof := true;\r
58   bufpointer := bufsize;\r
59   destroysourcestream := false;\r
60 end;\r
61 \r
62 constructor treadtxt.createf(filename : string);\r
63 begin\r
64   create(tfilestream.create(filename,fmOpenRead),true);\r
65 end;\r
66 \r
67 \r
68 function treadtxt.readline;\r
69 var\r
70   a,b,c,d:integer;\r
71 begin\r
72 \r
73   result := '';\r
74   repeat\r
75     if bufpointer >= bufsize then begin\r
76       numread := sourcestream.read(buf,bufsize);\r
77       bufpointer := 0;\r
78       if sourcestream.Position >= sourcestream.size then fileeof := true;\r
79     end;\r
80     b := numread-1;\r
81 \r
82     {core search loop begin}\r
83     d := -1;\r
84     for a := bufpointer to b do begin\r
85       c := buf[a];\r
86       if (c = 10) or (c = 13) then begin\r
87          d := a;\r
88          break;\r
89       end;\r
90     end;\r
91     {core search loop end}\r
92     \r
93     c := length(result);\r
94     if (d = -1) then begin\r
95       {ran out of buffer before end of line}\r
96       b := numread-bufpointer;\r
97       setlength(result,c+b);\r
98       move(buf[bufpointer],result[c+1],b);\r
99       bufpointer := numread;\r
100       if numread < bufsize then begin\r
101         reachedeof := true;\r
102         exit;\r
103       end;\r
104     end else begin\r
105 \r
106       preveol := currenteol;\r
107       currenteol := buf[d];\r
108 \r
109       {end of line before end of buffer}\r
110       if (currenteol = 10) and (preveol = 13) then begin\r
111         {it's the second EOL char of a DOS line ending, don't cause a line}\r
112         bufpointer := d+1;\r
113         eoltype := eoltype_crlf;\r
114       end else begin\r
115         if eoltype = eoltype_none then begin\r
116           if (currenteol = 10) then eoltype := eoltype_lf else eoltype := eoltype_cr;\r
117         end;  \r
118         b := d-bufpointer;\r
119         setlength(result,c+b);\r
120         move(buf[bufpointer],result[c+1],b);\r
121         bufpointer := d+1;\r
122 \r
123         {EOF check}\r
124         if fileeof then begin\r
125           if (bufpointer >= numread) then reachedeof := true;\r
126           if (currenteol = 13) and (bufpointer = numread-1) then if (buf[bufpointer] = 10) then reachedeof := true;\r
127         end;  \r
128 \r
129         exit;\r
130       end;\r
131     end;\r
132   until false;\r
133 end;\r
134 \r
135 function treadtxt.eof:boolean;\r
136 begin\r
137 \r
138   result := ((bufpointer >= bufsize) and fileeof) or reachedeof;\r
139 end;\r
140 \r
141 destructor treadtxt.destroy;\r
142 begin\r
143   if destroysourcestream then if assigned(sourcestream) then sourcestream.destroy;\r
144   inherited destroy;\r
145 end;\r
146 \r
147 end.\r