removed use of global vars in dnssync, should be reentrant safe
[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:ansistring;\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 end;\r
60 \r
61 constructor treadtxt.createf(filename: string);\r
62 begin\r
63   create(tfilestream.create(filename,fmOpenRead),true);\r
64 end;\r
65 \r
66 \r
67 function treadtxt.readline;\r
68 var\r
69   a,b,c,d:integer;\r
70 begin\r
71 \r
72   result := '';\r
73   repeat\r
74     if bufpointer >= bufsize then begin\r
75       numread := sourcestream.read(buf,bufsize);\r
76       bufpointer := 0;\r
77       if sourcestream.Position >= sourcestream.size then fileeof := true;\r
78     end;\r
79     b := numread-1;\r
80 \r
81     {core search loop begin}\r
82     d := -1;\r
83     for a := bufpointer to b do begin\r
84       c := buf[a];\r
85       if (c = 10) or (c = 13) then begin\r
86          d := a;\r
87          break;\r
88       end;\r
89     end;\r
90     {core search loop end}\r
91     \r
92     c := length(result);\r
93     if (d = -1) then begin\r
94       {ran out of buffer before end of line}\r
95       b := numread-bufpointer;\r
96       setlength(result,c+b);\r
97       move(buf[bufpointer],result[c+1],b);\r
98       bufpointer := numread;\r
99       if numread < bufsize then begin\r
100         reachedeof := true;\r
101         exit;\r
102       end;\r
103     end else begin\r
104 \r
105       preveol := currenteol;\r
106       currenteol := buf[d];\r
107 \r
108       {end of line before end of buffer}\r
109       if (currenteol = 10) and (preveol = 13) then begin\r
110         {it's the second EOL char of a DOS line ending, don't cause a line}\r
111         bufpointer := d+1;\r
112         eoltype := eoltype_crlf;\r
113       end else begin\r
114         if eoltype = eoltype_none then begin\r
115           if (currenteol = 10) then eoltype := eoltype_lf else eoltype := eoltype_cr;\r
116         end;  \r
117         b := d-bufpointer;\r
118         setlength(result,c+b);\r
119         move(buf[bufpointer],result[c+1],b);\r
120         bufpointer := d+1;\r
121 \r
122         {EOF check}\r
123         if fileeof then begin\r
124           if (bufpointer >= numread) then reachedeof := true;\r
125           if (currenteol = 13) and (bufpointer = numread-1) then if (buf[bufpointer] = 10) then reachedeof := true;\r
126         end;  \r
127 \r
128         exit;\r
129       end;\r
130     end;\r
131   until false;\r
132 end;\r
133 \r
134 function treadtxt.eof:boolean;\r
135 begin\r
136 \r
137   result := ((bufpointer >= bufsize) and fileeof) or reachedeof;\r
138 end;\r
139 \r
140 destructor treadtxt.destroy;\r
141 begin\r
142   if destroysourcestream then if assigned(sourcestream) then sourcestream.destroy;\r
143   inherited destroy;\r
144 end;\r
145 \r
146 end.\r