Implement a "full reader" wrapper for io.Read, guaranteeing that
either the buffer is full, zero bytes were read, or an error is returned.
R=rsc
DELTA=44 (42 added, 0 deleted, 2 changed)
OCL=19027
CL=19047
diff --git a/src/lib/io.go b/src/lib/io.go
index 20b7b90..44d072c 100644
--- a/src/lib/io.go
+++ b/src/lib/io.go
@@ -3,8 +3,13 @@
// license that can be found in the LICENSE file.
package io
-import os "os"
-import syscall "syscall"
+
+import (
+ "os";
+ "syscall";
+)
+
+export var ErrEOF = os.NewError("EOF")
export type Read interface {
Read(p *[]byte) (n int, err *os.Error);
@@ -34,3 +39,40 @@
r, e := w.Write(b[0:len(s)]);
return r, e
}
+
+// Read until buffer is full, EOF, or error
+export func Readn(fd Read, buf *[]byte) (n int, err *os.Error) {
+ n = 0;
+ for n < len(buf) {
+ nn, e := fd.Read(buf[n:len(buf)]);
+ if nn > 0 {
+ n += nn
+ }
+ if e != nil {
+ return n, e
+ }
+ if nn <= 0 {
+ return n, ErrEOF // no error but insufficient data
+ }
+ }
+ return n, nil
+}
+
+// Convert something that implements Read into something
+// whose Reads are always Readn
+type FullRead struct {
+ fd Read;
+}
+
+func (fd *FullRead) Read(p *[]byte) (n int, err *os.Error) {
+ n, err = Readn(fd, p);
+ return n, err
+}
+
+export func MakeFullReader(fd Read) Read {
+ if fr, ok := fd.(*FullRead); ok {
+ // already a FullRead
+ return fd
+ }
+ return &FullRead{fd}
+}