github.com/karrick/gorill@v1.10.3/nltr.go (about)

     1  package gorill
     2  
     3  import (
     4  	"io"
     5  )
     6  
     7  // LineTerminatedReader reads from the source io.Reader and ensures the final
     8  // byte from this is a newline.
     9  type LineTerminatedReader struct {
    10  	R                   io.Reader
    11  	wasFinalByteNewline bool
    12  	oweNewline          bool
    13  }
    14  
    15  // Read satisfies the io.Reader interface by reading up to len(p) bytes into p.
    16  // It returns the number of bytes read (0 <= n <= len(p)) and any error
    17  // encountered.
    18  func (r *LineTerminatedReader) Read(p []byte) (int, error) {
    19  	if r.oweNewline {
    20  		r.oweNewline = false
    21  		if len(p) == 0 {
    22  			return 0, nil // from io.Reader documentation
    23  		}
    24  		p[0] = '\n'
    25  		return 1, io.EOF // allowed per io.Reader documentation
    26  	}
    27  	n, err := r.R.Read(p)
    28  	if n > 0 {
    29  		r.wasFinalByteNewline = p[n-1] == '\n'
    30  	}
    31  	if err != io.EOF || r.wasFinalByteNewline {
    32  		return n, err
    33  	}
    34  	// fmt.Fprintf(os.Stderr, "Hit EOF && final byte was not a newline.\n")
    35  	if n == len(p) {
    36  		// No room to append newline to this buffer.
    37  		r.oweNewline = true
    38  		return n, nil
    39  	}
    40  	// Append the newline byte when it fits.
    41  	p[n] = '\n'
    42  	return n + 1, err
    43  }