@@ -16,72 +16,65 @@ package tailer
1616
1717import (
1818 "bytes"
19- "fmt"
2019 "io"
2120)
2221
23- type bufferedLineReader struct {
22+ type lineReader struct {
2423 remainingBytesFromLastRead []byte
25-
26- // channels are used to stream the results out
27- lines chan <- string
28- done <- chan struct {}
2924}
3025
31- func NewBufferedLineReader ( lines chan <- string , done <- chan struct {} ) * bufferedLineReader {
32- return & bufferedLineReader {
26+ func NewLineReader ( ) * lineReader {
27+ return & lineReader {
3328 remainingBytesFromLastRead : []byte {},
34- lines : lines ,
35- done : done ,
3629 }
3730}
3831
39- func (r * bufferedLineReader ) ReadAvailableLines (file io.Reader ) (bool , error ) {
40-
41- // for each buffer, split lines and stream
42- buf := make ([]byte , 512 )
43- var done bool
44-
32+ // read the next line from the file.
33+ // return values are (line, eof, err).
34+ // * line is the line read.
35+ // * eof is a boolean indicating if the end of file was reached before getting to the next '\n'.
36+ // * err is set if an error other than io.EOF has occurred. err is never io.EOF.
37+ // if eof is true, line is always "" and err always is nil.
38+ // if eof is false and err is nil, an empty line means that there actually was an empty line in the file.
39+ func (r * lineReader ) ReadLine (file io.Reader ) (string , bool , error ) {
40+ var (
41+ err error
42+ buf = make ([]byte , 512 )
43+ n = 0
44+ )
4545 for {
46- n , err := file .Read (buf )
47- if n > 0 {
48- // Callers should always process the n > 0 bytes returned before considering the error err.
49- result := append (r .remainingBytesFromLastRead , buf [0 :n ]... )
50- done , r .remainingBytesFromLastRead = r .processLines (result )
51- if done {
52- return true , nil
53- }
54- }
55- if err != nil {
46+ newlinePos := bytes .IndexByte (r .remainingBytesFromLastRead , '\n' )
47+ if newlinePos >= 0 {
48+ l := len (r .remainingBytesFromLastRead )
49+ result := make ([]byte , newlinePos )
50+ copy (result , r .remainingBytesFromLastRead [:newlinePos ])
51+ copy (r .remainingBytesFromLastRead , r .remainingBytesFromLastRead [newlinePos + 1 :])
52+ r .remainingBytesFromLastRead = r .remainingBytesFromLastRead [:l - (newlinePos + 1 )]
53+ return string (stripWindowsLineEnding (result )), false , nil
54+ } else if err != nil {
5655 if err == io .EOF {
57- return false , nil
56+ return "" , true , nil
5857 } else {
59- return false , fmt .Errorf ("read error: %v" , err .Error ())
58+ return "" , false , err
59+ }
60+ } else {
61+ n , err = file .Read (buf )
62+ if n > 0 {
63+ // io.Reader: Callers should always process the n > 0 bytes returned before considering the error err.
64+ r .remainingBytesFromLastRead = append (r .remainingBytesFromLastRead , buf [0 :n ]... )
6065 }
6166 }
6267 }
6368}
6469
65- func (r * bufferedLineReader ) Clear () {
66- r .remainingBytesFromLastRead = []byte {}
70+ func stripWindowsLineEnding (s []byte ) []byte {
71+ if len (s ) > 0 && s [len (s )- 1 ] == '\r' {
72+ return s [:len (s )- 1 ]
73+ } else {
74+ return s
75+ }
6776}
6877
69- func (r * bufferedLineReader ) processLines (data []byte ) (finished bool , remainingBytes []byte ) {
70- newline := []byte ("\n " )
71- for _ , line := range bytes .SplitAfter (data , newline ) {
72- if bytes .HasSuffix (line , newline ) {
73- line = bytes .TrimSuffix (line , newline )
74- line = bytes .TrimSuffix (line , []byte ("\r " )) // Needed for CRLF line endings?
75- select {
76- case r .lines <- string (line ):
77- case <- r .done :
78- finished = true
79- return
80- }
81- } else {
82- // This is the last (incomplete) line returned by SplitAfter(). We will exit the for loop here.
83- remainingBytes = line
84- }
85- }
86- return
78+ func (r * lineReader ) Clear () {
79+ r .remainingBytesFromLastRead = r .remainingBytesFromLastRead [:0 ]
8780}
0 commit comments