fmt.dirinstall: io.dirinstall reflect.dirinstall strconv.dirinstall
hash.dirinstall: os.dirinstall
http.dirinstall: bufio.install io.dirinstall net.dirinstall os.dirinstall strings.install log.install
-io.dirinstall: os.dirinstall syscall.dirinstall
+io.dirinstall: os.dirinstall syscall.dirinstall sync.dirinstall
json.dirinstall: container/array.dirinstall fmt.dirinstall io.dirinstall math.dirinstall \
strconv.dirinstall strings.install utf8.install
# TODO(rsc): net is not supposed to depend on fmt or strings or strconv
$(AS) $*.s
O1=\
- io.$O\
bytebuffer.$O\
+ io.$O\
-io.a: a1
+O2=\
+ pipe.$O\
+
+io.a: a1 a2
a1: $(O1)
- $(AR) grc io.a io.$O bytebuffer.$O
+ $(AR) grc io.a bytebuffer.$O io.$O
rm -f $(O1)
+a2: $(O2)
+ $(AR) grc io.a pipe.$O
+ rm -f $(O2)
+
newpkg: clean
$(AR) grc io.a
$(O1): newpkg
+$(O2): a1
nuke: clean
rm -f $(GOROOT)/pkg/io.a
Write(p []byte) (n int, err *os.Error);
}
+type Close interface {
+ Close() *os.Error;
+}
+
type ReadWrite interface {
Read(p []byte) (n int, err *os.Error);
Write(p []byte) (n int, err *os.Error);
}
-type ReadWriteClose interface {
+type ReadClose interface {
Read(p []byte) (n int, err *os.Error);
+ Close() *os.Error;
+}
+
+type WriteClose interface {
Write(p []byte) (n int, err *os.Error);
Close() *os.Error;
}
-type Close interface {
+type ReadWriteClose interface {
+ Read(p []byte) (n int, err *os.Error);
+ Write(p []byte) (n int, err *os.Error);
Close() *os.Error;
}
// Convert something that implements Read into something
// whose Reads are always Readn
-type _FullRead struct {
+type fullRead struct {
fd Read;
}
-func (fd *_FullRead) Read(p []byte) (n int, err *os.Error) {
+func (fd *fullRead) Read(p []byte) (n int, err *os.Error) {
n, err = Readn(fd.fd, p);
return n, err
}
-func Make_FullReader(fd Read) Read {
- if fr, ok := fd.(*_FullRead); ok {
- // already a _FullRead
+func MakeFullReader(fd Read) Read {
+ if fr, ok := fd.(*fullRead); ok {
+ // already a fullRead
return fd
}
- return &_FullRead(fd)
+ return &fullRead(fd)
}
// Copies n bytes (or until EOF is reached) from src to dst.
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pipe adapter to connect code expecting an io.Read
+// with code expecting an io.Write.
+
+package io
+
+import (
+ "io";
+ "os";
+ "sync";
+)
+
+type pipeReturn struct {
+ n int;
+ err *os.Error;
+}
+
+// Shared pipe structure.
+type pipe struct {
+ rclosed bool; // Read end closed?
+ wclosed bool; // Write end closed?
+ wpend []byte; // Written data waiting to be read.
+ wtot int; // Bytes consumed so far in current write.
+ cr chan []byte; // Write sends data here...
+ cw chan pipeReturn; // ... and reads the n, err back from here.
+}
+
+func (p *pipe) Read(data []byte) (n int, err *os.Error) {
+ if p == nil || p.rclosed {
+ return 0, os.EINVAL;
+ }
+
+ // Wait for next write block if necessary.
+ if p.wpend == nil {
+ if !p.wclosed {
+ p.wpend = <-p.cr;
+ }
+ if p.wpend == nil {
+ return 0, nil;
+ }
+ p.wtot = 0;
+ }
+
+ // Read from current write block.
+ n = len(data);
+ if n > len(p.wpend) {
+ n = len(p.wpend);
+ }
+ for i := 0; i < n; i++ {
+ data[i] = p.wpend[i];
+ }
+ p.wtot += n;
+ p.wpend = p.wpend[n:len(p.wpend)];
+
+ // If write block is done, finish the write.
+ if len(p.wpend) == 0 {
+ p.wpend = nil;
+ p.cw <- pipeReturn(p.wtot, nil);
+ p.wtot = 0;
+ }
+
+ return n, nil;
+}
+
+func (p *pipe) Write(data []byte) (n int, err *os.Error) {
+ if p == nil || p.wclosed {
+ return 0, os.EINVAL;
+ }
+ if p.rclosed {
+ return 0, os.EPIPE;
+ }
+
+ // Send data to reader.
+ p.cr <- data;
+
+ // Wait for reader to finish copying it.
+ res := <-p.cw;
+ return res.n, res.err;
+}
+
+func (p *pipe) CloseReader() *os.Error {
+ if p == nil || p.rclosed {
+ return os.EINVAL;
+ }
+
+ // Stop any future writes.
+ p.rclosed = true;
+
+ // Stop the current write.
+ if !p.wclosed {
+ p.cw <- pipeReturn(p.wtot, os.EPIPE);
+ }
+
+ return nil;
+}
+
+func (p *pipe) CloseWriter() *os.Error {
+ if p == nil || p.wclosed {
+ return os.EINVAL;
+ }
+
+ // Stop any future reads.
+ p.wclosed = true;
+
+ // Stop the current read.
+ if !p.rclosed {
+ p.cr <- nil;
+ }
+
+ return nil;
+}
+
+// Read/write halves of the pipe.
+// They are separate structures for two reasons:
+// 1. If one end becomes garbage without being Closed,
+// its finisher can Close so that the other end
+// does not hang indefinitely.
+// 2. Clients cannot use interface conversions on the
+// read end to find the Write method, and vice versa.
+
+// Read half of pipe.
+type pipeRead struct {
+ lock sync.Mutex;
+ p *pipe;
+}
+
+func (r *pipeRead) Read(data []byte) (n int, err *os.Error) {
+ r.lock.Lock();
+ defer r.lock.Unlock();
+
+ return r.p.Read(data);
+}
+
+func (r *pipeRead) Close() *os.Error {
+ r.lock.Lock();
+ defer r.lock.Unlock();
+
+ return r.p.CloseReader();
+}
+
+func (r *pipeRead) finish() {
+ r.Close();
+}
+
+// Write half of pipe.
+type pipeWrite struct {
+ lock sync.Mutex;
+ p *pipe;
+}
+
+func (w *pipeWrite) Write(data []byte) (n int, err *os.Error) {
+ w.lock.Lock();
+ defer w.lock.Unlock();
+
+ return w.p.Write(data);
+}
+
+func (w *pipeWrite) Close() *os.Error {
+ w.lock.Lock();
+ defer w.lock.Unlock();
+
+ return w.p.CloseWriter();
+}
+
+func (w *pipeWrite) finish() {
+ w.Close();
+}
+
+// Create a synchronous in-memory pipe.
+// Reads on one end are matched by writes on the other.
+// Writes don't complete until all the data has been
+// written or the read end is closed. Reads return
+// any available data or block until the next write
+// or the write end is closed.
+func Pipe() (io.ReadClose, io.WriteClose) {
+ p := new(pipe);
+ p.cr = make(chan []byte, 1);
+ p.cw = make(chan pipeReturn, 1);
+ r := new(pipeRead);
+ r.p = p;
+ w := new(pipeWrite);
+ w.p = p;
+ return r, w;
+}
+
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io
+
+import (
+ "io";
+ "os";
+ "testing";
+ "time";
+)
+
+func checkWrite(t *testing.T, w io.Write, data []byte, c chan int) {
+ n, err := w.Write(data);
+ if err != nil {
+ t.Errorf("write: %v", err);
+ }
+ if n != len(data) {
+ t.Errorf("short write: %d != %d", n, len(data));
+ }
+ c <- 0;
+}
+
+// Test a single read/write pair.
+func TestPipe1(t *testing.T) {
+ c := make(chan int);
+ r, w := io.Pipe();
+ var buf [64]byte;
+ go checkWrite(t, w, io.StringBytes("hello, world"), c);
+ n, err := r.Read(buf);
+ if err != nil {
+ t.Errorf("read: %v", err);
+ }
+ else if n != 12 || string(buf[0:12]) != "hello, world" {
+ t.Errorf("bad read: got %q", buf[0:n]);
+ }
+ <-c;
+ r.Close();
+ w.Close();
+}
+
+func reader(t *testing.T, r io.Read, c chan int) {
+ var buf [64]byte;
+ for {
+ n, err := r.Read(buf);
+ if err != nil {
+ t.Errorf("read: %v", err);
+ }
+ c <- n;
+ if n == 0 {
+ break;
+ }
+ }
+}
+
+// Test a sequence of read/write pairs.
+func TestPipe2(t *testing.T) {
+ c := make(chan int);
+ r, w := io.Pipe();
+ go reader(t, r, c);
+ var buf [64]byte;
+ for i := 0; i < 5; i++ {
+ p := buf[0:5+i*10];
+ n, err := w.Write(p);
+ if n != len(p) {
+ t.Errorf("wrote %d, got %d", len(p), n);
+ }
+ if err != nil {
+ t.Errorf("write: %v", err);
+ }
+ nn := <-c;
+ if nn != n {
+ t.Errorf("wrote %d, read got %d", n, nn);
+ }
+ }
+ w.Close();
+ nn := <-c;
+ if nn != 0 {
+ t.Errorf("final read got %d", nn);
+ }
+}
+
+// Test a large write that requires multiple reads to satisfy.
+func writer(w io.WriteClose, buf []byte, c chan pipeReturn) {
+ n, err := w.Write(buf);
+ w.Close();
+ c <- pipeReturn(n, err);
+}
+
+func TestPipe3(t *testing.T) {
+ c := make(chan pipeReturn);
+ r, w := io.Pipe();
+ var wdat [128]byte;
+ for i := 0; i < len(wdat); i++ {
+ wdat[i] = byte(i);
+ }
+ go writer(w, wdat, c);
+ var rdat [1024]byte;
+ tot := 0;
+ for n := 1; n <= 256; n *= 2 {
+ nn, err := r.Read(rdat[tot:tot+n]);
+ if err != nil {
+ t.Fatalf("read: %v", err);
+ }
+
+ // only final two reads should be short - 1 byte, then 0
+ expect := n;
+ if n == 128 {
+ expect = 1;
+ } else if n == 256 {
+ expect = 0;
+ }
+ if nn != expect {
+ t.Fatalf("read %d, expected %d, got %d", n, expect, nn);
+ }
+ tot += nn;
+ }
+ pr := <-c;
+ if pr.n != 128 || pr.err != nil {
+ t.Fatalf("write 128: %d, %v", pr.n, pr.err);
+ }
+ if tot != 128 {
+ t.Fatalf("total read %d != 128", tot);
+ }
+ for i := 0; i < 128; i++ {
+ if rdat[i] != byte(i) {
+ t.Fatalf("rdat[%d] = %d", i, rdat[i]);
+ }
+ }
+}
+
+// Test read after/before writer close.
+
+func delayClose(t *testing.T, cl io.Close, ch chan int) {
+ time.Sleep(1000*1000); // 1 ms
+ if err := cl.Close(); err != nil {
+ t.Errorf("delayClose: %v", err);
+ }
+ ch <- 0;
+}
+
+func testPipeReadClose(t *testing.T, async bool) {
+ c := make(chan int, 1);
+ r, w := io.Pipe();
+ if async {
+ go delayClose(t, w, c);
+ } else {
+ delayClose(t, w, c);
+ }
+ var buf [64]int;
+ n, err := r.Read(buf);
+ <-c;
+ if err != nil {
+ t.Errorf("read from closed pipe: %v", err);
+ }
+ if n != 0 {
+ t.Errorf("read on closed pipe returned %d", n);
+ }
+ if err = r.Close(); err != nil {
+ t.Errorf("r.Close: %v", err);
+ }
+}
+
+// Test write after/before reader close.
+
+func testPipeWriteClose(t *testing.T, async bool) {
+ c := make(chan int, 1);
+ r, w := io.Pipe();
+ if async {
+ go delayClose(t, r, c);
+ } else {
+ delayClose(t, r, c);
+ }
+ n, err := io.WriteString(w, "hello, world");
+ <-c;
+ if err != os.EPIPE {
+ t.Errorf("write on closed pipe: %v", err);
+ }
+ if n != 0 {
+ t.Errorf("write on closed pipe returned %d", n);
+ }
+ if err = w.Close(); err != nil {
+ t.Errorf("w.Close: %v", err);
+ }
+}
+
+func TestPipeReadCloseAsync(t *testing.T) {
+ testPipeReadClose(t, true);
+}
+
+func TestPipeReadCloseSync(t *testing.T) {
+ testPipeReadClose(t, false);
+}
+
+func TestPipeWriteCloseAsync(t *testing.T) {
+ testPipeWriteClose(t, true);
+}
+
+func TestPipeWriteCloseSync(t *testing.T) {
+ testPipeWriteClose(t, false);
+}
+
O1=\
zoneinfo.$O\
+ sleep.$O\
O2=\
time.$O\
time.a: a1 a2 a3
a1: $(O1)
- $(AR) grc time.a zoneinfo.$O
+ $(AR) grc time.a zoneinfo.$O sleep.$O
rm -f $(O1)
a2: $(O2)
when += ns
}
- syscall.Nstotimeval(when - now, &tv);
- syscall.Syscall6(syscall.SYS_SELECT, 0, 0, 0, 0, int64(uintptr(unsafe.Pointer(&tv))), 0);
+ time.Sleep(when - now);
now = time.Nanoseconds();
c <- now;
}
"time"
)
-// Seconds since January 1, 1970 00:00:00 GMT
+// Seconds since January 1, 1970 00:00:00 UTC
func Seconds() int64 {
sec, nsec, err := os.Time();
if err != nil {
return sec
}
-// Nanoseconds since January 1, 1970 00:00:00 GMT
+// Nanoseconds since January 1, 1970 00:00:00 UTC
func Nanoseconds() int64 {
sec, nsec, err := os.Time();
if err != nil {
}
const (
- _SecondsPerDay = 24*60*60;
+ secondsPerDay = 24*60*60;
- _DaysPer400Years = 365*400+97;
- _DaysPer100Years = 365*100+24;
- _DaysPer4Years = 365*4+1;
+ daysPer400Years = 365*400+97;
+ daysPer100Years = 365*100+24;
+ daysPer4Years = 365*4+1;
- _Days1970To2001 = 31*365+8;
+ days1970To2001 = 31*365+8;
)
func SecondsToUTC(sec int64) *Time {
t := new(Time);
// Split into time and day.
- day := sec/_SecondsPerDay;
- sec -= day*_SecondsPerDay;
+ day := sec/secondsPerDay;
+ sec -= day*secondsPerDay;
if sec < 0 {
day--;
- sec += _SecondsPerDay
+ sec += secondsPerDay
}
// Time
// Change day from 0 = 1970 to 0 = 2001,
// to make leap year calculations easier
// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
- day -= _Days1970To2001;
+ day -= days1970To2001;
year := int64(2001);
if day < 0 {
// Go back enough 400 year cycles to make day positive.
- n := -day/_DaysPer400Years + 1;
+ n := -day/daysPer400Years + 1;
year -= 400*n;
- day += _DaysPer400Years*n;
+ day += daysPer400Years*n;
} else {
// Cut off 400 year cycles.
- n := day/_DaysPer400Years;
+ n := day/daysPer400Years;
year += 400*n;
- day -= _DaysPer400Years*n;
+ day -= daysPer400Years*n;
}
// Cut off 100-year cycles
- n := day/_DaysPer100Years;
+ n := day/daysPer100Years;
year += 100*n;
- day -= _DaysPer100Years*n;
+ day -= daysPer100Years*n;
// Cut off 4-year cycles
- n = day/_DaysPer4Years;
+ n = day/daysPer4Years;
year += 4*n;
- day -= _DaysPer4Years*n;
+ day -= daysPer4Years*n;
// Cut off non-leap years.
n = day/365;
return SecondsToUTC(Seconds())
}
-// TODO: Should this return an error?
func SecondsToLocalTime(sec int64) *Time {
z, offset, err := time.LookupTimezone(sec);
if err != nil {
if year < 2001 {
n := (2001 - year)/400 + 1;
year += 400*n;
- day -= _DaysPer400Years*n;
+ day -= daysPer400Years*n;
}
// Add in days from 400-year cycles.
n := (year - 2001) / 400;
year -= 400*n;
- day += _DaysPer400Years*n;
+ day += daysPer400Years*n;
// Add in 100-year cycles.
n = (year - 2001) / 100;
year -= 100*n;
- day += _DaysPer100Years*n;
+ day += daysPer100Years*n;
// Add in 4-year cycles.
n = (year - 2001) / 4;
year -= 4*n;
- day += _DaysPer4Years*n;
+ day += daysPer4Years*n;
// Add in non-leap years.
n = year - 2001;
day += int64(t.Day - 1);
// Convert days to seconds since January 1, 2001.
- sec := day * _SecondsPerDay;
+ sec := day * secondsPerDay;
// Add in time elapsed today.
sec += int64(t.Hour) * 3600;
sec += int64(t.Second);
// Convert from seconds since 2001 to seconds since 1970.
- sec += _Days1970To2001 * _SecondsPerDay;
+ sec += days1970To2001 * secondsPerDay;
// Account for local time zone.
sec -= int64(t.ZoneOffset);
return sec
}
-var _LongDayNames = []string(
+var longDayNames = []string(
"Sunday",
"Monday",
"Tuesday",
"Saturday"
)
-var _ShortDayNames = []string(
+var shortDayNames = []string(
"Sun",
"Mon",
"Tue",
"Sat"
)
-var _ShortMonthNames = []string(
+var shortMonthNames = []string(
"Jan",
"Feb",
"Mar",
"Dec"
)
-func _Copy(dst []byte, s string) {
+func copy(dst []byte, s string) {
for i := 0; i < len(s); i++ {
dst[i] = s[i]
}
}
-func _Decimal(dst []byte, n int) {
+func decimal(dst []byte, n int) {
if n < 0 {
n = 0
}
}
}
-func _AddString(buf []byte, bp int, s string) int {
+func addString(buf []byte, bp int, s string) int {
n := len(s);
- _Copy(buf[bp:bp+n], s);
+ copy(buf[bp:bp+n], s);
return bp+n
}
// Just enough of strftime to implement the date formats below.
// Not exported.
-func _Format(t *Time, fmt string) string {
+func format(t *Time, fmt string) string {
buf := make([]byte, 128);
bp := 0;
i++;
switch fmt[i] {
case 'A': // %A full weekday name
- bp = _AddString(buf, bp, _LongDayNames[t.Weekday]);
+ bp = addString(buf, bp, longDayNames[t.Weekday]);
case 'a': // %a abbreviated weekday name
- bp = _AddString(buf, bp, _ShortDayNames[t.Weekday]);
+ bp = addString(buf, bp, shortDayNames[t.Weekday]);
case 'b': // %b abbreviated month name
- bp = _AddString(buf, bp, _ShortMonthNames[t.Month-1]);
+ bp = addString(buf, bp, shortMonthNames[t.Month-1]);
case 'd': // %d day of month (01-31)
- _Decimal(buf[bp:bp+2], t.Day);
+ decimal(buf[bp:bp+2], t.Day);
bp += 2;
case 'e': // %e day of month ( 1-31)
if t.Day >= 10 {
- _Decimal(buf[bp:bp+2], t.Day)
+ decimal(buf[bp:bp+2], t.Day)
} else {
buf[bp] = ' ';
buf[bp+1] = byte(t.Day + '0')
}
bp += 2;
case 'H': // %H hour 00-23
- _Decimal(buf[bp:bp+2], t.Hour);
+ decimal(buf[bp:bp+2], t.Hour);
bp += 2;
case 'M': // %M minute 00-59
- _Decimal(buf[bp:bp+2], t.Minute);
+ decimal(buf[bp:bp+2], t.Minute);
bp += 2;
case 'S': // %S second 00-59
- _Decimal(buf[bp:bp+2], t.Second);
+ decimal(buf[bp:bp+2], t.Second);
bp += 2;
case 'Y': // %Y year 2008
- _Decimal(buf[bp:bp+4], int(t.Year));
+ decimal(buf[bp:bp+4], int(t.Year));
bp += 4;
case 'y': // %y year 08
- _Decimal(buf[bp:bp+2], int(t.Year%100));
+ decimal(buf[bp:bp+2], int(t.Year%100));
bp += 2;
case 'Z':
- bp = _AddString(buf, bp, t.Zone);
+ bp = addString(buf, bp, t.Zone);
default:
buf[bp] = '%';
buf[bp+1] = fmt[i];
// ANSI C asctime: Sun Nov 6 08:49:37 1994
func (t *Time) Asctime() string {
- return _Format(t, "%a %b %e %H:%M:%S %Y")
+ return format(t, "%a %b %e %H:%M:%S %Y")
}
-// RFC 850: Sunday, 06-Nov-94 08:49:37 GMT
+// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC
func (t *Time) RFC850() string {
- return _Format(t, "%A, %d-%b-%y %H:%M:%S %Z")
+ return format(t, "%A, %d-%b-%y %H:%M:%S %Z")
}
-// RFC 1123: Sun, 06 Nov 1994 08:49:37 GMT
+// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC
func (t *Time) RFC1123() string {
- return _Format(t, "%a, %d %b %Y %H:%M:%S %Z")
+ return format(t, "%a, %d %b %Y %H:%M:%S %Z")
}
-// date(1) - Sun Nov 6 08:49:37 GMT 1994
+// date(1) - Sun Nov 6 08:49:37 UTC 1994
func (t *Time) String() string {
- return _Format(t, "%a %b %e %H:%M:%S %Z %Y")
+ return format(t, "%a %b %e %H:%M:%S %Z %Y")
}
maketest \
lib/fmt\
lib/hash\
+ lib/io\
lib/json\
lib/math\
lib/net\