amuz.es/src/go/misc@v1.0.1/strutil/chunk.go (about) 1 package strutil 2 3 import ( 4 "io" 5 ) 6 7 const pemLineLength = 64 8 9 // LineBreaker is an io.Writer that advances a newline if one line exceeds 64 bytes. 10 type LineBreaker struct { 11 // Out os 12 Out io.Writer 13 line [pemLineLength]byte 14 used int 15 } 16 17 var nl = []byte{'\n'} 18 19 // Write writes len(p) bytes from p to the underlying data stream. 20 // It returns the number of bytes written from p (0 <= n <= len(p)) 21 // and any error encountered that caused the write to stop early. 22 // Write must return a non-nil error if it returns n < len(p). 23 // Write must not modify the slice data, even temporarily. 24 func (l *LineBreaker) Write(b []byte) (n int, err error) { 25 if l.used+len(b) < pemLineLength { 26 copy(l.line[l.used:], b) 27 l.used += len(b) 28 return len(b), nil 29 } 30 31 n, err = l.Out.Write(l.line[0:l.used]) 32 if err != nil { 33 return 34 } 35 excess := pemLineLength - l.used 36 l.used = 0 37 38 n, err = l.Out.Write(b[0:excess]) 39 if err != nil { 40 return 41 } 42 43 n, err = l.Out.Write(nl) 44 if err != nil { 45 return 46 } 47 48 return l.Out.Write(b[excess:]) 49 } 50 51 // Close flushes any pending output from the writer. 52 // It is an error to call Write after calling Close. 53 func (l *LineBreaker) Close() (err error) { 54 if l.used > 0 { 55 _, err = l.Out.Write(l.line[0:l.used]) 56 if err != nil { 57 return 58 } 59 _, err = l.Out.Write(nl) 60 } 61 if err != nil { 62 return 63 } else if closer, ok := l.Out.(io.Closer); ok { 64 err = closer.Close() 65 } 66 return 67 }