summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/testsuite/go.test/test/env.go15
-rw-r--r--gcc/testsuite/go.test/test/fixedbugs/bug262.go4
-rw-r--r--libgo/MERGE2
-rw-r--r--libgo/Makefile.am9
-rw-r--r--libgo/Makefile.in9
-rw-r--r--libgo/go/bufio/bufio.go9
-rw-r--r--libgo/go/bufio/bufio_test.go21
-rw-r--r--libgo/go/bytes/bytes.go2
-rw-r--r--libgo/go/bytes/bytes_test.go41
-rw-r--r--libgo/go/bytes/example_test.go4
-rw-r--r--libgo/go/compress/flate/deflate_test.go7
-rw-r--r--libgo/go/container/heap/example_test.go42
-rw-r--r--libgo/go/crypto/dsa/dsa.go2
-rw-r--r--libgo/go/crypto/md5/md5_test.go13
-rw-r--r--libgo/go/crypto/sha1/sha1_test.go12
-rw-r--r--libgo/go/crypto/tls/handshake_client.go4
-rw-r--r--libgo/go/crypto/tls/handshake_server.go4
-rw-r--r--libgo/go/database/sql/convert.go4
-rw-r--r--libgo/go/database/sql/driver/driver.go51
-rw-r--r--libgo/go/database/sql/driver/types.go80
-rw-r--r--libgo/go/database/sql/fakedb_test.go16
-rw-r--r--libgo/go/database/sql/sql.go54
-rw-r--r--libgo/go/debug/dwarf/open.go5
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.c8
-rwxr-xr-xlibgo/go/debug/dwarf/testdata/typedef.elfbin10837 -> 12448 bytes
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.machobin5256 -> 5024 bytes
-rw-r--r--libgo/go/debug/dwarf/type.go36
-rw-r--r--libgo/go/debug/dwarf/type_test.go19
-rw-r--r--libgo/go/debug/gosym/pclntab_test.go35
-rw-r--r--libgo/go/encoding/gob/decode.go14
-rw-r--r--libgo/go/encoding/gob/encoder_test.go51
-rw-r--r--libgo/go/encoding/gob/type.go16
-rw-r--r--libgo/go/encoding/json/decode.go14
-rw-r--r--libgo/go/encoding/json/decode_test.go29
-rw-r--r--libgo/go/encoding/json/encode.go5
-rw-r--r--libgo/go/encoding/xml/marshal.go89
-rw-r--r--libgo/go/encoding/xml/read.go55
-rw-r--r--libgo/go/errors/errors_test.go30
-rw-r--r--libgo/go/exp/inotify/inotify_linux_test.go20
-rw-r--r--libgo/go/exp/norm/composition.go85
-rw-r--r--libgo/go/exp/norm/composition_test.go32
-rw-r--r--libgo/go/exp/norm/input.go10
-rw-r--r--libgo/go/exp/norm/iter.go286
-rw-r--r--libgo/go/exp/norm/iter_test.go186
-rw-r--r--libgo/go/exp/norm/normalize.go15
-rw-r--r--libgo/go/exp/norm/normalize_test.go55
-rw-r--r--libgo/go/exp/norm/normregtest.go11
-rw-r--r--libgo/go/exp/proxy/socks5.go6
-rw-r--r--libgo/go/exp/terminal/terminal.go4
-rw-r--r--libgo/go/exp/winfsnotify/winfsnotify_test.go9
-rw-r--r--libgo/go/go/doc/example.go65
-rw-r--r--libgo/go/go/doc/reader.go10
-rw-r--r--libgo/go/go/doc/synopsis.go52
-rw-r--r--libgo/go/go/doc/synopsis_test.go44
-rw-r--r--libgo/go/go/doc/testdata/benchmark.go6
-rw-r--r--libgo/go/go/doc/testdata/testing.1.golden2
-rw-r--r--libgo/go/go/doc/testdata/testing.go10
-rw-r--r--libgo/go/go/parser/parser.go261
-rw-r--r--libgo/go/go/printer/nodes.go106
-rw-r--r--libgo/go/go/printer/printer.go8
-rw-r--r--libgo/go/go/printer/printer_test.go8
-rw-r--r--libgo/go/go/printer/testdata/comments.golden43
-rw-r--r--libgo/go/go/printer/testdata/comments.input31
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden6
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw6
-rw-r--r--libgo/go/go/scanner/scanner.go18
-rw-r--r--libgo/go/html/template/clone.go90
-rw-r--r--libgo/go/html/template/clone_test.go175
-rw-r--r--libgo/go/html/template/content.go18
-rw-r--r--libgo/go/html/template/content_test.go40
-rw-r--r--libgo/go/html/template/doc.go12
-rw-r--r--libgo/go/html/template/escape.go94
-rw-r--r--libgo/go/html/template/template.go73
-rw-r--r--libgo/go/image/decode_example_test.go79
-rw-r--r--libgo/go/image/ycbcr_test.go3
-rw-r--r--libgo/go/io/ioutil/tempfile.go4
-rw-r--r--libgo/go/log/syslog/syslog.go2
-rw-r--r--libgo/go/log/syslog/syslog_test.go3
-rw-r--r--libgo/go/log/syslog/syslog_unix.go2
-rw-r--r--libgo/go/math/big/nat_test.go3
-rw-r--r--libgo/go/math/rand/rand.go13
-rw-r--r--libgo/go/math/rand/rand_test.go6
-rw-r--r--libgo/go/net/dialgoogle_test.go4
-rw-r--r--libgo/go/net/fd.go6
-rw-r--r--libgo/go/net/fd_windows.go20
-rw-r--r--libgo/go/net/file.go8
-rw-r--r--libgo/go/net/file_plan9.go7
-rw-r--r--libgo/go/net/hosts_test.go2
-rw-r--r--libgo/go/net/http/cookie_test.go28
-rw-r--r--libgo/go/net/http/example_test.go51
-rw-r--r--libgo/go/net/http/fs_test.go13
-rw-r--r--libgo/go/net/http/httputil/persist.go4
-rw-r--r--libgo/go/net/http/pprof/pprof.go81
-rw-r--r--libgo/go/net/http/request.go4
-rw-r--r--libgo/go/net/http/serve_test.go5
-rw-r--r--libgo/go/net/http/server.go11
-rw-r--r--libgo/go/net/http/transport_test.go6
-rw-r--r--libgo/go/net/interface_linux.go30
-rw-r--r--libgo/go/net/interface_test.go8
-rw-r--r--libgo/go/net/ipraw_test.go62
-rw-r--r--libgo/go/net/iprawsock_plan9.go26
-rw-r--r--libgo/go/net/iprawsock_posix.go24
-rw-r--r--libgo/go/net/ipsock_plan9.go15
-rw-r--r--libgo/go/net/ipsock_posix.go11
-rw-r--r--libgo/go/net/lookup_plan9.go3
-rw-r--r--libgo/go/net/lookup_test.go12
-rw-r--r--libgo/go/net/multicast_test.go181
-rw-r--r--libgo/go/net/net.go60
-rw-r--r--libgo/go/net/parse.go2
-rw-r--r--libgo/go/net/rpc/server_test.go4
-rw-r--r--libgo/go/net/server_test.go2
-rw-r--r--libgo/go/net/smtp/smtp.go7
-rw-r--r--libgo/go/net/smtp/smtp_test.go95
-rw-r--r--libgo/go/net/sock.go12
-rw-r--r--libgo/go/net/tcpsock_plan9.go16
-rw-r--r--libgo/go/net/tcpsock_posix.go49
-rw-r--r--libgo/go/net/testdata/hosts12
-rw-r--r--libgo/go/net/testdata/igmp24
-rw-r--r--libgo/go/net/testdata/igmp618
-rw-r--r--libgo/go/net/textproto/reader.go13
-rw-r--r--libgo/go/net/textproto/reader_test.go23
-rw-r--r--libgo/go/net/textproto/textproto.go3
-rw-r--r--libgo/go/net/udpsock_plan9.go19
-rw-r--r--libgo/go/net/udpsock_posix.go28
-rw-r--r--libgo/go/net/unixsock_plan9.go26
-rw-r--r--libgo/go/net/unixsock_posix.go46
-rw-r--r--libgo/go/net/url/url.go51
-rw-r--r--libgo/go/net/url/url_test.go35
-rw-r--r--libgo/go/old/netchan/netchan_test.go12
-rw-r--r--libgo/go/os/dir_plan9.go11
-rw-r--r--libgo/go/os/env.go23
-rw-r--r--libgo/go/os/error.go12
-rw-r--r--libgo/go/os/error_plan9.go60
-rw-r--r--libgo/go/os/error_posix.go67
-rw-r--r--libgo/go/os/exec/exec.go16
-rw-r--r--libgo/go/os/exec/lp_plan9.go3
-rw-r--r--libgo/go/os/exec/lp_unix.go2
-rw-r--r--libgo/go/os/exec/lp_windows.go4
-rw-r--r--libgo/go/os/exec_plan9.go97
-rw-r--r--libgo/go/os/exec_posix.go83
-rw-r--r--libgo/go/os/exec_unix.go52
-rw-r--r--libgo/go/os/exec_windows.go21
-rw-r--r--libgo/go/os/file.go49
-rw-r--r--libgo/go/os/file_plan9.go42
-rw-r--r--libgo/go/os/file_posix.go17
-rw-r--r--libgo/go/os/file_unix.go2
-rw-r--r--libgo/go/os/getwd.go4
-rw-r--r--libgo/go/os/os_test.go36
-rw-r--r--libgo/go/os/path.go9
-rw-r--r--libgo/go/os/path_test.go32
-rw-r--r--libgo/go/os/signal/signal_stub.go11
-rw-r--r--libgo/go/os/stat_plan9.go4
-rw-r--r--libgo/go/path/example_test.go26
-rw-r--r--libgo/go/path/filepath/match.go6
-rw-r--r--libgo/go/path/filepath/path.go19
-rw-r--r--libgo/go/path/filepath/path_test.go5
-rw-r--r--libgo/go/path/match.go4
-rw-r--r--libgo/go/path/path.go21
-rw-r--r--libgo/go/runtime/debug.go51
-rw-r--r--libgo/go/runtime/extern.go15
-rw-r--r--libgo/go/runtime/malloc1.go (renamed from gcc/testsuite/go.test/test/malloc1.go)4
-rw-r--r--libgo/go/runtime/mallocrand.go (renamed from gcc/testsuite/go.test/test/mallocrand.go)4
-rw-r--r--libgo/go/runtime/mallocrep.go (renamed from gcc/testsuite/go.test/test/mallocrep.go)4
-rw-r--r--libgo/go/runtime/mallocrep1.go (renamed from gcc/testsuite/go.test/test/mallocrep1.go)4
-rw-r--r--libgo/go/runtime/mem.go14
-rw-r--r--libgo/go/runtime/pprof/pprof.go504
-rw-r--r--libgo/go/sort/example_interface_test.go77
-rw-r--r--libgo/go/sort/example_reverse_test.go30
-rw-r--r--libgo/go/sort/example_test.go2
-rw-r--r--libgo/go/strconv/atof.go6
-rw-r--r--libgo/go/strconv/itoa_test.go1
-rw-r--r--libgo/go/strings/example_test.go93
-rw-r--r--libgo/go/sync/cond.go15
-rw-r--r--libgo/go/sync/example_test.go34
-rw-r--r--libgo/go/sync/export_test.go9
-rw-r--r--libgo/go/sync/mutex.go9
-rw-r--r--libgo/go/sync/mutex_test.go4
-rw-r--r--libgo/go/sync/runtime.go18
-rw-r--r--libgo/go/sync/runtime_sema_test.go (renamed from libgo/go/runtime/sema_test.go)15
-rw-r--r--libgo/go/sync/rwmutex.go13
-rw-r--r--libgo/go/sync/waitgroup.go9
-rw-r--r--libgo/go/testing/testing.go19
-rw-r--r--libgo/go/text/tabwriter/example_test.go38
-rw-r--r--libgo/go/text/tabwriter/tabwriter.go6
-rw-r--r--libgo/go/text/tabwriter/tabwriter_test.go3
-rw-r--r--libgo/go/text/template/doc.go24
-rw-r--r--libgo/go/text/template/exec.go10
-rw-r--r--libgo/go/text/template/exec_test.go8
-rw-r--r--libgo/go/text/template/multi_test.go2
-rw-r--r--libgo/go/text/template/parse/parse.go6
-rw-r--r--libgo/go/text/template/template.go8
-rw-r--r--libgo/go/time/example_test.go2
-rw-r--r--libgo/go/time/sys_plan9.go38
-rw-r--r--libgo/go/time/sys_unix.go38
-rw-r--r--libgo/go/time/sys_windows.go64
-rw-r--r--libgo/go/time/tick_test.go3
-rw-r--r--libgo/go/time/zoneinfo.go23
-rw-r--r--libgo/go/time/zoneinfo_plan9.go27
-rw-r--r--libgo/go/time/zoneinfo_read.go341
-rw-r--r--libgo/go/time/zoneinfo_unix.go197
-rw-r--r--libgo/go/time/zoneinfo_windows.go6
-rw-r--r--libgo/runtime/malloc.goc13
-rw-r--r--libgo/runtime/malloc.h19
-rw-r--r--libgo/runtime/mgc0.c44
-rw-r--r--libgo/runtime/mheap.c88
-rw-r--r--libgo/runtime/mprof.goc129
-rw-r--r--libgo/runtime/proc.c29
-rw-r--r--libgo/runtime/runtime.h18
-rw-r--r--libgo/runtime/sema.goc6
-rw-r--r--libgo/runtime/sigqueue.goc2
210 files changed, 4875 insertions, 2011 deletions
diff --git a/gcc/testsuite/go.test/test/env.go b/gcc/testsuite/go.test/test/env.go
index a4b9d05d87d..3c8e4232838 100644
--- a/gcc/testsuite/go.test/test/env.go
+++ b/gcc/testsuite/go.test/test/env.go
@@ -4,6 +4,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Test that the Go environment variables are present and accessible through
+// package os and package runtime.
+
package main
import (
@@ -12,18 +15,14 @@ import (
)
func main() {
- ga, e0 := os.Getenverror("GOARCH")
- if e0 != nil {
- print("$GOARCH: ", e0.Error(), "\n")
- os.Exit(1)
- }
+ ga := os.Getenv("GOARCH")
if ga != runtime.GOARCH {
print("$GOARCH=", ga, "!= runtime.GOARCH=", runtime.GOARCH, "\n")
os.Exit(1)
}
- xxx, e1 := os.Getenverror("DOES_NOT_EXIST")
- if e1 != os.ENOENV {
- print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.Error(), "\n")
+ xxx := os.Getenv("DOES_NOT_EXIST")
+ if xxx != "" {
+ print("$DOES_NOT_EXIST=", xxx, "\n")
os.Exit(1)
}
}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug262.go b/gcc/testsuite/go.test/test/fixedbugs/bug262.go
index f5f2c355322..ebca7905f9a 100644
--- a/gcc/testsuite/go.test/test/fixedbugs/bug262.go
+++ b/gcc/testsuite/go.test/test/fixedbugs/bug262.go
@@ -7,7 +7,7 @@
package main
import (
- "os"
+ "errors"
"strconv"
)
@@ -44,7 +44,7 @@ func main() {
}
mm := make(map[string]error)
trace = ""
- mm["abc"] = os.EINVAL
+ mm["abc"] = errors.New("invalid")
*i(), mm[f()] = strconv.Atoi(h())
if mm["abc"] != nil || trace != "ifh" {
println("BUG1", mm["abc"], trace)
diff --git a/libgo/MERGE b/libgo/MERGE
index a760ae9c8de..9605a8a9040 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-43cf9b39b647
+96bd78e7d35e
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 1167a3f7ed0..eb764df0eab 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -504,7 +504,7 @@ runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
mv -f $@.tmp $@
sema.c: $(srcdir)/runtime/sema.goc goc2c
- ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ ./goc2c --gcc --go-prefix libgo_sync $< > $@.tmp
mv -f $@.tmp $@
sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
@@ -847,6 +847,7 @@ go_sync_files = \
go/sync/cond.go \
go/sync/mutex.go \
go/sync/once.go \
+ go/sync/runtime.go \
go/sync/rwmutex.go \
go/sync/waitgroup.go
@@ -878,6 +879,7 @@ go_time_files = \
go/time/tick.go \
go/time/time.go \
go/time/zoneinfo.go \
+ go/time/zoneinfo_read.go \
go/time/zoneinfo_unix.go
go_unicode_files = \
@@ -1091,6 +1093,7 @@ go_exp_norm_files = \
go/exp/norm/composition.go \
go/exp/norm/forminfo.go \
go/exp/norm/input.go \
+ go/exp/norm/iter.go \
go/exp/norm/normalize.go \
go/exp/norm/readwriter.go \
go/exp/norm/tables.go \
@@ -1132,7 +1135,8 @@ go_go_doc_files = \
go/go/doc/example.go \
go/go/doc/exports.go \
go/go/doc/filter.go \
- go/go/doc/reader.go
+ go/go/doc/reader.go \
+ go/go/doc/synopsis.go
go_go_parser_files = \
go/go/parser/interface.go \
go/go/parser/parser.go
@@ -1159,7 +1163,6 @@ go_hash_fnv_files = \
go_html_template_files = \
go/html/template/attr.go \
- go/html/template/clone.go \
go/html/template/content.go \
go/html/template/context.go \
go/html/template/css.go \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index b1d1d4c561e..4604e560c9b 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -1157,6 +1157,7 @@ go_sync_files = \
go/sync/cond.go \
go/sync/mutex.go \
go/sync/once.go \
+ go/sync/runtime.go \
go/sync/rwmutex.go \
go/sync/waitgroup.go
@@ -1182,6 +1183,7 @@ go_time_files = \
go/time/tick.go \
go/time/time.go \
go/time/zoneinfo.go \
+ go/time/zoneinfo_read.go \
go/time/zoneinfo_unix.go
go_unicode_files = \
@@ -1427,6 +1429,7 @@ go_exp_norm_files = \
go/exp/norm/composition.go \
go/exp/norm/forminfo.go \
go/exp/norm/input.go \
+ go/exp/norm/iter.go \
go/exp/norm/normalize.go \
go/exp/norm/readwriter.go \
go/exp/norm/tables.go \
@@ -1474,7 +1477,8 @@ go_go_doc_files = \
go/go/doc/example.go \
go/go/doc/exports.go \
go/go/doc/filter.go \
- go/go/doc/reader.go
+ go/go/doc/reader.go \
+ go/go/doc/synopsis.go
go_go_parser_files = \
go/go/parser/interface.go \
@@ -1508,7 +1512,6 @@ go_hash_fnv_files = \
go_html_template_files = \
go/html/template/attr.go \
- go/html/template/clone.go \
go/html/template/content.go \
go/html/template/context.go \
go/html/template/css.go \
@@ -4318,7 +4321,7 @@ runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c
mv -f $@.tmp $@
sema.c: $(srcdir)/runtime/sema.goc goc2c
- ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ ./goc2c --gcc --go-prefix libgo_sync $< > $@.tmp
mv -f $@.tmp $@
sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index 156dddfcf07..6f3b1eec971 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -106,9 +106,12 @@ func (b *Reader) Peek(n int) ([]byte, error) {
if m > n {
m = n
}
- err := b.readErr()
- if m < n && err == nil {
- err = ErrBufferFull
+ var err error
+ if m < n {
+ err = b.readErr()
+ if err == nil {
+ err = ErrBufferFull
+ }
}
return b.buf[b.r : b.r+m], err
}
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 9aec61ec426..a43cbd23a64 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -539,6 +539,27 @@ func TestPeek(t *testing.T) {
if _, err := buf.Peek(1); err != io.EOF {
t.Fatalf("want EOF got %v", err)
}
+
+ // Test for issue 3022, not exposing a reader's error on a successful Peek.
+ buf = NewReaderSize(dataAndEOFReader("abcd"), 32)
+ if s, err := buf.Peek(2); string(s) != "ab" || err != nil {
+ t.Errorf(`Peek(2) on "abcd", EOF = %q, %v; want "ab", nil`, string(s), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+ t.Errorf(`Peek(4) on "abcd", EOF = %q, %v; want "abcd", nil`, string(s), err)
+ }
+ if n, err := buf.Read(p[0:5]); string(p[0:n]) != "abcd" || err != nil {
+ t.Fatalf("Read after peek = %q, %v; want abcd, EOF", p[0:n], err)
+ }
+ if n, err := buf.Read(p[0:1]); string(p[0:n]) != "" || err != io.EOF {
+ t.Fatalf(`second Read after peek = %q, %v; want "", EOF`, p[0:n], err)
+ }
+}
+
+type dataAndEOFReader string
+
+func (r dataAndEOFReader) Read(p []byte) (int, error) {
+ return copy(p, r), io.EOF
}
func TestPeekThenUnreadRune(t *testing.T) {
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index e94a0ec5c4f..7d1426fb417 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -13,6 +13,7 @@ import (
// Compare returns an integer comparing the two byte arrays lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
+// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int {
m := len(a)
if m > len(b) {
@@ -37,6 +38,7 @@ func Compare(a, b []byte) int {
}
// Equal returns a boolean reporting whether a == b.
+// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool
func equalPortable(a, b []byte) bool {
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index 2a1d41b910e..000f235176d 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -46,32 +46,39 @@ type BinOpTest struct {
i int
}
-var comparetests = []BinOpTest{
- {"", "", 0},
- {"a", "", 1},
- {"", "a", -1},
- {"abc", "abc", 0},
- {"ab", "abc", -1},
- {"abc", "ab", 1},
- {"x", "ab", 1},
- {"ab", "x", -1},
- {"x", "a", 1},
- {"b", "x", -1},
+var compareTests = []struct {
+ a, b []byte
+ i int
+}{
+ {[]byte(""), []byte(""), 0},
+ {[]byte("a"), []byte(""), 1},
+ {[]byte(""), []byte("a"), -1},
+ {[]byte("abc"), []byte("abc"), 0},
+ {[]byte("ab"), []byte("abc"), -1},
+ {[]byte("abc"), []byte("ab"), 1},
+ {[]byte("x"), []byte("ab"), 1},
+ {[]byte("ab"), []byte("x"), -1},
+ {[]byte("x"), []byte("a"), 1},
+ {[]byte("b"), []byte("x"), -1},
+ // nil tests
+ {nil, nil, 0},
+ {[]byte(""), nil, 0},
+ {nil, []byte(""), 0},
+ {[]byte("a"), nil, 1},
+ {nil, []byte("a"), -1},
}
func TestCompare(t *testing.T) {
- for _, tt := range comparetests {
- a := []byte(tt.a)
- b := []byte(tt.b)
- cmp := Compare(a, b)
+ for _, tt := range compareTests {
+ cmp := Compare(tt.a, tt.b)
if cmp != tt.i {
t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
}
- eql := Equal(a, b)
+ eql := Equal(tt.a, tt.b)
if eql != (tt.i == 0) {
t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
}
- eql = EqualPortable(a, b)
+ eql = EqualPortable(tt.a, tt.b)
if eql != (tt.i == 0) {
t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql)
}
diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go
index 0234a012a4e..6fe8cd5a90c 100644
--- a/libgo/go/bytes/example_test.go
+++ b/libgo/go/bytes/example_test.go
@@ -11,18 +11,18 @@ import (
"os"
)
-// Hello world!
func ExampleBuffer() {
var b Buffer // A Buffer needs no initialization.
b.Write([]byte("Hello "))
b.Write([]byte("world!"))
b.WriteTo(os.Stdout)
+ // Output: Hello world!
}
-// Gophers rule!
func ExampleBuffer_reader() {
// A Buffer can turn a string or a []byte into an io.Reader.
buf := NewBufferString("R29waGVycyBydWxlIQ==")
dec := base64.NewDecoder(base64.StdEncoding, buf)
io.Copy(os.Stdout, dec)
+ // Output: Gophers rule!
}
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
index a76e2d930f6..543c5950586 100644
--- a/libgo/go/compress/flate/deflate_test.go
+++ b/libgo/go/compress/flate/deflate_test.go
@@ -306,6 +306,9 @@ func TestDeflateInflateString(t *testing.T) {
t.Error(err)
}
testToFromWithLimit(t, gold, test.label, test.limit)
+ if testing.Short() {
+ break
+ }
}
}
@@ -363,6 +366,10 @@ func TestWriterDict(t *testing.T) {
// See http://code.google.com/p/go/issues/detail?id=2508
func TestRegression2508(t *testing.T) {
+ if testing.Short() {
+ t.Logf("test disabled with -short")
+ return
+ }
w, err := NewWriter(ioutil.Discard, 1)
if err != nil {
t.Fatalf("NewWriter: %v", err)
diff --git a/libgo/go/container/heap/example_test.go b/libgo/go/container/heap/example_test.go
index c3b8d94cb2a..2050bc83591 100644
--- a/libgo/go/container/heap/example_test.go
+++ b/libgo/go/container/heap/example_test.go
@@ -57,11 +57,26 @@ func (pq *PriorityQueue) Pop() interface{} {
return item
}
-// 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
-func ExampleInterface() {
- // The full code of this example, including the methods that implement
- // heap.Interface, is in the file src/pkg/container/heap/example_test.go.
+// update is not used by the example but shows how to take the top item from
+// the queue, update its priority and value, and put it back.
+func (pq *PriorityQueue) update(value string, priority int) {
+ item := heap.Pop(pq).(*Item)
+ item.value = value
+ item.priority = priority
+ heap.Push(pq, item)
+}
+// changePriority is not used by the example but shows how to change the
+// priority of an arbitrary item.
+func (pq *PriorityQueue) changePriority(item *Item, priority int) {
+ heap.Remove(pq, item.index)
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// This example pushes 10 items into a PriorityQueue and takes them out in
+// order of priority.
+func Example() {
const nItem = 10
// Random priorities for the items (a permutation of 0..9, times 11)).
priorities := [nItem]int{
@@ -85,21 +100,6 @@ func ExampleInterface() {
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
-}
-
-// update is not used by the example but shows how to take the top item from the queue,
-// update its priority and value, and put it back.
-func (pq *PriorityQueue) update(value string, priority int) {
- item := heap.Pop(pq).(*Item)
- item.value = value
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// changePriority is not used by the example but shows how to change the priority of an arbitrary
-// item.
-func (pq *PriorityQueue) changePriority(item *Item, priority int) {
- heap.Remove(pq, item.index)
- item.priority = priority
- heap.Push(pq, item)
+ // Output:
+ // 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
}
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index f7c47831790..05766a2f136 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
+// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
package dsa
import (
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
index b15e4668c32..aae875464f9 100644
--- a/libgo/go/crypto/md5/md5_test.go
+++ b/libgo/go/crypto/md5/md5_test.go
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package md5
+package md5_test
import (
+ "crypto/md5"
"fmt"
"io"
"testing"
@@ -52,7 +53,7 @@ var golden = []md5Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := New()
+ c := md5.New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
@@ -69,3 +70,11 @@ func TestGolden(t *testing.T) {
}
}
}
+
+func ExampleNew() {
+ h := md5.New()
+ io.WriteString(h, "The fog is getting thicker!")
+ io.WriteString(h, "And Leon's getting laaarger!")
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: e2c569be17396eca2a2e3c11578123ed
+}
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
index c23df6c41e9..2dc14ac9868 100644
--- a/libgo/go/crypto/sha1/sha1_test.go
+++ b/libgo/go/crypto/sha1/sha1_test.go
@@ -4,9 +4,10 @@
// SHA1 hash algorithm. See RFC 3174.
-package sha1
+package sha1_test
import (
+ "crypto/sha1"
"fmt"
"io"
"testing"
@@ -54,7 +55,7 @@ var golden = []sha1Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := New()
+ c := sha1.New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
@@ -71,3 +72,10 @@ func TestGolden(t *testing.T) {
}
}
}
+
+func ExampleNew() {
+ h := sha1.New()
+ io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+ fmt.Printf("% x", h.Sum(nil))
+ // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
+}
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index 687e5ef11b4..0d7b806ff5b 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -273,7 +273,7 @@ func (c *Conn) clientHandshake() error {
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
- clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
+ clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */)
clientHash := suite.mac(c.vers, clientMAC)
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
@@ -294,7 +294,7 @@ func (c *Conn) clientHandshake() error {
finishedHash.Write(finished.marshal())
c.writeRecord(recordTypeHandshake, finished.marshal())
- serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
+ serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */)
serverHash := suite.mac(c.vers, serverMAC)
c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.readRecord(recordTypeChangeCipherSpec)
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index fb53767f3e0..23ec5587235 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -295,7 +295,7 @@ FindCipherSuite:
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromPreMasterSecret(c.vers, preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
- clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
+ clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */)
clientHash := suite.mac(c.vers, clientMAC)
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.readRecord(recordTypeChangeCipherSpec)
@@ -333,7 +333,7 @@ FindCipherSuite:
finishedHash.Write(clientFinished.marshal())
- serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
+ serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */)
serverHash := suite.mac(c.vers, serverMAC)
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go
index 4afa2bef753..bfcb03ccf8d 100644
--- a/libgo/go/database/sql/convert.go
+++ b/libgo/go/database/sql/convert.go
@@ -17,8 +17,8 @@ import (
// subsetTypeArgs takes a slice of arguments from callers of the sql
// package and converts them into a slice of the driver package's
// "subset types".
-func subsetTypeArgs(args []interface{}) ([]interface{}, error) {
- out := make([]interface{}, len(args))
+func subsetTypeArgs(args []interface{}) ([]driver.Value, error) {
+ out := make([]driver.Value, len(args))
for n, arg := range args {
var err error
out[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go
index b9300776050..7f986b80f2c 100644
--- a/libgo/go/database/sql/driver/driver.go
+++ b/libgo/go/database/sql/driver/driver.go
@@ -6,21 +6,20 @@
// drivers as used by package sql.
//
// Most code should use package sql.
-//
-// Drivers only need to be aware of a subset of Go's types. The sql package
-// will convert all types into one of the following:
+package driver
+
+import "errors"
+
+// A driver Value is a value that drivers must be able to handle.
+// A Value is either nil or an instance of one of these types:
//
// int64
// float64
// bool
-// nil
// []byte
// string [*] everywhere except from Rows.Next.
// time.Time
-//
-package driver
-
-import "errors"
+type Value interface{}
// Driver is the interface that must be implemented by a database
// driver.
@@ -50,11 +49,9 @@ var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
// first prepare a query, execute the statement, and then close the
// statement.
//
-// All arguments are of a subset type as defined in the package docs.
-//
// Exec may return ErrSkip.
type Execer interface {
- Exec(query string, args []interface{}) (Result, error)
+ Exec(query string, args []Value) (Result, error)
}
// Conn is a connection to a database. It is not used concurrently
@@ -127,18 +124,17 @@ type Stmt interface {
NumInput() int
// Exec executes a query that doesn't return rows, such
- // as an INSERT or UPDATE. The args are all of a subset
- // type as defined above.
- Exec(args []interface{}) (Result, error)
+ // as an INSERT or UPDATE.
+ Exec(args []Value) (Result, error)
// Exec executes a query that may return rows, such as a
- // SELECT. The args of all of a subset type as defined above.
- Query(args []interface{}) (Rows, error)
+ // SELECT.
+ Query(args []Value) (Rows, error)
}
// ColumnConverter may be optionally implemented by Stmt if the
// the statement is aware of its own columns' types and can
-// convert from any type to a driver subset type.
+// convert from any type to a driver Value.
type ColumnConverter interface {
// ColumnConverter returns a ValueConverter for the provided
// column index. If the type of a specific column isn't known
@@ -162,12 +158,12 @@ type Rows interface {
// the provided slice. The provided slice will be the same
// size as the Columns() are wide.
//
- // The dest slice may be populated with only with values
- // of subset types defined above, but excluding string.
+ // The dest slice may be populated only with
+ // a driver Value type, but excluding string.
// All string values must be converted to []byte.
//
// Next should return io.EOF when there are no more rows.
- Next(dest []interface{}) error
+ Next(dest []Value) error
}
// Tx is a transaction.
@@ -190,18 +186,19 @@ func (v RowsAffected) RowsAffected() (int64, error) {
return int64(v), nil
}
-// DDLSuccess is a pre-defined Result for drivers to return when a DDL
-// command succeeds.
-var DDLSuccess ddlSuccess
+// ResultNoRows is a pre-defined Result for drivers to return when a DDL
+// command (such as a CREATE TABLE) succeeds. It returns an error for both
+// LastInsertId and RowsAffected.
+var ResultNoRows noRows
-type ddlSuccess struct{}
+type noRows struct{}
-var _ Result = ddlSuccess{}
+var _ Result = noRows{}
-func (ddlSuccess) LastInsertId() (int64, error) {
+func (noRows) LastInsertId() (int64, error) {
return 0, errors.New("no LastInsertId available after DDL statement")
}
-func (ddlSuccess) RowsAffected() (int64, error) {
+func (noRows) RowsAffected() (int64, error) {
return 0, errors.New("no RowsAffected available after DDL statement")
}
diff --git a/libgo/go/database/sql/driver/types.go b/libgo/go/database/sql/driver/types.go
index ce3c943ead2..3305354dfd0 100644
--- a/libgo/go/database/sql/driver/types.go
+++ b/libgo/go/database/sql/driver/types.go
@@ -17,28 +17,28 @@ import (
// driver package to provide consistent implementations of conversions
// between drivers. The ValueConverters have several uses:
//
-// * converting from the subset types as provided by the sql package
+// * converting from the Value types as provided by the sql package
// into a database table's specific column type and making sure it
// fits, such as making sure a particular int64 fits in a
// table's uint16 column.
//
// * converting a value as given from the database into one of the
-// subset types.
+// driver Value types.
//
-// * by the sql package, for converting from a driver's subset type
+// * by the sql package, for converting from a driver's Value type
// to a user's type in a scan.
type ValueConverter interface {
- // ConvertValue converts a value to a restricted subset type.
- ConvertValue(v interface{}) (interface{}, error)
+ // ConvertValue converts a value to a driver Value.
+ ConvertValue(v interface{}) (Value, error)
}
-// SubsetValuer is the interface providing the SubsetValue method.
+// Valuer is the interface providing the Value method.
//
-// Types implementing SubsetValuer interface are able to convert
-// themselves to one of the driver's allowed subset values.
-type SubsetValuer interface {
- // SubsetValue returns a driver parameter subset value.
- SubsetValue() (interface{}, error)
+// Types implementing Valuer interface are able to convert
+// themselves to a driver Value.
+type Valuer interface {
+ // Value returns a driver Value.
+ Value() (Value, error)
}
// Bool is a ValueConverter that converts input values to bools.
@@ -59,7 +59,7 @@ var _ ValueConverter = boolType{}
func (boolType) String() string { return "Bool" }
-func (boolType) ConvertValue(src interface{}) (interface{}, error) {
+func (boolType) ConvertValue(src interface{}) (Value, error) {
switch s := src.(type) {
case bool:
return s, nil
@@ -104,7 +104,7 @@ type int32Type struct{}
var _ ValueConverter = int32Type{}
-func (int32Type) ConvertValue(v interface{}) (interface{}, error) {
+func (int32Type) ConvertValue(v interface{}) (Value, error) {
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -137,7 +137,7 @@ var String stringType
type stringType struct{}
-func (stringType) ConvertValue(v interface{}) (interface{}, error) {
+func (stringType) ConvertValue(v interface{}) (Value, error) {
switch v.(type) {
case string, []byte:
return v, nil
@@ -151,7 +151,7 @@ type Null struct {
Converter ValueConverter
}
-func (n Null) ConvertValue(v interface{}) (interface{}, error) {
+func (n Null) ConvertValue(v interface{}) (Value, error) {
if v == nil {
return nil, nil
}
@@ -164,28 +164,17 @@ type NotNull struct {
Converter ValueConverter
}
-func (n NotNull) ConvertValue(v interface{}) (interface{}, error) {
+func (n NotNull) ConvertValue(v interface{}) (Value, error) {
if v == nil {
return nil, fmt.Errorf("nil value not allowed")
}
return n.Converter.ConvertValue(v)
}
-// IsParameterSubsetType reports whether v is of a valid type for a
-// parameter. These types are:
-//
-// int64
-// float64
-// bool
-// nil
-// []byte
-// time.Time
-// string
-//
-// This is the same list as IsScanSubsetType, with the addition of
-// string.
-func IsParameterSubsetType(v interface{}) bool {
- if IsScanSubsetType(v) {
+// IsValue reports whether v is a valid Value parameter type.
+// Unlike IsScanValue, IsValue permits the string type.
+func IsValue(v interface{}) bool {
+ if IsScanValue(v) {
return true
}
if _, ok := v.(string); ok {
@@ -194,18 +183,9 @@ func IsParameterSubsetType(v interface{}) bool {
return false
}
-// IsScanSubsetType reports whether v is of a valid type for a
-// value populated by Rows.Next. These types are:
-//
-// int64
-// float64
-// bool
-// nil
-// []byte
-// time.Time
-//
-// This is the same list as IsParameterSubsetType, without string.
-func IsScanSubsetType(v interface{}) bool {
+// IsScanValue reports whether v is a valid Value scan type.
+// Unlike IsValue, IsScanValue does not permit the string type.
+func IsScanValue(v interface{}) bool {
if v == nil {
return true
}
@@ -221,7 +201,7 @@ func IsScanSubsetType(v interface{}) bool {
// ColumnConverter.
//
// DefaultParameterConverter returns the given value directly if
-// IsSubsetType(value). Otherwise integer type are converted to
+// IsValue(value). Otherwise integer type are converted to
// int64, floats to float64, and strings to []byte. Other types are
// an error.
var DefaultParameterConverter defaultConverter
@@ -230,18 +210,18 @@ type defaultConverter struct{}
var _ ValueConverter = defaultConverter{}
-func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) {
- if IsParameterSubsetType(v) {
+func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
+ if IsValue(v) {
return v, nil
}
- if svi, ok := v.(SubsetValuer); ok {
- sv, err := svi.SubsetValue()
+ if svi, ok := v.(Valuer); ok {
+ sv, err := svi.Value()
if err != nil {
return nil, err
}
- if !IsParameterSubsetType(sv) {
- return nil, fmt.Errorf("non-subset type %T returned from SubsetValue", sv)
+ if !IsValue(sv) {
+ return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
}
return sv, nil
}
diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go
index 889e2a25232..fc63f03740a 100644
--- a/libgo/go/database/sql/fakedb_test.go
+++ b/libgo/go/database/sql/fakedb_test.go
@@ -217,7 +217,7 @@ func (c *fakeConn) Close() error {
return nil
}
-func checkSubsetTypes(args []interface{}) error {
+func checkSubsetTypes(args []driver.Value) error {
for n, arg := range args {
switch arg.(type) {
case int64, float64, bool, nil, []byte, string, time.Time:
@@ -228,7 +228,7 @@ func checkSubsetTypes(args []interface{}) error {
return nil
}
-func (c *fakeConn) Exec(query string, args []interface{}) (driver.Result, error) {
+func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args of of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
@@ -379,7 +379,7 @@ func (s *fakeStmt) Close() error {
var errClosed = errors.New("fakedb: statement has been closed")
-func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
+func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
if s.closed {
return nil, errClosed
}
@@ -392,12 +392,12 @@ func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
switch s.cmd {
case "WIPE":
db.wipe()
- return driver.DDLSuccess, nil
+ return driver.ResultNoRows, nil
case "CREATE":
if err := db.createTable(s.table, s.colName, s.colType); err != nil {
return nil, err
}
- return driver.DDLSuccess, nil
+ return driver.ResultNoRows, nil
case "INSERT":
return s.execInsert(args)
}
@@ -405,7 +405,7 @@ func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd)
}
-func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) {
+func (s *fakeStmt) execInsert(args []driver.Value) (driver.Result, error) {
db := s.c.db
if len(args) != s.placeholders {
panic("error in pkg db; should only get here if size is correct")
@@ -441,7 +441,7 @@ func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) {
return driver.RowsAffected(1), nil
}
-func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) {
+func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if s.closed {
return nil, errClosed
}
@@ -548,7 +548,7 @@ func (rc *rowsCursor) Columns() []string {
return rc.cols
}
-func (rc *rowsCursor) Next(dest []interface{}) error {
+func (rc *rowsCursor) Next(dest []driver.Value) error {
if rc.closed {
return errors.New("fakedb: cursor is closed")
}
diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go
index f14a98c3cf2..62b551d89b5 100644
--- a/libgo/go/database/sql/sql.go
+++ b/libgo/go/database/sql/sql.go
@@ -62,8 +62,8 @@ func (ns *NullString) Scan(value interface{}) error {
return convertAssign(&ns.String, value)
}
-// SubsetValue implements the driver SubsetValuer interface.
-func (ns NullString) SubsetValue() (interface{}, error) {
+// Value implements the driver Valuer interface.
+func (ns NullString) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
@@ -88,8 +88,8 @@ func (n *NullInt64) Scan(value interface{}) error {
return convertAssign(&n.Int64, value)
}
-// SubsetValue implements the driver SubsetValuer interface.
-func (n NullInt64) SubsetValue() (interface{}, error) {
+// Value implements the driver Valuer interface.
+func (n NullInt64) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
@@ -114,8 +114,8 @@ func (n *NullFloat64) Scan(value interface{}) error {
return convertAssign(&n.Float64, value)
}
-// SubsetValue implements the driver SubsetValuer interface.
-func (n NullFloat64) SubsetValue() (interface{}, error) {
+// Value implements the driver Valuer interface.
+func (n NullFloat64) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
@@ -140,8 +140,8 @@ func (n *NullBool) Scan(value interface{}) error {
return convertAssign(&n.Bool, value)
}
-// SubsetValue implements the driver SubsetValuer interface.
-func (n NullBool) SubsetValue() (interface{}, error) {
+// Value implements the driver Valuer interface.
+func (n NullBool) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
@@ -523,8 +523,13 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
}
defer tx.releaseConn()
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
+ }
+
if execer, ok := ci.(driver.Execer); ok {
- resi, err := execer.Exec(query, args)
+ resi, err := execer.Exec(query, sargs)
if err == nil {
return result{resi}, nil
}
@@ -539,11 +544,6 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
}
defer sti.Close()
- sargs, err := subsetTypeArgs(args)
- if err != nil {
- return nil, err
- }
-
resi, err := sti.Exec(sargs)
if err != nil {
return nil, err
@@ -618,19 +618,21 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
+ sargs := make([]driver.Value, len(args))
+
// Convert args to subset types.
if cc, ok := si.(driver.ColumnConverter); ok {
for n, arg := range args {
// First, see if the value itself knows how to convert
// itself to a driver type. For example, a NullString
// struct changing into a string or nil.
- if svi, ok := arg.(driver.SubsetValuer); ok {
- sv, err := svi.SubsetValue()
+ if svi, ok := arg.(driver.Valuer); ok {
+ sv, err := svi.Value()
if err != nil {
- return nil, fmt.Errorf("sql: argument index %d from SubsetValue: %v", n, err)
+ return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err)
}
- if !driver.IsParameterSubsetType(sv) {
- return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from SubsetValue", n, sv)
+ if !driver.IsValue(sv) {
+ return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv)
}
arg = sv
}
@@ -642,25 +644,25 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
// truncated), or that a nil can't go into a NOT NULL
// column before going across the network to get the
// same error.
- args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ sargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
if err != nil {
return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
}
- if !driver.IsParameterSubsetType(args[n]) {
+ if !driver.IsValue(sargs[n]) {
return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
- arg, args[n])
+ arg, sargs[n])
}
}
} else {
for n, arg := range args {
- args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ sargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
if err != nil {
return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
}
}
}
- resi, err := si.Exec(args)
+ resi, err := si.Exec(sargs)
if err != nil {
return nil, err
}
@@ -829,7 +831,7 @@ type Rows struct {
rowsi driver.Rows
closed bool
- lastcols []interface{}
+ lastcols []driver.Value
lasterr error
closeStmt *Stmt // if non-nil, statement to Close on close
}
@@ -846,7 +848,7 @@ func (rs *Rows) Next() bool {
return false
}
if rs.lastcols == nil {
- rs.lastcols = make([]interface{}, len(rs.rowsi.Columns()))
+ rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
}
rs.lasterr = rs.rowsi.Next(rs.lastcols)
if rs.lasterr == io.EOF {
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
index 9543297e189..37a518b6d37 100644
--- a/libgo/go/debug/dwarf/open.go
+++ b/libgo/go/debug/dwarf/open.go
@@ -31,8 +31,9 @@ type Data struct {
}
// New returns a new Data object initialized from the given parameters.
-// Clients should typically use [TODO(rsc): method to be named later] instead of calling
-// New directly.
+// Rather than calling this function directly, clients should typically use
+// the DWARF method of the File type of the appropriate package debug/elf,
+// debug/macho, or debug/pe.
//
// The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of
diff --git a/libgo/go/debug/dwarf/testdata/typedef.c b/libgo/go/debug/dwarf/testdata/typedef.c
index 664d021ced5..f05f01564ff 100644
--- a/libgo/go/debug/dwarf/testdata/typedef.c
+++ b/libgo/go/debug/dwarf/testdata/typedef.c
@@ -28,8 +28,13 @@ typedef struct my_struct {
volatile int vi;
char x : 1;
int y : 4;
+ int z[0];
long long array[40];
+ int zz[0];
} t_my_struct;
+typedef struct my_struct1 {
+ int zz [1];
+} t_my_struct1;
typedef union my_union {
volatile int vi;
char x : 1;
@@ -65,7 +70,8 @@ t_func_void_of_char *a9;
t_func_void_of_void *a10;
t_func_void_of_ptr_char_dots *a11;
t_my_struct *a12;
-t_my_union *a12a;
+t_my_struct1 *a12a;
+t_my_union *a12b;
t_my_enum *a13;
t_my_list *a14;
t_my_tree *a15;
diff --git a/libgo/go/debug/dwarf/testdata/typedef.elf b/libgo/go/debug/dwarf/testdata/typedef.elf
index 44df8da9bc7..b2062d2c4bb 100755
--- a/libgo/go/debug/dwarf/testdata/typedef.elf
+++ b/libgo/go/debug/dwarf/testdata/typedef.elf
Binary files differ
diff --git a/libgo/go/debug/dwarf/testdata/typedef.macho b/libgo/go/debug/dwarf/testdata/typedef.macho
index 41019c1e146..f75afcccbfc 100644
--- a/libgo/go/debug/dwarf/testdata/typedef.macho
+++ b/libgo/go/debug/dwarf/testdata/typedef.macho
Binary files differ
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 9be66658fe9..4502355022d 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -426,6 +426,8 @@ func (d *Data) Type(off Offset) (Type, error) {
t.StructName, _ = e.Val(AttrName).(string)
t.Incomplete = e.Val(AttrDeclaration) != nil
t.Field = make([]*StructField, 0, 8)
+ var lastFieldType Type
+ var lastFieldBitOffset int64
for kid := next(); kid != nil; kid = next() {
if kid.Tag == TagMember {
f := new(StructField)
@@ -444,11 +446,32 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
}
+
+ haveBitOffset := false
f.Name, _ = kid.Val(AttrName).(string)
f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
- f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
+ f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
f.BitSize, _ = kid.Val(AttrBitSize).(int64)
t.Field = append(t.Field, f)
+
+ bito := f.BitOffset
+ if !haveBitOffset {
+ bito = f.ByteOffset * 8
+ }
+ if bito == lastFieldBitOffset && t.Kind != "union" {
+ // Last field was zero width. Fix array length.
+ // (DWARF writes out 0-length arrays as if they were 1-length arrays.)
+ zeroArray(lastFieldType)
+ }
+ lastFieldType = f.Type
+ lastFieldBitOffset = bito
+ }
+ }
+ if t.Kind != "union" {
+ b, ok := e.Val(AttrByteSize).(int64)
+ if ok && b*8 == lastFieldBitOffset {
+ // Final field must be zero width. Fix array length.
+ zeroArray(lastFieldType)
}
}
@@ -579,3 +602,14 @@ Error:
delete(d.typeCache, off)
return nil, err
}
+
+func zeroArray(t Type) {
+ for {
+ at, ok := t.(*ArrayType)
+ if !ok {
+ break
+ }
+ at.Count = 0
+ t = at.Type
+ }
+}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
index b9470a4fcb4..b5b255f6f4a 100644
--- a/libgo/go/debug/dwarf/type_test.go
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -25,13 +25,22 @@ var typedefTests = map[string]string{
"t_func_void_of_char": "func(char) void",
"t_func_void_of_void": "func() void",
"t_func_void_of_ptr_char_dots": "func(*char, ...) void",
- "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+ "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
+ "t_my_struct1": "struct my_struct1 {zz [1]int@0}",
"t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
"t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
"t_my_list": "struct list {val short int@0; next *t_my_list@8}",
"t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
}
+// As Apple converts gcc to a clang-based front end
+// they keep breaking the DWARF output. This map lists the
+// conversion from real answer to Apple answer.
+var machoBug = map[string]string{
+ "func(*char, ...) void": "func(*char) void",
+ "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
+}
+
func elfData(t *testing.T, name string) *Data {
f, err := elf.Open(name)
if err != nil {
@@ -58,13 +67,13 @@ func machoData(t *testing.T, name string) *Data {
return d
}
-func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
func TestTypedefsMachO(t *testing.T) {
- testTypedefs(t, machoData(t, "testdata/typedef.macho"))
+ testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
}
-func testTypedefs(t *testing.T, d *Data) {
+func testTypedefs(t *testing.T, d *Data, kind string) {
r := d.Reader()
seen := make(map[string]bool)
for {
@@ -93,7 +102,7 @@ func testTypedefs(t *testing.T, d *Data) {
t.Errorf("multiple definitions for %s", t1.Name)
}
seen[t1.Name] = true
- if typstr != want {
+ if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
}
}
diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go
index b90181bdc64..b2400bb3ba7 100644
--- a/libgo/go/debug/gosym/pclntab_test.go
+++ b/libgo/go/debug/gosym/pclntab_test.go
@@ -6,15 +6,37 @@ package gosym
import (
"debug/elf"
+ "fmt"
"os"
+ "os/exec"
"runtime"
+ "strings"
"testing"
)
+var pclinetestBinary string
+
func dotest() bool {
// For now, only works on ELF platforms.
- // TODO: convert to work with new go tool
- return false && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ return false
+ }
+ if pclinetestBinary != "" {
+ return true
+ }
+ // This command builds pclinetest from pclinetest.asm;
+ // the resulting binary looks like it was built from pclinetest.s,
+ // but we have renamed it to keep it away from the go tool.
+ pclinetestBinary = os.TempDir() + "/pclinetest"
+ command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -E main -o %s %s.6",
+ pclinetestBinary, pclinetestBinary, pclinetestBinary)
+ cmd := exec.Command("sh", "-c", command)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ panic(err)
+ }
+ return true
}
func getTable(t *testing.T) *Table {
@@ -149,7 +171,7 @@ func TestPCLine(t *testing.T) {
return
}
- f, tab := crack("_test/pclinetest", t)
+ f, tab := crack(pclinetestBinary, t)
text := f.Section(".text")
textdat, err := text.Data()
if err != nil {
@@ -163,10 +185,13 @@ func TestPCLine(t *testing.T) {
file, line, fn := tab.PCToLine(pc)
off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
wantLine += int(textdat[off])
+ t.Logf("off is %d", off)
if fn == nil {
t.Errorf("failed to get line of PC %#x", pc)
- } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
- t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+ } else if !strings.HasSuffix(file, "pclinetest.asm") {
+ t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.asm", sym.Name, pc, file, fn.Name)
+ } else if line != wantLine || fn != sym {
+ t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
}
}
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index 750d623cde2..a0bb985300f 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -464,7 +464,7 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
// decodeSingle decodes a top-level value that is not a struct and stores it through p.
// Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number).
-func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) (err error) {
+func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) {
state := dec.newDecoderState(&dec.buf)
state.fieldnum = singletonField
delta := int(state.decodeUint())
@@ -473,7 +473,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint
}
instr := &engine.instr[singletonField]
if instr.indir != ut.indir {
- return errors.New("gob: internal error: inconsistent indirection")
+ errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
}
ptr := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 1 {
@@ -481,10 +481,9 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint
}
instr.op(instr, state, ptr)
dec.freeDecoderState(state)
- return nil
}
-// decodeSingle decodes a top-level struct and stores it through p.
+// decodeStruct decodes a top-level struct and stores it through p.
// Indir is for the value, not the type. At the time of the call it may
// differ from ut.indir, which was computed when the engine was built.
// This state cannot arise for decodeSingle, which is called directly
@@ -839,11 +838,10 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
}
case reflect.Map:
- name = "element of " + name
keyId := dec.wireType[wireId].MapT.Key
elemId := dec.wireType[wireId].MapT.Elem
- keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name, inProgress)
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
up := unsafe.Pointer(p)
@@ -1151,7 +1149,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
// getDecEnginePtr returns the engine for the specified type.
func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) {
- rt := ut.base
+ rt := ut.user
decoderMap, ok := dec.decoderCache[rt]
if !ok {
decoderMap = make(map[typeId]**decEngine)
diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go
index 9a62cf9c2ad..3bfae30f39a 100644
--- a/libgo/go/encoding/gob/encoder_test.go
+++ b/libgo/go/encoding/gob/encoder_test.go
@@ -685,3 +685,54 @@ func TestSliceIncompatibility(t *testing.T) {
t.Error("expected compatibility error")
}
}
+
+// Mutually recursive slices of structs caused problems.
+type Bug3 struct {
+ Num int
+ Children []*Bug3
+}
+
+func TestGobPtrSlices(t *testing.T) {
+ in := []*Bug3{
+ &Bug3{1, nil},
+ &Bug3{2, nil},
+ }
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(&in)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+
+ var out []*Bug3
+ err = NewDecoder(b).Decode(&out)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(in, out) {
+ t.Fatal("got %v; wanted %v", out, in)
+ }
+}
+
+// getDecEnginePtr cached engine for ut.base instead of ut.user so we passed
+// a *map and then tried to reuse its engine to decode the inner map.
+func TestPtrToMapOfMap(t *testing.T) {
+ Register(make(map[string]interface{}))
+ subdata := make(map[string]interface{})
+ subdata["bar"] = "baz"
+ data := make(map[string]interface{})
+ data["foo"] = subdata
+
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(data)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ var newData map[string]interface{}
+ err = NewDecoder(b).Decode(&newData)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(data, newData) {
+ t.Fatalf("expected %v got %v", data, newData)
+ }
+}
diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go
index 39006efdb2d..0dd7a0a770e 100644
--- a/libgo/go/encoding/gob/type.go
+++ b/libgo/go/encoding/gob/type.go
@@ -152,6 +152,10 @@ var idToType = make(map[typeId]gobType)
var builtinIdToType map[typeId]gobType // set in init() after builtins are established
func setTypeId(typ gobType) {
+ // When building recursive types, someone may get there before us.
+ if typ.id() != 0 {
+ return
+ }
nextId++
typ.setId(nextId)
idToType[nextId] = typ
@@ -346,6 +350,11 @@ func newSliceType(name string) *sliceType {
func (s *sliceType) init(elem gobType) {
// Set our type id before evaluating the element's, in case it's our own.
setTypeId(s)
+ // See the comments about ids in newTypeObject. Only slices and
+ // structs have mutual recursion.
+ if elem.id() == 0 {
+ setTypeId(elem)
+ }
s.Elem = elem.id()
}
@@ -503,6 +512,13 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
if err != nil {
return nil, err
}
+ // Some mutually recursive types can cause us to be here while
+ // still defining the element. Fix the element type id here.
+ // We could do this more neatly by setting the id at the start of
+ // building every type, but that would break binary compatibility.
+ if gt.id() == 0 {
+ setTypeId(gt)
+ }
st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
}
return st, nil
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 87076b53dc0..110c6fd6238 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -496,6 +496,12 @@ func (d *decodeState) object(v reflect.Value) {
// Pretend this field doesn't exist.
continue
}
+ if sf.Anonymous {
+ // Pretend this field doesn't exist,
+ // so that we can do a good job with
+ // these in a later version.
+ continue
+ }
// First, tag match
tagName, _ := parseTag(tag)
if tagName == key {
@@ -963,3 +969,11 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
}
return b[0:w], true
}
+
+// The following is issue 3069.
+
+// BUG(rsc): This package ignores anonymous (embedded) struct fields
+// during encoding and decoding. A future version may assign meaning
+// to them. To force an anonymous field to be ignored in all future
+// versions of this package, use an explicit `json:"-"` tag in the struct
+// definition.
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index 775becfa7c9..0eec586a9bb 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -619,3 +619,32 @@ func TestRefUnmarshal(t *testing.T) {
t.Errorf("got %+v, want %+v", got, want)
}
}
+
+// Test that anonymous fields are ignored.
+// We may assign meaning to them later.
+func TestAnonymous(t *testing.T) {
+ type S struct {
+ T
+ N int
+ }
+
+ data, err := Marshal(new(S))
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := `{"N":0}`
+ if string(data) != want {
+ t.Fatalf("Marshal = %#q, want %#q", string(data), want)
+ }
+
+ var s S
+ if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if s.N != 2 {
+ t.Fatal("Unmarshal: did not set N")
+ }
+ if s.T.Y != 0 {
+ t.Fatal("Unmarshal: did set T.Y")
+ }
+}
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index 83e73c09cb4..8a794b79bd5 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -538,6 +538,11 @@ func encodeFields(t reflect.Type) []encodeField {
if f.PkgPath != "" {
continue
}
+ if f.Anonymous {
+ // We want to do a better job with these later,
+ // so for now pretend they don't exist.
+ continue
+ }
var ef encodeField
ef.i = i
ef.tag = f.Name
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go
index a96c523d553..6c3170bdda3 100644
--- a/libgo/go/encoding/xml/marshal.go
+++ b/libgo/go/encoding/xml/marshal.go
@@ -57,35 +57,14 @@ const (
// if the field value is empty. The empty values are false, 0, any
// nil pointer or interface value, and any array, slice, map, or
// string of length zero.
+// - a non-pointer anonymous struct field is handled as if the
+// fields of its value were part of the outer struct.
//
// If a field uses a tag "a>b>c", then the element c will be nested inside
// parent elements a and b. Fields that appear next to each other that name
-// the same parent will be enclosed in one XML element. For example:
+// the same parent will be enclosed in one XML element.
//
-// type Result struct {
-// XMLName xml.Name `xml:"result"`
-// Id int `xml:"id,attr"`
-// FirstName string `xml:"person>name>first"`
-// LastName string `xml:"person>name>last"`
-// Age int `xml:"person>age"`
-// Height float `xml:"person>height,omitempty"`
-// Married bool `xml:"person>married"`
-// }
-//
-// xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42})
-//
-// would be marshalled as:
-//
-// <result>
-// <person id="13">
-// <name>
-// <first>John</first>
-// <last>Doe</last>
-// </name>
-// <age>42</age>
-// <married>false</married>
-// </person>
-// </result>
+// See MarshalIndent for an example.
//
// Marshal will return an error if asked to marshal a channel, function, or map.
func Marshal(v interface{}) ([]byte, error) {
@@ -96,6 +75,22 @@ func Marshal(v interface{}) ([]byte, error) {
return b.Bytes(), nil
}
+// MarshalIndent works like Marshal, but each XML element begins on a new
+// indented line that starts with prefix and is followed by one or more
+// copies of indent according to the nesting depth.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
+ var b bytes.Buffer
+ enc := NewEncoder(&b)
+ enc.prefix = prefix
+ enc.indent = indent
+ err := enc.marshalValue(reflect.ValueOf(v), nil)
+ enc.Flush()
+ if err != nil {
+ return nil, err
+ }
+ return b.Bytes(), nil
+}
+
// An Encoder writes XML data to an output stream.
type Encoder struct {
printer
@@ -103,7 +98,7 @@ type Encoder struct {
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{printer{bufio.NewWriter(w)}}
+ return &Encoder{printer{Writer: bufio.NewWriter(w)}}
}
// Encode writes the XML encoding of v to the stream.
@@ -118,8 +113,14 @@ func (enc *Encoder) Encode(v interface{}) error {
type printer struct {
*bufio.Writer
+ indent string
+ prefix string
+ depth int
+ indentedIn bool
}
+// marshalValue writes one or more XML elements representing val.
+// If val was obtained from a struct field, finfo must have its details.
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
if !val.IsValid() {
return nil
@@ -177,6 +178,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
}
}
+ p.writeIndent(1)
p.WriteByte('<')
p.WriteString(name)
@@ -216,6 +218,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
return err
}
+ p.writeIndent(-1)
p.WriteByte('<')
p.WriteByte('/')
p.WriteString(name)
@@ -294,6 +297,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
if vf.Len() == 0 {
continue
}
+ p.writeIndent(0)
p.WriteString("<!--")
dashDash := false
dashLast := false
@@ -352,6 +356,33 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
return nil
}
+func (p *printer) writeIndent(depthDelta int) {
+ if len(p.prefix) == 0 && len(p.indent) == 0 {
+ return
+ }
+ if depthDelta < 0 {
+ p.depth--
+ if p.indentedIn {
+ p.indentedIn = false
+ return
+ }
+ p.indentedIn = false
+ }
+ p.WriteByte('\n')
+ if len(p.prefix) > 0 {
+ p.WriteString(p.prefix)
+ }
+ if len(p.indent) > 0 {
+ for i := 0; i < p.depth; i++ {
+ p.WriteString(p.indent)
+ }
+ }
+ if depthDelta > 0 {
+ p.depth++
+ p.indentedIn = true
+ }
+}
+
type parentStack struct {
*printer
stack []string
@@ -367,20 +398,20 @@ func (s *parentStack) trim(parents []string) {
break
}
}
-
for i := len(s.stack) - 1; i >= split; i-- {
+ s.writeIndent(-1)
s.WriteString("</")
s.WriteString(s.stack[i])
s.WriteByte('>')
}
-
s.stack = parents[:split]
}
// push adds parent elements to the stack and writes open tags.
func (s *parentStack) push(parents []string) {
for i := 0; i < len(parents); i++ {
- s.WriteString("<")
+ s.writeIndent(1)
+ s.WriteByte('<')
s.WriteString(parents[i])
s.WriteByte('>')
}
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index b5a3426a328..c2168242091 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -25,58 +25,6 @@ import (
// slice, or string. Well-formed data that does not fit into v is
// discarded.
//
-// For example, given these definitions:
-//
-// type Email struct {
-// Where string `xml:",attr"`
-// Addr string
-// }
-//
-// type Result struct {
-// XMLName xml.Name `xml:"result"`
-// Name string
-// Phone string
-// Email []Email
-// Groups []string `xml:"group>value"`
-// }
-//
-// result := Result{Name: "name", Phone: "phone", Email: nil}
-//
-// unmarshalling the XML input
-//
-// <result>
-// <email where="home">
-// <addr>gre@example.com</addr>
-// </email>
-// <email where='work'>
-// <addr>gre@work.com</addr>
-// </email>
-// <name>Grace R. Emlin</name>
-// <group>
-// <value>Friends</value>
-// <value>Squash</value>
-// </group>
-// <address>123 Main Street</address>
-// </result>
-//
-// via Unmarshal(data, &result) is equivalent to assigning
-//
-// r = Result{
-// xml.Name{Local: "result"},
-// "Grace R. Emlin", // name
-// "phone", // no phone given
-// []Email{
-// Email{"home", "gre@example.com"},
-// Email{"work", "gre@work.com"},
-// },
-// []string{"Friends", "Squash"},
-// }
-//
-// Note that the field r.Phone has not been modified and
-// that the XML <address> element was discarded. Also, the field
-// Groups was assigned considering the element path provided in the
-// field tag.
-//
// Because Unmarshal uses the reflect package, it can only assign
// to exported (upper case) fields. Unmarshal uses a case-sensitive
// comparison to match XML element names to tag values and struct
@@ -133,6 +81,9 @@ import (
// of the above rules and the struct has a field with tag ",any",
// unmarshal maps the sub-element to that struct field.
//
+// * A non-pointer anonymous struct field is handled as if the
+// fields of its value were part of the outer struct.
+//
// * A struct field with tag "-" is never unmarshalled into.
//
// Unmarshal maps an XML element to a string or []byte by saving the
diff --git a/libgo/go/errors/errors_test.go b/libgo/go/errors/errors_test.go
index c537eeb6251..63c05d7185b 100644
--- a/libgo/go/errors/errors_test.go
+++ b/libgo/go/errors/errors_test.go
@@ -5,29 +5,49 @@
package errors_test
import (
- . "errors"
+ "errors"
+ "fmt"
"testing"
)
func TestNewEqual(t *testing.T) {
// Different allocations should not be equal.
- if New("abc") == New("abc") {
+ if errors.New("abc") == errors.New("abc") {
t.Errorf(`New("abc") == New("abc")`)
}
- if New("abc") == New("xyz") {
+ if errors.New("abc") == errors.New("xyz") {
t.Errorf(`New("abc") == New("xyz")`)
}
// Same allocation should be equal to itself (not crash).
- err := New("jkl")
+ err := errors.New("jkl")
if err != err {
t.Errorf(`err != err`)
}
}
func TestErrorMethod(t *testing.T) {
- err := New("abc")
+ err := errors.New("abc")
if err.Error() != "abc" {
t.Errorf(`New("abc").Error() = %q, want %q`, err.Error(), "abc")
}
}
+
+func ExampleNew() {
+ err := errors.New("emit macho dwarf: elf header corrupted")
+ if err != nil {
+ fmt.Print(err)
+ }
+ // Output: emit macho dwarf: elf header corrupted
+}
+
+// The fmt package's Errorf function lets us use the package's formatting
+// features to create descriptive error messages.
+func ExampleNew_errorf() {
+ const name, id = "bimmler", 17
+ err := fmt.Errorf("user %q (id %d) not found", name, id)
+ if err != nil {
+ fmt.Print(err)
+ }
+ // Output: user "bimmler" (id 17) not found
+}
diff --git a/libgo/go/exp/inotify/inotify_linux_test.go b/libgo/go/exp/inotify/inotify_linux_test.go
index c2160fc6537..d41d66bfacd 100644
--- a/libgo/go/exp/inotify/inotify_linux_test.go
+++ b/libgo/go/exp/inotify/inotify_linux_test.go
@@ -7,6 +7,7 @@
package inotify
import (
+ "io/ioutil"
"os"
"testing"
"time"
@@ -16,16 +17,19 @@ func TestInotifyEvents(t *testing.T) {
// Create an inotify watcher instance and initialize it
watcher, err := NewWatcher()
if err != nil {
- t.Fatalf("NewWatcher() failed: %s", err)
+ t.Fatalf("NewWatcher failed: %s", err)
}
- t.Logf("NEEDS TO BE CONVERTED TO NEW GO TOOL") // TODO
- return
+ dir, err := ioutil.TempDir("", "inotify")
+ if err != nil {
+ t.Fatalf("TempDir failed: %s", err)
+ }
+ defer os.RemoveAll(dir)
// Add a watch for "_test"
- err = watcher.Watch("_test")
+ err = watcher.Watch(dir)
if err != nil {
- t.Fatalf("Watcher.Watch() failed: %s", err)
+ t.Fatalf("Watch failed: %s", err)
}
// Receive errors on the error channel on a separate goroutine
@@ -35,7 +39,7 @@ func TestInotifyEvents(t *testing.T) {
}
}()
- const testFile string = "_test/TestInotifyEvents.testfile"
+ testFile := dir + "/TestInotifyEvents.testfile"
// Receive events on the event channel on a separate goroutine
eventstream := watcher.Event
@@ -58,7 +62,7 @@ func TestInotifyEvents(t *testing.T) {
// This should add at least one event to the inotify event queue
_, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
- t.Fatalf("creating test file failed: %s", err)
+ t.Fatalf("creating test file: %s", err)
}
// We expect this event to be received almost immediately, but let's wait 1 s to be sure
@@ -95,7 +99,7 @@ func TestInotifyClose(t *testing.T) {
t.Fatal("double Close() test failed: second Close() call didn't return")
}
- err := watcher.Watch("_test")
+ err := watcher.Watch(os.TempDir())
if err == nil {
t.Fatal("expected error on Watch() after Close(), got nil")
}
diff --git a/libgo/go/exp/norm/composition.go b/libgo/go/exp/norm/composition.go
index ccff4670602..2cbe1ac730e 100644
--- a/libgo/go/exp/norm/composition.go
+++ b/libgo/go/exp/norm/composition.go
@@ -66,6 +66,18 @@ func (rb *reorderBuffer) flush(out []byte) []byte {
return out
}
+// flushCopy copies the normalized segment to buf and resets rb.
+// It returns the number of bytes written to buf.
+func (rb *reorderBuffer) flushCopy(buf []byte) int {
+ p := 0
+ for i := 0; i < rb.nrune; i++ {
+ runep := rb.rune[i]
+ p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size])
+ }
+ rb.reset()
+ return p
+}
+
// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
// It returns false if the buffer is not large enough to hold the rune.
// It is used internally by insert and insertString only.
@@ -96,32 +108,41 @@ func (rb *reorderBuffer) insertOrdered(info runeInfo) bool {
// insert inserts the given rune in the buffer ordered by CCC.
// It returns true if the buffer was large enough to hold the decomposed rune.
func (rb *reorderBuffer) insert(src input, i int, info runeInfo) bool {
- if info.size == 3 {
- if rune := src.hangul(i); rune != 0 {
- return rb.decomposeHangul(rune)
- }
+ if rune := src.hangul(i); rune != 0 {
+ return rb.decomposeHangul(rune)
}
if info.hasDecomposition() {
- dcomp := info.decomposition()
- rb.tmpBytes = inputBytes(dcomp)
- for i := 0; i < len(dcomp); {
- info = rb.f.info(&rb.tmpBytes, i)
- pos := rb.nbyte
- if !rb.insertOrdered(info) {
- return false
- }
- end := i + int(info.size)
- copy(rb.byte[pos:], dcomp[i:end])
- i = end
- }
- } else {
- // insertOrder changes nbyte
+ return rb.insertDecomposed(info.decomposition())
+ }
+ return rb.insertSingle(src, i, info)
+}
+
+// insertDecomposed inserts an entry in to the reorderBuffer for each rune
+// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes.
+func (rb *reorderBuffer) insertDecomposed(dcomp []byte) bool {
+ saveNrune, saveNbyte := rb.nrune, rb.nbyte
+ rb.tmpBytes = inputBytes(dcomp)
+ for i := 0; i < len(dcomp); {
+ info := rb.f.info(&rb.tmpBytes, i)
pos := rb.nbyte
if !rb.insertOrdered(info) {
+ rb.nrune, rb.nbyte = saveNrune, saveNbyte
return false
}
- src.copySlice(rb.byte[pos:], i, i+int(info.size))
+ i += copy(rb.byte[pos:], dcomp[i:i+int(info.size)])
+ }
+ return true
+}
+
+// insertSingle inserts an entry in the reorderBuffer for the rune at
+// position i. info is the runeInfo for the rune at position i.
+func (rb *reorderBuffer) insertSingle(src input, i int, info runeInfo) bool {
+ // insertOrder changes nbyte
+ pos := rb.nbyte
+ if !rb.insertOrdered(info) {
+ return false
}
+ src.copySlice(rb.byte[pos:], i, i+int(info.size))
return true
}
@@ -182,8 +203,12 @@ const (
jamoLVTCount = 19 * 21 * 28
)
-// Caller must verify that len(b) >= 3.
+const hangulUTF8Size = 3
+
func isHangul(b []byte) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
b0 := b[0]
if b0 < hangulBase0 {
return false
@@ -202,8 +227,10 @@ func isHangul(b []byte) bool {
return b1 == hangulEnd1 && b[2] < hangulEnd2
}
-// Caller must verify that len(b) >= 3.
func isHangulString(b string) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
b0 := b[0]
if b0 < hangulBase0 {
return false
@@ -234,6 +261,22 @@ func isHangulWithoutJamoT(b []byte) bool {
return c < jamoLVTCount && c%jamoTCount == 0
}
+// decomposeHangul writes the decomposed Hangul to buf and returns the number
+// of bytes written. len(buf) should be at least 9.
+func decomposeHangul(buf []byte, r rune) int {
+ const JamoUTF8Len = 3
+ r -= hangulBase
+ x := r % jamoTCount
+ r /= jamoTCount
+ utf8.EncodeRune(buf, jamoLBase+r/jamoVCount)
+ utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount)
+ if x != 0 {
+ utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x)
+ return 3 * JamoUTF8Len
+ }
+ return 2 * JamoUTF8Len
+}
+
// decomposeHangul algorithmically decomposes a Hangul rune into
// its Jamo components.
// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
diff --git a/libgo/go/exp/norm/composition_test.go b/libgo/go/exp/norm/composition_test.go
index e32380d7afa..9de9eacfd65 100644
--- a/libgo/go/exp/norm/composition_test.go
+++ b/libgo/go/exp/norm/composition_test.go
@@ -47,14 +47,14 @@ func runTests(t *testing.T, name string, fm Form, f insertFunc, tests []TestCase
}
}
-func TestFlush(t *testing.T) {
+type flushFunc func(rb *reorderBuffer) []byte
+
+func testFlush(t *testing.T, name string, fn flushFunc) {
rb := reorderBuffer{}
rb.init(NFC, nil)
- out := make([]byte, 0)
-
- out = rb.flush(out)
+ out := fn(&rb)
if len(out) != 0 {
- t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", len(out))
+ t.Errorf("%s: wrote bytes on flush of empty buffer. (len(out) = %d)", name, len(out))
}
for _, r := range []rune("world!") {
@@ -65,16 +65,32 @@ func TestFlush(t *testing.T) {
out = rb.flush(out)
want := "Hello world!"
if string(out) != want {
- t.Errorf(`output after flush was "%s"; want "%s"`, string(out), want)
+ t.Errorf(`%s: output after flush was "%s"; want "%s"`, name, string(out), want)
}
if rb.nrune != 0 {
- t.Errorf("flush: non-null size of info buffer (rb.nrune == %d)", rb.nrune)
+ t.Errorf("%s: non-null size of info buffer (rb.nrune == %d)", name, rb.nrune)
}
if rb.nbyte != 0 {
- t.Errorf("flush: non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte)
+ t.Errorf("%s: non-null size of byte buffer (rb.nbyte == %d)", name, rb.nbyte)
}
}
+func flushF(rb *reorderBuffer) []byte {
+ out := make([]byte, 0)
+ return rb.flush(out)
+}
+
+func flushCopyF(rb *reorderBuffer) []byte {
+ out := make([]byte, MaxSegmentSize)
+ n := rb.flushCopy(out)
+ return out[:n]
+}
+
+func TestFlush(t *testing.T) {
+ testFlush(t, "flush", flushF)
+ testFlush(t, "flushCopy", flushCopyF)
+}
+
var insertTests = []TestCase{
{[]rune{'a'}, []rune{'a'}},
{[]rune{0x300}, []rune{0x300}},
diff --git a/libgo/go/exp/norm/input.go b/libgo/go/exp/norm/input.go
index 5c0968ba58c..9c564d67718 100644
--- a/libgo/go/exp/norm/input.go
+++ b/libgo/go/exp/norm/input.go
@@ -7,7 +7,7 @@ package norm
import "unicode/utf8"
type input interface {
- skipASCII(p int) int
+ skipASCII(p, max int) int
skipNonStarter(p int) int
appendSlice(buf []byte, s, e int) []byte
copySlice(buf []byte, s, e int)
@@ -18,8 +18,8 @@ type input interface {
type inputString string
-func (s inputString) skipASCII(p int) int {
- for ; p < len(s) && s[p] < utf8.RuneSelf; p++ {
+func (s inputString) skipASCII(p, max int) int {
+ for ; p < max && s[p] < utf8.RuneSelf; p++ {
}
return p
}
@@ -59,8 +59,8 @@ func (s inputString) hangul(p int) rune {
type inputBytes []byte
-func (s inputBytes) skipASCII(p int) int {
- for ; p < len(s) && s[p] < utf8.RuneSelf; p++ {
+func (s inputBytes) skipASCII(p, max int) int {
+ for ; p < max && s[p] < utf8.RuneSelf; p++ {
}
return p
}
diff --git a/libgo/go/exp/norm/iter.go b/libgo/go/exp/norm/iter.go
new file mode 100644
index 00000000000..761ba90cdd4
--- /dev/null
+++ b/libgo/go/exp/norm/iter.go
@@ -0,0 +1,286 @@
+// Copyright 2011 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 norm
+
+const MaxSegmentSize = maxByteBufferSize
+
+// An Iter iterates over a string or byte slice, while normalizing it
+// to a given Form.
+type Iter struct {
+ rb reorderBuffer
+ info runeInfo // first character saved from previous iteration
+ next iterFunc // implementation of next depends on form
+
+ p int // current position in input source
+ outStart int // start of current segment in output buffer
+ inStart int // start of current segment in input source
+ maxp int // position in output buffer after which not to start a new segment
+ maxseg int // for tracking an excess of combining characters
+
+ tccc uint8
+ done bool
+}
+
+type iterFunc func(*Iter, []byte) int
+
+// SetInput initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) SetInput(f Form, src []byte) {
+ i.rb.init(f, src)
+ if i.rb.f.composing {
+ i.next = nextComposed
+ } else {
+ i.next = nextDecomposed
+ }
+ i.p = 0
+ if i.done = len(src) == 0; !i.done {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+}
+
+// SetInputString initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) SetInputString(f Form, src string) {
+ i.rb.initString(f, src)
+ if i.rb.f.composing {
+ i.next = nextComposed
+ } else {
+ i.next = nextDecomposed
+ }
+ i.p = 0
+ if i.done = len(src) == 0; !i.done {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+}
+
+// Pos returns the byte position at which the next call to Next will commence processing.
+func (i *Iter) Pos() int {
+ return i.p
+}
+
+// Done returns true if there is no more input to process.
+func (i *Iter) Done() bool {
+ return i.done
+}
+
+// Next writes f(i.input[i.Pos():n]...) to buffer buf, where n is the
+// largest boundary of i.input such that the result fits in buf.
+// It returns the number of bytes written to buf.
+// len(buf) should be at least MaxSegmentSize.
+// Done must be false before calling Next.
+func (i *Iter) Next(buf []byte) int {
+ return i.next(i, buf)
+}
+
+func (i *Iter) initNext(outn, inStart int) {
+ i.outStart = 0
+ i.inStart = inStart
+ i.maxp = outn - MaxSegmentSize
+ i.maxseg = MaxSegmentSize
+}
+
+// setStart resets the start of the new segment to the given position.
+// It returns true if there is not enough room for the new segment.
+func (i *Iter) setStart(outp, inp int) bool {
+ if outp > i.maxp {
+ return true
+ }
+ i.outStart = outp
+ i.inStart = inp
+ i.maxseg = outp + MaxSegmentSize
+ return false
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// nextDecomposed is the implementation of Next for forms NFD and NFKD.
+func nextDecomposed(i *Iter, out []byte) int {
+ var outp int
+ i.initNext(len(out), i.p)
+doFast:
+ inCopyStart, outCopyStart := i.p, outp // invariant xCopyStart <= i.xStart
+ for {
+ if sz := int(i.info.size); sz <= 1 {
+ // ASCII or illegal byte. Either way, advance by 1.
+ i.p++
+ outp++
+ max := min(i.rb.nsrc, len(out)-outp+i.p)
+ if np := i.rb.src.skipASCII(i.p, max); np > i.p {
+ outp += np - i.p
+ i.p = np
+ if i.p >= i.rb.nsrc {
+ break
+ }
+ // ASCII may combine with consecutive runes.
+ if i.setStart(outp-1, i.p-1) {
+ i.p--
+ outp--
+ i.info.size = 1
+ break
+ }
+ }
+ } else if d := i.info.decomposition(); d != nil {
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.p)
+ p := outp + len(d)
+ if p > i.maxseg && i.setStart(outp, i.p) {
+ return outp
+ }
+ copy(out[outp:], d)
+ outp = p
+ i.p += sz
+ inCopyStart, outCopyStart = i.p, outp
+ } else if r := i.rb.src.hangul(i.p); r != 0 {
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.p)
+ for {
+ outp += decomposeHangul(out[outp:], r)
+ i.p += hangulUTF8Size
+ if r = i.rb.src.hangul(i.p); r == 0 {
+ break
+ }
+ if i.setStart(outp, i.p) {
+ return outp
+ }
+ }
+ inCopyStart, outCopyStart = i.p, outp
+ } else {
+ p := outp + sz
+ if p > i.maxseg && i.setStart(outp, i.p) {
+ break
+ }
+ outp = p
+ i.p += sz
+ }
+ if i.p >= i.rb.nsrc {
+ break
+ }
+ prevCC := i.info.tccc
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if cc := i.info.ccc; cc == 0 {
+ if i.setStart(outp, i.p) {
+ break
+ }
+ } else if cc < prevCC {
+ goto doNorm
+ }
+ }
+ if inCopyStart != i.p {
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.p)
+ }
+ i.done = i.p >= i.rb.nsrc
+ return outp
+doNorm:
+ // Insert what we have decomposed so far in the reorderBuffer.
+ // As we will only reorder, there will always be enough room.
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.p)
+ if !i.rb.insertDecomposed(out[i.outStart:outp]) {
+ // Start over to prevent decompositions from crossing segment boundaries.
+ // This is a rare occurance.
+ i.p = i.inStart
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+ outp = i.outStart
+ for {
+ if !i.rb.insert(i.rb.src, i.p, i.info) {
+ break
+ }
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ outp += i.rb.flushCopy(out[outp:])
+ i.done = true
+ return outp
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.ccc == 0 {
+ break
+ }
+ }
+ // new segment or too many combining characters: exit normalization
+ if outp += i.rb.flushCopy(out[outp:]); i.setStart(outp, i.p) {
+ return outp
+ }
+ goto doFast
+}
+
+// nextComposed is the implementation of Next for forms NFC and NFKC.
+func nextComposed(i *Iter, out []byte) int {
+ var outp int
+ i.initNext(len(out), i.p)
+doFast:
+ inCopyStart, outCopyStart := i.p, outp // invariant xCopyStart <= i.xStart
+ var prevCC uint8
+ for {
+ if !i.info.isYesC() {
+ goto doNorm
+ }
+ if cc := i.info.ccc; cc == 0 {
+ if i.setStart(outp, i.p) {
+ break
+ }
+ } else if cc < prevCC {
+ goto doNorm
+ }
+ prevCC = i.info.tccc
+ sz := int(i.info.size)
+ if sz == 0 {
+ sz = 1 // illegal rune: copy byte-by-byte
+ }
+ p := outp + sz
+ if p > i.maxseg && i.setStart(outp, i.p) {
+ break
+ }
+ outp = p
+ i.p += sz
+ max := min(i.rb.nsrc, len(out)-outp+i.p)
+ if np := i.rb.src.skipASCII(i.p, max); np > i.p {
+ outp += np - i.p
+ i.p = np
+ if i.p >= i.rb.nsrc {
+ break
+ }
+ // ASCII may combine with consecutive runes.
+ if i.setStart(outp-1, i.p-1) {
+ i.p--
+ outp--
+ i.info = runeInfo{size: 1}
+ break
+ }
+ }
+ if i.p >= i.rb.nsrc {
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+ if inCopyStart != i.p {
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.p)
+ }
+ i.done = i.p >= i.rb.nsrc
+ return outp
+doNorm:
+ i.rb.src.copySlice(out[outCopyStart:], inCopyStart, i.inStart)
+ outp, i.p = i.outStart, i.inStart
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ for {
+ if !i.rb.insert(i.rb.src, i.p, i.info) {
+ break
+ }
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ i.rb.compose()
+ outp += i.rb.flushCopy(out[outp:])
+ i.done = true
+ return outp
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.boundaryBefore() {
+ break
+ }
+ }
+ i.rb.compose()
+ if outp += i.rb.flushCopy(out[outp:]); i.setStart(outp, i.p) {
+ return outp
+ }
+ goto doFast
+}
diff --git a/libgo/go/exp/norm/iter_test.go b/libgo/go/exp/norm/iter_test.go
new file mode 100644
index 00000000000..f6e8d817251
--- /dev/null
+++ b/libgo/go/exp/norm/iter_test.go
@@ -0,0 +1,186 @@
+// Copyright 2011 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 norm
+
+import (
+ "strings"
+ "testing"
+)
+
+var iterBufSizes = []int{
+ MaxSegmentSize,
+ 1.5 * MaxSegmentSize,
+ 2 * MaxSegmentSize,
+ 3 * MaxSegmentSize,
+ 100 * MaxSegmentSize,
+}
+
+func doIterNorm(f Form, buf []byte, s string) []byte {
+ acc := []byte{}
+ i := Iter{}
+ i.SetInputString(f, s)
+ for !i.Done() {
+ n := i.Next(buf)
+ acc = append(acc, buf[:n]...)
+ }
+ return acc
+}
+
+func runIterTests(t *testing.T, name string, f Form, tests []AppendTest, norm bool) {
+ for i, test := range tests {
+ in := test.left + test.right
+ gold := test.out
+ if norm {
+ gold = string(f.AppendString(nil, test.out))
+ }
+ for _, sz := range iterBufSizes {
+ buf := make([]byte, sz)
+ out := string(doIterNorm(f, buf, in))
+ if len(out) != len(gold) {
+ const msg = "%s:%d:%d: length is %d; want %d"
+ t.Errorf(msg, name, i, sz, len(out), len(gold))
+ }
+ if out != gold {
+ // Find first rune that differs and show context.
+ ir := []rune(out)
+ ig := []rune(gold)
+ for j := 0; j < len(ir) && j < len(ig); j++ {
+ if ir[j] == ig[j] {
+ continue
+ }
+ if j -= 3; j < 0 {
+ j = 0
+ }
+ for e := j + 7; j < e && j < len(ir) && j < len(ig); j++ {
+ const msg = "%s:%d:%d: runeAt(%d) = %U; want %U"
+ t.Errorf(msg, name, i, sz, j, ir[j], ig[j])
+ }
+ break
+ }
+ }
+ }
+ }
+}
+
+func rep(r rune, n int) string {
+ return strings.Repeat(string(r), n)
+}
+
+var iterTests = []AppendTest{
+ {"", ascii, ascii},
+ {"", txt_all, txt_all},
+ {"", "a" + rep(0x0300, MaxSegmentSize/2), "a" + rep(0x0300, MaxSegmentSize/2)},
+}
+
+var iterTestsD = []AppendTest{
+ { // segment overflow on unchanged character
+ "",
+ "a" + rep(0x0300, MaxSegmentSize/2) + "\u0316",
+ "a" + rep(0x0300, MaxSegmentSize/2-1) + "\u0316\u0300",
+ },
+ { // segment overflow on unchanged character + start value
+ "",
+ "a" + rep(0x0300, MaxSegmentSize/2+maxCombiningChars+4) + "\u0316",
+ "a" + rep(0x0300, MaxSegmentSize/2+maxCombiningChars) + "\u0316" + rep(0x300, 4),
+ },
+ { // segment overflow on decomposition
+ "",
+ "a" + rep(0x0300, MaxSegmentSize/2-1) + "\u0340",
+ "a" + rep(0x0300, MaxSegmentSize/2),
+ },
+ { // segment overflow on decomposition + start value
+ "",
+ "a" + rep(0x0300, MaxSegmentSize/2-1) + "\u0340" + rep(0x300, maxCombiningChars+4) + "\u0320",
+ "a" + rep(0x0300, MaxSegmentSize/2-1) + rep(0x300, maxCombiningChars+1) + "\u0320" + rep(0x300, 4),
+ },
+ { // start value after ASCII overflow
+ "",
+ rep('a', MaxSegmentSize) + rep(0x300, maxCombiningChars+2) + "\u0320",
+ rep('a', MaxSegmentSize) + rep(0x300, maxCombiningChars) + "\u0320\u0300\u0300",
+ },
+ { // start value after Hangul overflow
+ "",
+ rep(0xAC00, MaxSegmentSize/6) + rep(0x300, maxCombiningChars+2) + "\u0320",
+ strings.Repeat("\u1100\u1161", MaxSegmentSize/6) + rep(0x300, maxCombiningChars-1) + "\u0320" + rep(0x300, 3),
+ },
+ { // start value after cc=0
+ "",
+ "您您" + rep(0x300, maxCombiningChars+4) + "\u0320",
+ "您您" + rep(0x300, maxCombiningChars) + "\u0320" + rep(0x300, 4),
+ },
+ { // start value after normalization
+ "",
+ "\u0300\u0320a" + rep(0x300, maxCombiningChars+4) + "\u0320",
+ "\u0320\u0300a" + rep(0x300, maxCombiningChars) + "\u0320" + rep(0x300, 4),
+ },
+}
+
+var iterTestsC = []AppendTest{
+ { // ordering of non-composing combining characters
+ "",
+ "\u0305\u0316",
+ "\u0316\u0305",
+ },
+ { // segment overflow
+ "",
+ "a" + rep(0x0305, MaxSegmentSize/2+4) + "\u0316",
+ "a" + rep(0x0305, MaxSegmentSize/2-1) + "\u0316" + rep(0x305, 5),
+ },
+}
+
+func TestIterNextD(t *testing.T) {
+ runIterTests(t, "IterNextD1", NFKD, appendTests, true)
+ runIterTests(t, "IterNextD2", NFKD, iterTests, true)
+ runIterTests(t, "IterNextD3", NFKD, iterTestsD, false)
+}
+
+func TestIterNextC(t *testing.T) {
+ runIterTests(t, "IterNextC1", NFKC, appendTests, true)
+ runIterTests(t, "IterNextC2", NFKC, iterTests, true)
+ runIterTests(t, "IterNextC3", NFKC, iterTestsC, false)
+}
+
+type SegmentTest struct {
+ in string
+ out []string
+}
+
+var segmentTests = []SegmentTest{
+ {rep('a', MaxSegmentSize), []string{rep('a', MaxSegmentSize), ""}},
+ {rep('a', MaxSegmentSize+2), []string{rep('a', MaxSegmentSize-1), "aaa", ""}},
+ {rep('a', MaxSegmentSize) + "\u0300aa", []string{rep('a', MaxSegmentSize-1), "a\u0300", "aa", ""}},
+}
+
+// Note that, by design, segmentation is equal for composing and decomposing forms.
+func TestIterSegmentation(t *testing.T) {
+ segmentTest(t, "SegmentTestD", NFD, segmentTests)
+ segmentTest(t, "SegmentTestC", NFC, segmentTests)
+}
+
+func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) {
+ iter := Iter{}
+ for i, tt := range segmentTests {
+ buf := make([]byte, MaxSegmentSize)
+ iter.SetInputString(f, tt.in)
+ for j, seg := range tt.out {
+ if seg == "" {
+ if !iter.Done() {
+ n := iter.Next(buf)
+ res := string(buf[:n])
+ t.Errorf(`%s:%d:%d: expected Done()==true, found segment "%s"`, name, i, j, res)
+ }
+ continue
+ }
+ if iter.Done() {
+ t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j)
+ }
+ n := iter.Next(buf)
+ seg = f.String(seg)
+ if res := string(buf[:n]); res != seg {
+ t.Errorf(`%s:%d:%d" segment was "%s" (%d); want "%s" (%d)`, name, i, j, res, len(res), seg, len(seg))
+ }
+ }
+ }
+}
diff --git a/libgo/go/exp/norm/normalize.go b/libgo/go/exp/norm/normalize.go
index 030d900918e..b5cd44abfa0 100644
--- a/libgo/go/exp/norm/normalize.go
+++ b/libgo/go/exp/norm/normalize.go
@@ -243,7 +243,7 @@ func quickSpan(rb *reorderBuffer, i int) int {
lastSegStart := i
src, n := rb.src, rb.nsrc
for i < n {
- if j := src.skipASCII(i); i != j {
+ if j := src.skipASCII(i, n); i != j {
i = j
lastSegStart = i - 1
lastCC = 0
@@ -448,11 +448,16 @@ func decomposeToLastBoundary(rb *reorderBuffer, buf []byte) []byte {
}
// Check that decomposition doesn't result in overflow.
if info.hasDecomposition() {
- dcomp := info.decomposition()
- for i := 0; i < len(dcomp); {
- inf := rb.f.info(inputBytes(dcomp), i)
- i += int(inf.size)
+ if isHangul(buf) {
+ i += int(info.size)
n++
+ } else {
+ dcomp := info.decomposition()
+ for i := 0; i < len(dcomp); {
+ inf := rb.f.info(inputBytes(dcomp), i)
+ i += int(inf.size)
+ n++
+ }
}
} else {
n++
diff --git a/libgo/go/exp/norm/normalize_test.go b/libgo/go/exp/norm/normalize_test.go
index c7d5e08fca0..8b970598b4d 100644
--- a/libgo/go/exp/norm/normalize_test.go
+++ b/libgo/go/exp/norm/normalize_test.go
@@ -5,6 +5,7 @@
package norm
import (
+ "bytes"
"strings"
"testing"
)
@@ -495,15 +496,40 @@ func TestAppend(t *testing.T) {
runAppendTests(t, "TestString", NFKC, stringF, appendTests)
}
+func appendBench(f Form, in []byte) func() {
+ buf := make([]byte, 0, 4*len(in))
+ return func() {
+ f.Append(buf, in...)
+ }
+}
+
+func iterBench(f Form, in []byte) func() {
+ buf := make([]byte, 4*len(in))
+ iter := Iter{}
+ return func() {
+ iter.SetInput(f, in)
+ for !iter.Done() {
+ iter.Next(buf)
+ }
+ }
+}
+
+func appendBenchmarks(bm []func(), f Form, in []byte) []func() {
+ //bm = append(bm, appendBench(f, in))
+ bm = append(bm, iterBench(f, in))
+ return bm
+}
+
func doFormBenchmark(b *testing.B, inf, f Form, s string) {
b.StopTimer()
in := inf.Bytes([]byte(s))
- buf := make([]byte, 2*len(in))
- b.SetBytes(int64(len(in)))
+ bm := appendBenchmarks(nil, f, in)
+ b.SetBytes(int64(len(in) * len(bm)))
b.StartTimer()
for i := 0; i < b.N; i++ {
- buf = f.Append(buf[0:0], in...)
- buf = buf[0:0]
+ for _, fn := range bm {
+ fn()
+ }
}
}
@@ -549,17 +575,21 @@ func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) {
doFormBenchmark(b, NFD, NFD, txt_kr)
}
+var forms = []Form{NFC, NFD, NFKC, NFKD}
+
func doTextBenchmark(b *testing.B, s string) {
b.StopTimer()
- b.SetBytes(int64(len(s)) * 4)
in := []byte(s)
- var buf = make([]byte, 0, 2*len(in))
+ bm := []func(){}
+ for _, f := range forms {
+ bm = appendBenchmarks(bm, f, in)
+ }
+ b.SetBytes(int64(len(s) * len(bm)))
b.StartTimer()
for i := 0; i < b.N; i++ {
- NFC.Append(buf, in...)
- NFD.Append(buf, in...)
- NFKC.Append(buf, in...)
- NFKD.Append(buf, in...)
+ for _, f := range bm {
+ f()
+ }
}
}
@@ -584,6 +614,11 @@ func BenchmarkJapanese(b *testing.B) {
func BenchmarkChinese(b *testing.B) {
doTextBenchmark(b, txt_cn)
}
+func BenchmarkOverflow(b *testing.B) {
+ doTextBenchmark(b, overflow)
+}
+
+var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B"
// Tests sampled from the Canonical ordering tests (Part 2) of
// http://unicode.org/Public/UNIDATA/NormalizationTest.txt
diff --git a/libgo/go/exp/norm/normregtest.go b/libgo/go/exp/norm/normregtest.go
index c2ab25bc99d..507de1ae834 100644
--- a/libgo/go/exp/norm/normregtest.go
+++ b/libgo/go/exp/norm/normregtest.go
@@ -220,6 +220,17 @@ func cmpIsNormal(t *Test, name string, f norm.Form, test string, result, want bo
func doTest(t *Test, f norm.Form, gold, test string) {
result := f.Bytes([]byte(test))
cmpResult(t, "Bytes", f, gold, test, string(result))
+ sresult := f.String(test)
+ cmpResult(t, "String", f, gold, test, sresult)
+ buf := make([]byte, norm.MaxSegmentSize)
+ acc := []byte{}
+ i := norm.Iter{}
+ i.SetInputString(f, test)
+ for !i.Done() {
+ n := i.Next(buf)
+ acc = append(acc, buf[:n]...)
+ }
+ cmpResult(t, "Iter.Next", f, gold, test, string(acc))
for i := range test {
out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...)
cmpResult(t, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out))
diff --git a/libgo/go/exp/proxy/socks5.go b/libgo/go/exp/proxy/socks5.go
index 466e135eb10..62fa5c9296d 100644
--- a/libgo/go/exp/proxy/socks5.go
+++ b/libgo/go/exp/proxy/socks5.go
@@ -98,9 +98,9 @@ func (s *socks5) Dial(network, addr string) (net.Conn, error) {
buf = append(buf, socks5Version)
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
- buf = append(buf, 2, /* num auth methods */ socks5AuthNone, socks5AuthPassword)
+ buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
} else {
- buf = append(buf, 1, /* num auth methods */ socks5AuthNone)
+ buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
}
if _, err = conn.Write(buf); err != nil {
@@ -139,7 +139,7 @@ func (s *socks5) Dial(network, addr string) (net.Conn, error) {
}
buf = buf[:0]
- buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */ )
+ buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
if ip := net.ParseIP(host); ip != nil {
if len(ip) == 4 {
diff --git a/libgo/go/exp/terminal/terminal.go b/libgo/go/exp/terminal/terminal.go
index c3ba5bde2ee..c1ed0c0c443 100644
--- a/libgo/go/exp/terminal/terminal.go
+++ b/libgo/go/exp/terminal/terminal.go
@@ -389,12 +389,12 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
// We have a prompt and possibly user input on the screen. We
// have to clear it first.
- t.move(0, /* up */ 0, /* down */ t.cursorX, /* left */ 0 /* right */ )
+ t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
t.cursorX = 0
t.clearLineToRight()
for t.cursorY > 0 {
- t.move(1, /* up */ 0, 0, 0)
+ t.move(1 /* up */, 0, 0, 0)
t.cursorY--
t.clearLineToRight()
}
diff --git a/libgo/go/exp/winfsnotify/winfsnotify_test.go b/libgo/go/exp/winfsnotify/winfsnotify_test.go
index 59ac1624a26..4a1929a8397 100644
--- a/libgo/go/exp/winfsnotify/winfsnotify_test.go
+++ b/libgo/go/exp/winfsnotify/winfsnotify_test.go
@@ -7,6 +7,7 @@
package winfsnotify
import (
+ "io/ioutil"
"os"
"testing"
"time"
@@ -115,7 +116,13 @@ func TestNotifyClose(t *testing.T) {
t.Fatal("double Close() test failed: second Close() call didn't return")
}
- err := watcher.Watch("_test")
+ dir, err := ioutil.TempDir("", "wininotify")
+ if err != nil {
+ t.Fatalf("TempDir failed: %s", err)
+ }
+ defer os.RemoveAll(dir)
+
+ err = watcher.Watch(dir)
if err == nil {
t.Fatal("expected error on Watch() after Close(), got nil")
}
diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go
index 1c23b0d95c3..a7e0e250a2e 100644
--- a/libgo/go/go/doc/example.go
+++ b/libgo/go/go/doc/example.go
@@ -2,28 +2,31 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Extract example functions from package ASTs.
+// Extract example functions from file ASTs.
package doc
import (
"go/ast"
- "go/printer"
"go/token"
+ "regexp"
+ "sort"
"strings"
"unicode"
"unicode/utf8"
)
type Example struct {
- Name string // name of the item being demonstrated
- Body *printer.CommentedNode // code
- Output string // expected output
+ Name string // name of the item being exemplified
+ Doc string // example function doc string
+ Code ast.Node
+ Comments []*ast.CommentGroup
+ Output string // expected output
}
-func Examples(pkg *ast.Package) []*Example {
+func Examples(files ...*ast.File) []*Example {
var list []*Example
- for _, file := range pkg.Files {
+ for _, file := range files {
hasTests := false // file contains tests or benchmarks
numDecl := 0 // number of non-import declarations in the file
var flist []*Example
@@ -45,26 +48,54 @@ func Examples(pkg *ast.Package) []*Example {
if !isTest(name, "Example") {
continue
}
+ var doc string
+ if f.Doc != nil {
+ doc = f.Doc.Text()
+ }
flist = append(flist, &Example{
- Name: name[len("Example"):],
- Body: &printer.CommentedNode{
- Node: f.Body,
- Comments: file.Comments,
- },
- Output: f.Doc.Text(),
+ Name: name[len("Example"):],
+ Doc: doc,
+ Code: f.Body,
+ Comments: file.Comments,
+ Output: exampleOutput(f, file.Comments),
})
}
if !hasTests && numDecl > 1 && len(flist) == 1 {
// If this file only has one example function, some
// other top-level declarations, and no tests or
// benchmarks, use the whole file as the example.
- flist[0].Body.Node = file
+ flist[0].Code = file
}
list = append(list, flist...)
}
+ sort.Sort(exampleByName(list))
return list
}
+var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
+
+func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string {
+ // find the last comment in the function
+ var last *ast.CommentGroup
+ for _, cg := range comments {
+ if cg.Pos() < fun.Pos() {
+ continue
+ }
+ if cg.End() > fun.End() {
+ break
+ }
+ last = cg
+ }
+ if last != nil {
+ // test that it begins with the correct prefix
+ text := last.Text()
+ if loc := outputPrefix.FindStringIndex(text); loc != nil {
+ return strings.TrimSpace(text[loc[1]:])
+ }
+ }
+ return "" // no suitable comment found
+}
+
// isTest tells whether name looks like a test, example, or benchmark.
// It is a Test (say) if there is a character after Test that is not a
// lower-case letter. (We don't want Testiness.)
@@ -78,3 +109,9 @@ func isTest(name, prefix string) bool {
rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
return !unicode.IsLower(rune)
}
+
+type exampleByName []*Example
+
+func (s exampleByName) Len() int { return len(s) }
+func (s exampleByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s exampleByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
diff --git a/libgo/go/go/doc/reader.go b/libgo/go/go/doc/reader.go
index bdfb294adb0..3558892ebd0 100644
--- a/libgo/go/go/doc/reader.go
+++ b/libgo/go/go/doc/reader.go
@@ -439,8 +439,10 @@ func (r *reader) readFile(src *ast.File) {
// gets to (re-)use the declaration documentation
// if there's none associated with the spec itself
fake := &ast.GenDecl{
- d.Doc, d.Pos(), token.TYPE, token.NoPos,
- []ast.Spec{s}, token.NoPos,
+ Doc: d.Doc,
+ TokPos: d.Pos(),
+ Tok: token.TYPE,
+ Specs: []ast.Spec{s},
}
r.readType(fake, s)
}
@@ -460,7 +462,7 @@ func (r *reader) readFile(src *ast.File) {
// non-empty BUG comment; collect comment without BUG prefix
list := append([]*ast.Comment(nil), c.List...) // make a copy
list[0].Text = text[m[1]:]
- r.bugs = append(r.bugs, (&ast.CommentGroup{list}).Text())
+ r.bugs = append(r.bugs, (&ast.CommentGroup{List: list}).Text())
}
}
}
@@ -530,7 +532,7 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int)
_, origRecvIsPtr := newField.Type.(*ast.StarExpr)
var typ ast.Expr = ast.NewIdent(recvTypeName)
if !embeddedIsPtr && origRecvIsPtr {
- typ = &ast.StarExpr{token.NoPos, typ}
+ typ = &ast.StarExpr{X: typ}
}
newField.Type = typ
diff --git a/libgo/go/go/doc/synopsis.go b/libgo/go/go/doc/synopsis.go
new file mode 100644
index 00000000000..2192d78c0cd
--- /dev/null
+++ b/libgo/go/go/doc/synopsis.go
@@ -0,0 +1,52 @@
+// Copyright 2012 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 doc
+
+import "unicode"
+
+// firstSentenceLen returns the length of the first sentence in s.
+// The sentence ends after the first period followed by space and
+// not preceded by exactly one uppercase letter.
+//
+func firstSentenceLen(s string) int {
+ var ppp, pp, p rune
+ for i, q := range s {
+ if q == '\n' || q == '\r' || q == '\t' {
+ q = ' '
+ }
+ if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) {
+ return i
+ }
+ ppp, pp, p = pp, p, q
+ }
+ return len(s)
+}
+
+// Synopsis returns a cleaned version of the first sentence in s.
+// That sentence ends after the first period followed by space and
+// not preceded by exactly one uppercase letter. The result string
+// has no \n, \r, or \t characters and uses only single spaces between
+// words.
+//
+func Synopsis(s string) string {
+ n := firstSentenceLen(s)
+ var b []byte
+ p := byte(' ')
+ for i := 0; i < n; i++ {
+ q := s[i]
+ if q == '\n' || q == '\r' || q == '\t' {
+ q = ' '
+ }
+ if q != ' ' || p != ' ' {
+ b = append(b, q)
+ p = q
+ }
+ }
+ // remove trailing blank, if any
+ if n := len(b); n > 0 && p == ' ' {
+ b = b[0 : n-1]
+ }
+ return string(b)
+}
diff --git a/libgo/go/go/doc/synopsis_test.go b/libgo/go/go/doc/synopsis_test.go
new file mode 100644
index 00000000000..dfc6598af47
--- /dev/null
+++ b/libgo/go/go/doc/synopsis_test.go
@@ -0,0 +1,44 @@
+// Copyright 2012 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 doc
+
+import "testing"
+
+var tests = []struct {
+ txt string
+ fsl int
+ syn string
+}{
+ {"", 0, ""},
+ {"foo", 3, "foo"},
+ {"foo.", 4, "foo."},
+ {"foo.bar", 7, "foo.bar"},
+ {" foo. ", 6, "foo."},
+ {" foo\t bar.\n", 12, "foo bar."},
+ {" foo\t bar.\n", 12, "foo bar."},
+ {"a b\n\nc\r\rd\t\t", 12, "a b c d"},
+ {"a b\n\nc\r\rd\t\t . BLA", 15, "a b c d ."},
+ {"Package poems by T.S.Eliot. To rhyme...", 27, "Package poems by T.S.Eliot."},
+ {"Package poems by T. S. Eliot. To rhyme...", 29, "Package poems by T. S. Eliot."},
+ {"foo implements the foo ABI. The foo ABI is...", 27, "foo implements the foo ABI."},
+ {"Package\nfoo. ..", 12, "Package foo."},
+ {"P . Q.", 3, "P ."},
+ {"P. Q. ", 8, "P. Q."},
+ {"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},
+ {"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},
+}
+
+func TestSynopsis(t *testing.T) {
+ for _, e := range tests {
+ fsl := firstSentenceLen(e.txt)
+ if fsl != e.fsl {
+ t.Errorf("got fsl = %d; want %d for %q\n", fsl, e.fsl, e.txt)
+ }
+ syn := Synopsis(e.txt)
+ if syn != e.syn {
+ t.Errorf("got syn = %q; want %q for %q\n", syn, e.syn, e.txt)
+ }
+ }
+}
diff --git a/libgo/go/go/doc/testdata/benchmark.go b/libgo/go/go/doc/testdata/benchmark.go
index 0bf567b7c4d..0aded5bb4c7 100644
--- a/libgo/go/go/doc/testdata/benchmark.go
+++ b/libgo/go/go/doc/testdata/benchmark.go
@@ -16,7 +16,7 @@ var matchBenchmarks = flag.String("test.bench", "", "regular expression to selec
var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds")
// An internal type but exported because it is cross-package; part of the implementation
-// of gotest.
+// of go test.
type InternalBenchmark struct {
Name string
F func(b *B)
@@ -213,7 +213,7 @@ func (r BenchmarkResult) String() string {
}
// An internal function but exported because it is cross-package; part of the implementation
-// of gotest.
+// of go test.
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
// If no flag was specified, don't run benchmarks.
if len(*matchBenchmarks) == 0 {
@@ -281,7 +281,7 @@ func (b *B) trimOutput() {
}
// Benchmark benchmarks a single function. Useful for creating
-// custom benchmarks that do not use gotest.
+// custom benchmarks that do not use go test.
func Benchmark(f func(b *B)) BenchmarkResult {
b := &B{
common: common{
diff --git a/libgo/go/go/doc/testdata/testing.1.golden b/libgo/go/go/doc/testdata/testing.1.golden
index 1f92f8fe3e1..d26a4685ca0 100644
--- a/libgo/go/go/doc/testdata/testing.1.golden
+++ b/libgo/go/go/doc/testdata/testing.1.golden
@@ -27,7 +27,7 @@ VARIABLES
// The short flag requests that tests run more quickly, but its functionality
// is provided by test writers themselves. The testing package is just its
// home. The all.bash installation script sets it to make installation more
- // efficient, but by default the flag is off so a plain "gotest" will do a
+ // efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
diff --git a/libgo/go/go/doc/testdata/testing.go b/libgo/go/go/doc/testdata/testing.go
index cfe212dc1d7..71c1d1eaf0e 100644
--- a/libgo/go/go/doc/testdata/testing.go
+++ b/libgo/go/go/doc/testdata/testing.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package testing provides support for automated testing of Go packages.
-// It is intended to be used in concert with the ``gotest'' utility, which automates
+// It is intended to be used in concert with the ``go test'' utility, which automates
// execution of any function of the form
// func TestXxx(*testing.T)
// where Xxx can be any alphanumeric string (but the first letter must not be in
@@ -12,7 +12,7 @@
//
// Functions of the form
// func BenchmarkXxx(*testing.B)
-// are considered benchmarks, and are executed by gotest when the -test.bench
+// are considered benchmarks, and are executed by go test when the -test.bench
// flag is provided.
//
// A sample benchmark function looks like this:
@@ -53,7 +53,7 @@ var (
// The short flag requests that tests run more quickly, but its functionality
// is provided by test writers themselves. The testing package is just its
// home. The all.bash installation script sets it to make installation more
- // efficient, but by default the flag is off so a plain "gotest" will do a
+ // efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -205,7 +205,7 @@ func (t *T) Parallel() {
}
// An internal type but exported because it is cross-package; part of the implementation
-// of gotest.
+// of go test.
type InternalTest struct {
Name string
F func(*T)
@@ -227,7 +227,7 @@ func tRunner(t *T, test *InternalTest) {
}
// An internal function but exported because it is cross-package; part of the implementation
-// of gotest.
+// of go test.
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
flag.Parse()
parseCpuList()
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index 6a0b61eb48c..c1e61904486 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -249,7 +249,7 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
}
}
- comment = &ast.Comment{p.pos, p.lit}
+ comment = &ast.Comment{Slash: p.pos, Text: p.lit}
p.next0()
return
@@ -270,7 +270,7 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
}
// add comment group to the comments list
- comments = &ast.CommentGroup{list}
+ comments = &ast.CommentGroup{List: list}
p.comments = append(p.comments, comments)
return
@@ -391,7 +391,7 @@ func (p *parser) parseIdent() *ast.Ident {
} else {
p.expect(token.IDENT) // use expect() error handling
}
- return &ast.Ident{pos, name, nil}
+ return &ast.Ident{NamePos: pos, Name: name}
}
func (p *parser) parseIdentList() (list []*ast.Ident) {
@@ -469,7 +469,7 @@ func (p *parser) parseType() ast.Expr {
pos := p.pos
p.errorExpected(pos, "type")
p.next() // make progress
- return &ast.BadExpr{pos, p.pos}
+ return &ast.BadExpr{From: pos, To: p.pos}
}
return typ
@@ -489,7 +489,7 @@ func (p *parser) parseTypeName() ast.Expr {
p.next()
p.resolve(ident)
sel := p.parseIdent()
- return &ast.SelectorExpr{ident, sel}
+ return &ast.SelectorExpr{X: ident, Sel: sel}
}
return ident
@@ -503,7 +503,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
lbrack := p.expect(token.LBRACK)
var len ast.Expr
if ellipsisOk && p.tok == token.ELLIPSIS {
- len = &ast.Ellipsis{p.pos, nil}
+ len = &ast.Ellipsis{Ellipsis: p.pos}
p.next()
} else if p.tok != token.RBRACK {
len = p.parseRhs()
@@ -511,7 +511,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
p.expect(token.RBRACK)
elt := p.parseType()
- return &ast.ArrayType{lbrack, len, elt}
+ return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}
}
func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
@@ -521,7 +521,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
if !isIdent {
pos := x.Pos()
p.errorExpected(pos, "identifier")
- ident = &ast.Ident{pos, "_", nil}
+ ident = &ast.Ident{NamePos: pos, Name: "_"}
}
idents[i] = ident
}
@@ -541,7 +541,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
// optional tag
var tag *ast.BasicLit
if p.tok == token.STRING {
- tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+ tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
}
@@ -557,13 +557,13 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if n := len(list); n > 1 || !isTypeName(deref(typ)) {
pos := typ.Pos()
p.errorExpected(pos, "anonymous field")
- typ = &ast.BadExpr{pos, list[n-1].End()}
+ typ = &ast.BadExpr{From: pos, To: list[n-1].End()}
}
}
p.expectSemi() // call before accessing p.linecomment
- field := &ast.Field{doc, idents, typ, tag, p.lineComment}
+ field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
p.declare(field, nil, scope, ast.Var, idents...)
return field
@@ -586,7 +586,14 @@ func (p *parser) parseStructType() *ast.StructType {
}
rbrace := p.expect(token.RBRACE)
- return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+ return &ast.StructType{
+ Struct: pos,
+ Fields: &ast.FieldList{
+ Opening: lbrace,
+ List: list,
+ Closing: rbrace,
+ },
+ }
}
func (p *parser) parsePointerType() *ast.StarExpr {
@@ -597,7 +604,7 @@ func (p *parser) parsePointerType() *ast.StarExpr {
star := p.expect(token.MUL)
base := p.parseType()
- return &ast.StarExpr{star, base}
+ return &ast.StarExpr{Star: star, X: base}
}
func (p *parser) tryVarType(isParam bool) ast.Expr {
@@ -607,9 +614,9 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
if typ == nil {
p.error(pos, "'...' parameter is missing type")
- typ = &ast.BadExpr{pos, p.pos}
+ typ = &ast.BadExpr{From: pos, To: p.pos}
}
- return &ast.Ellipsis{pos, typ}
+ return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
}
return p.tryIdentOrType(false)
}
@@ -620,7 +627,7 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
pos := p.pos
p.errorExpected(pos, "type")
p.next() // make progress
- typ = &ast.BadExpr{pos, p.pos}
+ typ = &ast.BadExpr{From: pos, To: p.pos}
}
return typ
}
@@ -661,7 +668,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
if typ != nil {
// IdentifierList Type
idents := p.makeIdentList(list)
- field := &ast.Field{nil, idents, typ, nil, nil}
+ field := &ast.Field{Names: idents, Type: typ}
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
@@ -673,7 +680,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
for p.tok != token.RPAREN && p.tok != token.EOF {
idents := p.parseIdentList()
typ := p.parseVarType(ellipsisOk)
- field := &ast.Field{nil, idents, typ, nil, nil}
+ field := &ast.Field{Names: idents, Type: typ}
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
@@ -708,7 +715,7 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
}
rparen := p.expect(token.RPAREN)
- return &ast.FieldList{lparen, params, rparen}
+ return &ast.FieldList{Opening: lparen, List: params, Closing: rparen}
}
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
@@ -750,7 +757,7 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
scope := ast.NewScope(p.topScope) // function scope
params, results := p.parseSignature(scope)
- return &ast.FuncType{pos, params, results}, scope
+ return &ast.FuncType{Func: pos, Params: params, Results: results}, scope
}
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
@@ -767,7 +774,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
idents = []*ast.Ident{ident}
scope := ast.NewScope(nil) // method scope
params, results := p.parseSignature(scope)
- typ = &ast.FuncType{token.NoPos, params, results}
+ typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
} else {
// embedded interface
typ = x
@@ -775,7 +782,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
}
p.expectSemi() // call before accessing p.linecomment
- spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
+ spec := &ast.Field{Doc: doc, Names: idents, Type: typ, Comment: p.lineComment}
p.declare(spec, nil, scope, ast.Fun, idents...)
return spec
@@ -795,7 +802,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
}
rbrace := p.expect(token.RBRACE)
- return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+ return &ast.InterfaceType{
+ Interface: pos,
+ Methods: &ast.FieldList{
+ Opening: lbrace,
+ List: list,
+ Closing: rbrace,
+ },
+ }
}
func (p *parser) parseMapType() *ast.MapType {
@@ -809,7 +823,7 @@ func (p *parser) parseMapType() *ast.MapType {
p.expect(token.RBRACK)
value := p.parseType()
- return &ast.MapType{pos, key, value}
+ return &ast.MapType{Map: pos, Key: key, Value: value}
}
func (p *parser) parseChanType() *ast.ChanType {
@@ -832,7 +846,7 @@ func (p *parser) parseChanType() *ast.ChanType {
}
value := p.parseType()
- return &ast.ChanType{pos, dir, value}
+ return &ast.ChanType{Begin: pos, Dir: dir, Value: value}
}
// If the result is an identifier, it is not resolved.
@@ -860,7 +874,7 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
p.next()
typ := p.parseType()
rparen := p.expect(token.RPAREN)
- return &ast.ParenExpr{lparen, typ, rparen}
+ return &ast.ParenExpr{Lparen: lparen, X: typ, Rparen: rparen}
}
// no type found
@@ -903,7 +917,7 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
p.closeScope()
rbrace := p.expect(token.RBRACE)
- return &ast.BlockStmt{lbrace, list, rbrace}
+ return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
func (p *parser) parseBlockStmt() *ast.BlockStmt {
@@ -917,7 +931,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
p.closeScope()
rbrace := p.expect(token.RBRACE)
- return &ast.BlockStmt{lbrace, list, rbrace}
+ return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
// ----------------------------------------------------------------------------
@@ -938,7 +952,7 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
body := p.parseBody(scope)
p.exprLev--
- return &ast.FuncLit{typ, body}
+ return &ast.FuncLit{Type: typ, Body: body}
}
// parseOperand may return an expression or a raw type (incl. array
@@ -959,7 +973,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return x
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
- x := &ast.BasicLit{p.pos, p.tok, p.lit}
+ x := &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
return x
@@ -970,7 +984,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
x := p.parseRhsOrType() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
- return &ast.ParenExpr{lparen, x, rparen}
+ return &ast.ParenExpr{Lparen: lparen, X: x, Rparen: rparen}
case token.FUNC:
return p.parseFuncTypeOrLit()
@@ -987,7 +1001,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
pos := p.pos
p.errorExpected(pos, "operand")
p.next() // make progress
- return &ast.BadExpr{pos, p.pos}
+ return &ast.BadExpr{From: pos, To: p.pos}
}
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
@@ -997,7 +1011,7 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
sel := p.parseIdent()
- return &ast.SelectorExpr{x, sel}
+ return &ast.SelectorExpr{X: x, Sel: sel}
}
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
@@ -1015,7 +1029,7 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
}
p.expect(token.RPAREN)
- return &ast.TypeAssertExpr{x, typ}
+ return &ast.TypeAssertExpr{X: x, Type: typ}
}
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
@@ -1041,9 +1055,9 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
rbrack := p.expect(token.RBRACK)
if isSlice {
- return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: low, High: high, Rbrack: rbrack}
}
- return &ast.IndexExpr{x, lbrack, low, rbrack}
+ return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: low, Rbrack: rbrack}
}
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
@@ -1069,7 +1083,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
p.exprLev--
rparen := p.expectClosing(token.RPAREN, "argument list")
- return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+ return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen}
}
func (p *parser) parseElement(keyOk bool) ast.Expr {
@@ -1086,7 +1100,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.tok == token.COLON {
colon := p.pos
p.next()
- return &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+ return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)}
}
p.resolve(x) // not a map key
}
@@ -1123,7 +1137,7 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
}
p.exprLev--
rbrace := p.expectClosing(token.RBRACE, "composite literal")
- return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+ return &ast.CompositeLit{Type: typ, Lbrace: lbrace, Elts: elts, Rbrace: rbrace}
}
// checkExpr checks that x is an expression (and not a type).
@@ -1152,7 +1166,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos(), x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: x.End()}
}
return x
}
@@ -1215,7 +1229,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
p.error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{x.Pos(), x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: x.End()}
}
}
@@ -1247,7 +1261,7 @@ L:
pos := p.pos
p.next() // make progress
p.errorExpected(pos, "selector or type assertion")
- x = &ast.BadExpr{pos, p.pos}
+ x = &ast.BadExpr{From: pos, To: p.pos}
}
case token.LBRACK:
if lhs {
@@ -1288,7 +1302,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
pos, op := p.pos, p.tok
p.next()
x := p.parseUnaryExpr(false)
- return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: pos, Op: op, X: p.checkExpr(x)}
case token.ARROW:
// channel type or receive expression
@@ -1297,18 +1311,18 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.tok == token.CHAN {
p.next()
value := p.parseType()
- return &ast.ChanType{pos, ast.RECV, value}
+ return &ast.ChanType{Begin: pos, Dir: ast.RECV, Value: value}
}
x := p.parseUnaryExpr(false)
- return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: pos, Op: token.ARROW, X: p.checkExpr(x)}
case token.MUL:
// pointer type or unary "*" expression
pos := p.pos
p.next()
x := p.parseUnaryExpr(false)
- return &ast.StarExpr{pos, p.checkExprOrType(x)}
+ return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
}
return p.parsePrimaryExpr(lhs)
@@ -1330,7 +1344,7 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
lhs = false
}
y := p.parseBinaryExpr(false, prec+1)
- x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+ x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
}
}
@@ -1392,12 +1406,12 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
if mode == rangeOk && p.tok == token.RANGE && (tok == token.DEFINE || tok == token.ASSIGN) {
pos := p.pos
p.next()
- y = []ast.Expr{&ast.UnaryExpr{pos, token.RANGE, p.parseRhs()}}
+ y = []ast.Expr{&ast.UnaryExpr{OpPos: pos, Op: token.RANGE, X: p.parseRhs()}}
isRange = true
} else {
y = p.parseRhsList()
}
- as := &ast.AssignStmt{x, pos, tok, y}
+ as := &ast.AssignStmt{Lhs: x, TokPos: pos, Tok: tok, Rhs: y}
if tok == token.DEFINE {
p.shortVarDecl(as, x)
}
@@ -1418,7 +1432,7 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
// Go spec: The scope of a label is the body of the function
// in which it is declared and excludes the body of any nested
// function.
- stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
+ stmt := &ast.LabeledStmt{Label: label, Colon: colon, Stmt: p.parseStmt()}
p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
return stmt, false
}
@@ -1429,24 +1443,24 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
// before the ':' that caused the problem. Thus, use the (latest) colon
// position for error reporting.
p.error(colon, "illegal label declaration")
- return &ast.BadStmt{x[0].Pos(), colon + 1}, false
+ return &ast.BadStmt{From: x[0].Pos(), To: colon + 1}, false
case token.ARROW:
// send statement
arrow := p.pos
p.next()
y := p.parseRhs()
- return &ast.SendStmt{x[0], arrow, y}, false
+ return &ast.SendStmt{Chan: x[0], Arrow: arrow, Value: y}, false
case token.INC, token.DEC:
// increment or decrement
- s := &ast.IncDecStmt{x[0], p.pos, p.tok}
+ s := &ast.IncDecStmt{X: x[0], TokPos: p.pos, Tok: p.tok}
p.next()
return s, false
}
// expression
- return &ast.ExprStmt{x[0]}, false
+ return &ast.ExprStmt{X: x[0]}, false
}
func (p *parser) parseCallExpr() *ast.CallExpr {
@@ -1467,10 +1481,10 @@ func (p *parser) parseGoStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos, pos + 2} // len("go")
+ return &ast.BadStmt{From: pos, To: pos + 2} // len("go")
}
- return &ast.GoStmt{pos, call}
+ return &ast.GoStmt{Go: pos, Call: call}
}
func (p *parser) parseDeferStmt() ast.Stmt {
@@ -1482,10 +1496,10 @@ func (p *parser) parseDeferStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos, pos + 5} // len("defer")
+ return &ast.BadStmt{From: pos, To: pos + 5} // len("defer")
}
- return &ast.DeferStmt{pos, call}
+ return &ast.DeferStmt{Defer: pos, Call: call}
}
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
@@ -1501,7 +1515,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
}
p.expectSemi()
- return &ast.ReturnStmt{pos, x}
+ return &ast.ReturnStmt{Return: pos, Results: x}
}
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
@@ -1519,7 +1533,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
}
p.expectSemi()
- return &ast.BranchStmt{pos, tok, label}
+ return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
}
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
@@ -1530,7 +1544,7 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return p.checkExpr(es.X)
}
p.error(s.Pos(), "expected condition, found simple statement")
- return &ast.BadExpr{s.Pos(), s.End()}
+ return &ast.BadExpr{From: s.Pos(), To: s.End()}
}
func (p *parser) parseIfStmt() *ast.IfStmt {
@@ -1572,7 +1586,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.expectSemi()
}
- return &ast.IfStmt{pos, s, x, body, else_}
+ return &ast.IfStmt{If: pos, Init: s, Cond: x, Body: body, Else: else_}
}
func (p *parser) parseTypeList() (list []ast.Expr) {
@@ -1612,7 +1626,7 @@ func (p *parser) parseCaseClause(typeSwitch bool) *ast.CaseClause {
body := p.parseStmtList()
p.closeScope()
- return &ast.CaseClause{pos, list, colon, body}
+ return &ast.CaseClause{Case: pos, List: list, Colon: colon, Body: body}
}
func isTypeSwitchAssert(x ast.Expr) bool {
@@ -1681,13 +1695,13 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, list, rbrace}
+ body := &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
if typeSwitch {
- return &ast.TypeSwitchStmt{pos, s1, s2, body}
+ return &ast.TypeSwitchStmt{Switch: pos, Init: s1, Assign: s2, Body: body}
}
- return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+ return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2), Body: body}
}
func (p *parser) parseCommClause() *ast.CommClause {
@@ -1710,7 +1724,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
arrow := p.pos
p.next()
rhs := p.parseRhs()
- comm = &ast.SendStmt{lhs[0], arrow, rhs}
+ comm = &ast.SendStmt{Chan: lhs[0], Arrow: arrow, Value: rhs}
} else {
// RecvStmt
if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
@@ -1723,7 +1737,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
pos := p.pos
p.next()
rhs := p.parseRhs()
- as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+ as := &ast.AssignStmt{Lhs: lhs, TokPos: pos, Tok: tok, Rhs: []ast.Expr{rhs}}
if tok == token.DEFINE {
p.shortVarDecl(as, lhs)
}
@@ -1734,7 +1748,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
p.errorExpected(lhs[0].Pos(), "1 expression")
// continue with first expression
}
- comm = &ast.ExprStmt{lhs[0]}
+ comm = &ast.ExprStmt{X: lhs[0]}
}
}
} else {
@@ -1745,7 +1759,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
body := p.parseStmtList()
p.closeScope()
- return &ast.CommClause{pos, comm, colon, body}
+ return &ast.CommClause{Case: pos, Comm: comm, Colon: colon, Body: body}
}
func (p *parser) parseSelectStmt() *ast.SelectStmt {
@@ -1761,9 +1775,9 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, list, rbrace}
+ body := &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
- return &ast.SelectStmt{pos, body}
+ return &ast.SelectStmt{Select: pos, Body: body}
}
func (p *parser) parseForStmt() ast.Stmt {
@@ -1812,16 +1826,30 @@ func (p *parser) parseForStmt() ast.Stmt {
key = as.Lhs[0]
default:
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
- return &ast.BadStmt{pos, body.End()}
+ return &ast.BadStmt{From: pos, To: body.End()}
}
// parseSimpleStmt returned a right-hand side that
// is a single unary expression of the form "range x"
x := as.Rhs[0].(*ast.UnaryExpr).X
- return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, x, body}
+ return &ast.RangeStmt{
+ For: pos,
+ Key: key,
+ Value: value,
+ TokPos: as.TokPos,
+ Tok: as.Tok,
+ X: x,
+ Body: body,
+ }
}
// regular for statement
- return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+ return &ast.ForStmt{
+ For: pos,
+ Init: s1,
+ Cond: p.makeExpr(s2),
+ Post: s3,
+ Body: body,
+ }
}
func (p *parser) parseStmt() (s ast.Stmt) {
@@ -1831,12 +1859,12 @@ func (p *parser) parseStmt() (s ast.Stmt) {
switch p.tok {
case token.CONST, token.TYPE, token.VAR:
- s = &ast.DeclStmt{p.parseDecl()}
+ s = &ast.DeclStmt{Decl: p.parseDecl()}
case
- // tokens that may start a top-level expression
- token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
- token.LBRACK, token.STRUCT, // composite type
- token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+ // tokens that may start an expression
+ token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
+ token.LBRACK, token.STRUCT, // composite types
+ token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators
s, _ = p.parseSimpleStmt(labelOk)
// because of the required look-ahead, labeled statements are
// parsed by parseSimpleStmt - don't expect a semicolon after
@@ -1864,17 +1892,17 @@ func (p *parser) parseStmt() (s ast.Stmt) {
case token.FOR:
s = p.parseForStmt()
case token.SEMICOLON:
- s = &ast.EmptyStmt{p.pos}
+ s = &ast.EmptyStmt{Semicolon: p.pos}
p.next()
case token.RBRACE:
// a semicolon may be omitted before a closing "}"
- s = &ast.EmptyStmt{p.pos}
+ s = &ast.EmptyStmt{Semicolon: p.pos}
default:
// no statement found
pos := p.pos
p.errorExpected(pos, "statement")
p.next() // make progress
- s = &ast.BadStmt{pos, p.pos}
+ s = &ast.BadStmt{From: pos, To: p.pos}
}
return
@@ -1893,7 +1921,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var ident *ast.Ident
switch p.tok {
case token.PERIOD:
- ident = &ast.Ident{p.pos, ".", nil}
+ ident = &ast.Ident{NamePos: p.pos, Name: "."}
p.next()
case token.IDENT:
ident = p.parseIdent()
@@ -1901,7 +1929,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var path *ast.BasicLit
if p.tok == token.STRING {
- path = &ast.BasicLit{p.pos, p.tok, p.lit}
+ path = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
} else {
p.expect(token.STRING) // use expect() error handling
@@ -1909,7 +1937,12 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
p.expectSemi() // call before accessing p.linecomment
// collect imports
- spec := &ast.ImportSpec{doc, ident, path, p.lineComment, token.NoPos}
+ spec := &ast.ImportSpec{
+ Doc: doc,
+ Name: ident,
+ Path: path,
+ Comment: p.lineComment,
+ }
p.imports = append(p.imports, spec)
return spec
@@ -1933,7 +1966,13 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
// a function begins at the end of the ConstSpec or VarSpec and ends at
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
- spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ spec := &ast.ValueSpec{
+ Doc: doc,
+ Names: idents,
+ Type: typ,
+ Values: values,
+ Comment: p.lineComment,
+ }
p.declare(spec, iota, p.topScope, ast.Con, idents...)
return spec
@@ -1950,7 +1989,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// at the identifier in the TypeSpec and ends at the end of the innermost
// containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
- spec := &ast.TypeSpec{doc, ident, nil, nil}
+ spec := &ast.TypeSpec{Doc: doc, Name: ident}
p.declare(spec, nil, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
@@ -1978,7 +2017,13 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// a function begins at the end of the ConstSpec or VarSpec and ends at
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
- spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ spec := &ast.ValueSpec{
+ Doc: doc,
+ Names: idents,
+ Type: typ,
+ Values: values,
+ Comment: p.lineComment,
+ }
p.declare(spec, nil, p.topScope, ast.Var, idents...)
return spec
@@ -2005,7 +2050,14 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
list = append(list, f(p, nil, 0))
}
- return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+ return &ast.GenDecl{
+ Doc: doc,
+ TokPos: pos,
+ Tok: keyword,
+ Lparen: lparen,
+ Specs: list,
+ Rparen: rparen,
+ }
}
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
@@ -2018,7 +2070,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
// must have exactly one receiver
if par.NumFields() != 1 {
p.errorExpected(par.Opening, "exactly one receiver")
- par.List = []*ast.Field{{Type: &ast.BadExpr{par.Opening, par.Closing + 1}}}
+ par.List = []*ast.Field{{Type: &ast.BadExpr{From: par.Opening, To: par.Closing + 1}}}
return par
}
@@ -2027,7 +2079,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
base := deref(recv.Type)
if _, isIdent := base.(*ast.Ident); !isIdent {
p.errorExpected(base.Pos(), "(unqualified) identifier")
- par.List = []*ast.Field{{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ par.List = []*ast.Field{{Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}}}
}
return par
@@ -2057,7 +2109,17 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
}
p.expectSemi()
- decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+ decl := &ast.FuncDecl{
+ Doc: doc,
+ Recv: recv,
+ Name: ident,
+ Type: &ast.FuncType{
+ Func: pos,
+ Params: params,
+ Results: results,
+ },
+ Body: body,
+ }
if recv == nil {
// Go spec: The scope of an identifier denoting a constant, type,
// variable, or function (but not method) declared at top level
@@ -2096,7 +2158,7 @@ func (p *parser) parseDecl() ast.Decl {
pos := p.pos
p.errorExpected(pos, "declaration")
p.next() // make progress
- decl := &ast.BadDecl{pos, p.pos}
+ decl := &ast.BadDecl{From: pos, To: p.pos}
return decl
}
@@ -2155,5 +2217,14 @@ func (p *parser) parseFile() *ast.File {
}
}
- return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
+ return &ast.File{
+ Doc: doc,
+ Package: pos,
+ Name: ident,
+ Decls: decls,
+ Scope: p.pkgScope,
+ Imports: p.imports,
+ Unresolved: p.unresolved[0:i],
+ Comments: p.comments,
+ }
}
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 25935fb42bb..cd5e075c16c 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -87,7 +87,6 @@ const (
commaSep // elements are separated by commas
commaTerm // list is optionally terminated by a comma
noIndent // no extra indentation in multi-line lists
- periodSep // elements are separated by periods
)
// Sets multiLine to true if the identifier list spans multiple lines.
@@ -133,7 +132,9 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
for i, x := range list {
if i > 0 {
if mode&commaSep != 0 {
- p.print(token.COMMA)
+ // use position of expression following the comma as
+ // comma position for correct comment placement
+ p.print(x.Pos(), token.COMMA)
}
p.print(blank)
}
@@ -213,14 +214,18 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
if i > 0 {
- switch {
- case mode&commaSep != 0:
+ needsLinebreak := prevLine < line && prevLine > 0 && line > 0
+ if mode&commaSep != 0 {
+ // use position of expression following the comma as
+ // comma position for correct comment placement, but
+ // only if the expression is on the same line
+ if !needsLinebreak {
+ p.print(x.Pos())
+ }
p.print(token.COMMA)
- case mode&periodSep != 0:
- p.print(token.PERIOD)
}
- needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
- if prevLine < line && prevLine > 0 && line > 0 {
+ needsBlank := true
+ if needsLinebreak {
// lines are broken using newlines so comments remain aligned
// unless forceFF is set or there are multiple expressions on
// the same line in which case formfeed is used
@@ -287,11 +292,18 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
parLineBeg = parLineEnd
}
// separating "," if needed
+ needsLinebreak := 0 < prevLine && prevLine < parLineBeg
if i > 0 {
+ // use position of parameter following the comma as
+ // comma position for correct comma placement, but
+ // only if the next parameter is on the same line
+ if !needsLinebreak {
+ p.print(par.Pos())
+ }
p.print(token.COMMA)
}
// separator if needed (linebreak or blank)
- if 0 < prevLine && prevLine < parLineBeg && p.linebreak(parLineBeg, 0, ws, true) {
+ if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) {
// break line if the opening "(" or previous parameter ended on a different line
ws = ignore
*multiLine = true
@@ -316,7 +328,7 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
// if the closing ")" is on a separate line from the last parameter,
// print an additional "," and line break
if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
- p.print(",")
+ p.print(token.COMMA)
p.linebreak(closing, 0, ignore, true)
}
// unindent if we indented
@@ -374,7 +386,7 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
}
func (p *printer) setLineComment(text string) {
- p.setComment(&ast.CommentGroup{[]*ast.Comment{{token.NoPos, text}}})
+ p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
}
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
@@ -397,6 +409,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
f := list[0]
for i, x := range f.Names {
if i > 0 {
+ // no comments so no need for comma position
p.print(token.COMMA, blank)
}
p.expr(x, ignoreMultiLine)
@@ -668,63 +681,6 @@ func isBinary(expr ast.Expr) bool {
return ok
}
-// If the expression contains one or more selector expressions, splits it into
-// two expressions at the rightmost period. Writes entire expr to suffix when
-// selector isn't found. Rewrites AST nodes for calls, index expressions and
-// type assertions, all of which may be found in selector chains, to make them
-// parts of the chain.
-func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
- switch x := expr.(type) {
- case *ast.SelectorExpr:
- body, suffix = x.X, x.Sel
- return
- case *ast.CallExpr:
- body, suffix = splitSelector(x.Fun)
- if body != nil {
- suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
- return
- }
- case *ast.IndexExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
- return
- }
- case *ast.SliceExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
- return
- }
- case *ast.TypeAssertExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.TypeAssertExpr{suffix, x.Type}
- return
- }
- }
- suffix = expr
- return
-}
-
-// Convert an expression into an expression list split at the periods of
-// selector expressions.
-func selectorExprList(expr ast.Expr) (list []ast.Expr) {
- // split expression
- for expr != nil {
- var suffix ast.Expr
- expr, suffix = splitSelector(expr)
- list = append(list, suffix)
- }
-
- // reverse list
- for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
- list[i], list[j] = list[j], list[i]
- }
-
- return
-}
-
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(expr.Pos())
@@ -798,8 +754,14 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
}
case *ast.SelectorExpr:
- parts := selectorExprList(expr)
- p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
+ p.expr1(x.X, token.HighestPrec, depth, multiLine)
+ p.print(token.PERIOD)
+ if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
+ p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent)
+ *multiLine = true
+ } else {
+ p.print(x.Sel.Pos(), x.Sel)
+ }
case *ast.TypeAssertExpr:
p.expr1(x.X, token.HighestPrec, depth, multiLine)
@@ -1180,7 +1142,9 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(token.FOR, blank)
p.expr(s.Key, multiLine)
if s.Value != nil {
- p.print(token.COMMA, blank)
+ // use position of value following the comma as
+ // comma position for correct comment placement
+ p.print(s.Value.Pos(), token.COMMA, blank)
p.expr(s.Value, multiLine)
}
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index c9949205e8a..72f65a1d852 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -686,9 +686,11 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
}
if last != nil {
- if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line {
- // the last comment is a /*-style comment and the next item
- // follows on the same line: separate with an extra blank
+ // if the last comment is a /*-style comment and the next item
+ // follows on the same line but is not a comma or a "closing"
+ // token, add an extra blank for separation
+ if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
+ tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
p.writeByte(' ', 1)
}
// ensure that there is a line break after a //-style comment,
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index fa133cd35f0..2d4f61356c1 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -283,10 +283,10 @@ func fibo(n int) {
t.Error("expected offset 1") // error in test
}
- testComment(t, f, len(src), &ast.Comment{pos, "//-style comment"})
- testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment */"})
- testComment(t, f, len(src), &ast.Comment{pos, "/*-style \n comment */"})
- testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment \n\n\n */"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "//-style comment"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style comment */"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style \n comment */"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style comment \n\n\n */"})
}
type visitor chan *ast.Ident
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index e5826eecefe..4c6f1ab8274 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -405,16 +405,17 @@ func _() {
}
// Some interesting interspersed comments.
+// See below for more common cases.
func _( /* this */ x /* is */ /* an */ int) {
}
-func _( /* no params */ ) {}
+func _( /* no params */) {}
func _() {
- f( /* no args */ )
+ f( /* no args */)
}
-func ( /* comment1 */ T /* comment2 */ ) _() {}
+func ( /* comment1 */ T /* comment2 */) _() {}
func _() { /* one-line functions with comments are formatted as multi-line functions */
}
@@ -425,7 +426,7 @@ func _() {
}
func _() {
- _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
}
// Test cases from issue 1542:
@@ -448,8 +449,9 @@ func _() {
_ = a
}
-// Comments immediately adjacent to punctuation (for which the go/printer
-// may only have estimated position information) must remain after the punctuation.
+// Comments immediately adjacent to punctuation followed by a newline
+// remain after the punctuation (looks better and permits alignment of
+// comments).
func _() {
_ = T{
1, // comment after comma
@@ -479,6 +481,35 @@ func _() {
}
}
+// If there is no newline following punctuation, commas move before the punctuation.
+// This way, commas interspersed in lists stay with the respective expression.
+func f(x /* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
+ f(x /* comment */, y)
+ f(x, /* comment */
+ y)
+ f(
+ x, /* comment */
+ )
+}
+
+func g(
+ x int, /* comment */
+) {
+}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+func _() {
+ for a /* comment */, b := range x {
+ }
+}
+
// Print line directives correctly.
// The following is a legal line directive.
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index 55f6b61f21f..c0f8cca3a92 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -411,6 +411,7 @@ func _() {
// Some interesting interspersed comments.
+// See below for more common cases.
func _(/* this */x/* is *//* an */ int) {
}
@@ -453,8 +454,9 @@ func _() {
_ = a
}
-// Comments immediately adjacent to punctuation (for which the go/printer
-// may only have estimated position information) must remain after the punctuation.
+// Comments immediately adjacent to punctuation followed by a newline
+// remain after the punctuation (looks better and permits alignment of
+// comments).
func _() {
_ = T{
1, // comment after comma
@@ -486,6 +488,31 @@ func _() {
}
}
+// If there is no newline following punctuation, commas move before the punctuation.
+// This way, commas interspersed in lists stay with the respective expression.
+func f(x/* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
+ f(x /* comment */, y)
+ f(x /* comment */,
+ y)
+ f(
+ x /* comment */,
+ )
+}
+
+func g(
+ x int /* comment */,
+) {}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+type _ struct { a, b /* comment */, c int }
+
+func _() {
+ for a /* comment */, b := range x {
+ }
+}
// Print line directives correctly.
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index d0cf24ad6f6..95fdd95ffbb 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -545,7 +545,7 @@ func _() {
// handle multiline argument list correctly
_ = new(T).
foo(
- 1).
+ 1).
foo(2)
_ = new(T).foo(
@@ -587,12 +587,12 @@ func _() {
_ = new(T).
Field.
Array[3+
- 4].
+ 4].
Table["foo"].
Blob.(*Type).
Slices[1:4].
Method(1, 2,
- 3).
+ 3).
Thingy
_ = a.b.c
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index d7819a3baad..3442ba9b950 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -545,7 +545,7 @@ func _() {
// handle multiline argument list correctly
_ = new(T).
foo(
- 1).
+ 1).
foo(2)
_ = new(T).foo(
@@ -587,12 +587,12 @@ func _() {
_ = new(T).
Field.
Array[3+
- 4].
+ 4].
Table["foo"].
Blob.(*Type).
Slices[1:4].
Method(1, 2,
- 3).
+ 3).
Thingy
_ = a.b.c
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index 458e1f9f37a..2395363b0ec 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -2,21 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package scanner implements a scanner for Go source text. Takes a []byte as
-// source which can then be tokenized through repeated calls to the Scan
-// function. Typical use:
-//
-// var s scanner.Scanner
-// fset := token.NewFileSet() // position information is relative to fset
-// file := fset.AddFile(filename, fset.Base(), len(src)) // register file
-// s.Init(file, src, nil /* no error handler */, 0)
-// for {
-// pos, tok, lit := s.Scan()
-// if tok == token.EOF {
-// break
-// }
-// // do something here with pos, tok, and lit
-// }
+// Package scanner implements a scanner for Go source text.
+// It takes a []byte as source which can then be tokenized
+// through repeated calls to the Scan method.
//
package scanner
diff --git a/libgo/go/html/template/clone.go b/libgo/go/html/template/clone.go
deleted file mode 100644
index d0d8ea46733..00000000000
--- a/libgo/go/html/template/clone.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2011 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 template
-
-import (
- "text/template/parse"
-)
-
-// clone clones a template Node.
-func clone(n parse.Node) parse.Node {
- switch t := n.(type) {
- case *parse.ActionNode:
- return cloneAction(t)
- case *parse.IfNode:
- b := new(parse.IfNode)
- copyBranch(&b.BranchNode, &t.BranchNode)
- return b
- case *parse.ListNode:
- return cloneList(t)
- case *parse.RangeNode:
- b := new(parse.RangeNode)
- copyBranch(&b.BranchNode, &t.BranchNode)
- return b
- case *parse.TemplateNode:
- return cloneTemplate(t)
- case *parse.TextNode:
- return cloneText(t)
- case *parse.WithNode:
- b := new(parse.WithNode)
- copyBranch(&b.BranchNode, &t.BranchNode)
- return b
- }
- panic("cloning " + n.String() + " is unimplemented")
-}
-
-// cloneAction returns a deep clone of n.
-func cloneAction(n *parse.ActionNode) *parse.ActionNode {
- // We use keyless fields because they won't compile if a field is added.
- return &parse.ActionNode{n.NodeType, n.Line, clonePipe(n.Pipe)}
-}
-
-// cloneList returns a deep clone of n.
-func cloneList(n *parse.ListNode) *parse.ListNode {
- if n == nil {
- return nil
- }
- // We use keyless fields because they won't compile if a field is added.
- c := parse.ListNode{n.NodeType, make([]parse.Node, len(n.Nodes))}
- for i, child := range n.Nodes {
- c.Nodes[i] = clone(child)
- }
- return &c
-}
-
-// clonePipe returns a shallow clone of n.
-// The escaper does not modify pipe descendants in place so there's no need to
-// clone deeply.
-func clonePipe(n *parse.PipeNode) *parse.PipeNode {
- if n == nil {
- return nil
- }
- // We use keyless fields because they won't compile if a field is added.
- return &parse.PipeNode{n.NodeType, n.Line, n.Decl, n.Cmds}
-}
-
-// cloneTemplate returns a deep clone of n.
-func cloneTemplate(n *parse.TemplateNode) *parse.TemplateNode {
- // We use keyless fields because they won't compile if a field is added.
- return &parse.TemplateNode{n.NodeType, n.Line, n.Name, clonePipe(n.Pipe)}
-}
-
-// cloneText clones the given node sharing its []byte.
-func cloneText(n *parse.TextNode) *parse.TextNode {
- // We use keyless fields because they won't compile if a field is added.
- return &parse.TextNode{n.NodeType, n.Text}
-}
-
-// copyBranch clones src into dst.
-func copyBranch(dst, src *parse.BranchNode) {
- // We use keyless fields because they won't compile if a field is added.
- *dst = parse.BranchNode{
- src.NodeType,
- src.Line,
- clonePipe(src.Pipe),
- cloneList(src.List),
- cloneList(src.ElseList),
- }
-}
diff --git a/libgo/go/html/template/clone_test.go b/libgo/go/html/template/clone_test.go
index 39788173b99..c612775d4f0 100644
--- a/libgo/go/html/template/clone_test.go
+++ b/libgo/go/html/template/clone_test.go
@@ -7,86 +7,109 @@ package template
import (
"bytes"
"testing"
+ "text/template/parse"
)
+func TestAddParseTree(t *testing.T) {
+ root := Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`))
+ tree, err := parse.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ added := Must(root.AddParseTree("b", tree["b"]))
+ b := new(bytes.Buffer)
+ err = added.ExecuteTemplate(b, "a", "1>0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` 1&gt;0 <a href=" 1%3e0 "></a>`; got != want {
+ t.Errorf("got %q want %q", got, want)
+ }
+}
+
func TestClone(t *testing.T) {
- tests := []struct {
- input, want, wantClone string
- }{
- {
- `Hello, {{if true}}{{"<World>"}}{{end}}!`,
- "Hello, <World>!",
- "Hello, &lt;World&gt;!",
- },
- {
- `Hello, {{if false}}{{.X}}{{else}}{{"<World>"}}{{end}}!`,
- "Hello, <World>!",
- "Hello, &lt;World&gt;!",
- },
- {
- `Hello, {{with "<World>"}}{{.}}{{end}}!`,
- "Hello, <World>!",
- "Hello, &lt;World&gt;!",
- },
- {
- `{{range .}}<p>{{.}}</p>{{end}}`,
- "<p>foo</p><p><bar></p><p>baz</p>",
- "<p>foo</p><p>&lt;bar&gt;</p><p>baz</p>",
- },
- {
- `Hello, {{"<World>" | html}}!`,
- "Hello, &lt;World&gt;!",
- "Hello, &lt;World&gt;!",
- },
- {
- `Hello{{if 1}}, World{{else}}{{template "d"}}{{end}}!`,
- "Hello, World!",
- "Hello, World!",
- },
+ // The {{.}} will be executed with data "<i>*/" in different contexts.
+ // In the t0 template, it will be in a text context.
+ // In the t1 template, it will be in a URL context.
+ // In the t2 template, it will be in a JavaScript context.
+ // In the t3 template, it will be in a CSS context.
+ const tmpl = `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}`
+ b := new(bytes.Buffer)
+
+ // Create an incomplete template t0.
+ t0 := Must(New("t0").Parse(tmpl))
+
+ // Clone t0 as t1.
+ t1 := Must(t0.Clone())
+ Must(t1.Parse(`{{define "lhs"}} <a href=" {{end}}`))
+ Must(t1.Parse(`{{define "rhs"}} "></a> {{end}}`))
+
+ // Execute t1.
+ b.Reset()
+ if err := t1.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <a href=" %3ci%3e*/ "></a> `; got != want {
+ t.Errorf("t1: got %q want %q", got, want)
+ }
+
+ // Clone t0 as t2.
+ t2 := Must(t0.Clone())
+ Must(t2.Parse(`{{define "lhs"}} <p onclick="javascript: {{end}}`))
+ Must(t2.Parse(`{{define "rhs"}} "></p> {{end}}`))
+
+ // Execute t2.
+ b.Reset()
+ if err := t2.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <p onclick="javascript: &#34;\u003ci\u003e*/&#34; "></p> `; got != want {
+ t.Errorf("t2: got %q want %q", got, want)
}
- for _, test := range tests {
- s, err := New("s").Parse(test.input)
- if err != nil {
- t.Errorf("input=%q: unexpected parse error %v", test.input, err)
- }
-
- d, _ := New("d").Parse(test.input)
- // Hack: just replace the root of the tree.
- d.text.Root = cloneList(s.text.Root)
-
- if want, got := s.text.Root.String(), d.text.Root.String(); want != got {
- t.Errorf("want %q, got %q", want, got)
- }
-
- err = escapeTemplates(d, "d")
- if err != nil {
- t.Errorf("%q: failed to escape: %s", test.input, err)
- continue
- }
-
- if want, got := "s", s.Name(); want != got {
- t.Errorf("want %q, got %q", want, got)
- continue
- }
- if want, got := "d", d.Name(); want != got {
- t.Errorf("want %q, got %q", want, got)
- continue
- }
-
- data := []string{"foo", "<bar>", "baz"}
-
- var b bytes.Buffer
- d.Execute(&b, data)
- if got := b.String(); got != test.wantClone {
- t.Errorf("input=%q: want %q, got %q", test.input, test.wantClone, got)
- }
-
- // Make sure escaping d did not affect s.
- b.Reset()
- s.text.Execute(&b, data)
- if got := b.String(); got != test.want {
- t.Errorf("input=%q: want %q, got %q", test.input, test.want, got)
- }
+ // Clone t0 as t3, but do not execute t3 yet.
+ t3 := Must(t0.Clone())
+ Must(t3.Parse(`{{define "lhs"}} <style> {{end}}`))
+ Must(t3.Parse(`{{define "rhs"}} </style> {{end}}`))
+
+ // Complete t0.
+ Must(t0.Parse(`{{define "lhs"}} ( {{end}}`))
+ Must(t0.Parse(`{{define "rhs"}} ) {{end}}`))
+
+ // Clone t0 as t4. Redefining the "lhs" template should fail.
+ t4 := Must(t0.Clone())
+ if _, err := t4.Parse(`{{define "lhs"}} FAIL {{end}}`); err == nil {
+ t.Error(`redefine "lhs": got nil err want non-nil`)
+ }
+
+ // Execute t0.
+ b.Reset()
+ if err := t0.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` ( &lt;i&gt;*/ ) `; got != want {
+ t.Errorf("t0: got %q want %q", got, want)
+ }
+
+ // Clone t0. This should fail, as t0 has already executed.
+ if _, err := t0.Clone(); err == nil {
+ t.Error(`t0.Clone(): got nil err want non-nil`)
+ }
+
+ // Similarly, cloning sub-templates should fail.
+ if _, err := t0.Lookup("a").Clone(); err == nil {
+ t.Error(`t0.Lookup("a").Clone(): got nil err want non-nil`)
+ }
+ if _, err := t0.Lookup("lhs").Clone(); err == nil {
+ t.Error(`t0.Lookup("lhs").Clone(): got nil err want non-nil`)
+ }
+
+ // Execute t3.
+ b.Reset()
+ if err := t3.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <style> ZgotmplZ </style> `; got != want {
+ t.Errorf("t3: got %q want %q", got, want)
}
}
diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go
index 4de7ccde912..539664f9729 100644
--- a/libgo/go/html/template/content.go
+++ b/libgo/go/html/template/content.go
@@ -85,6 +85,22 @@ func indirect(a interface{}) interface{} {
return v.Interface()
}
+var (
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+// indirectToStringerOrError returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
+// or error,
+func indirectToStringerOrError(a interface{}) interface{} {
+ v := reflect.ValueOf(a)
+ for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
// stringify converts its arguments to a string and the type of the content.
// All pointers are dereferenced, as in the text/template package.
func stringify(args ...interface{}) (string, contentType) {
@@ -107,7 +123,7 @@ func stringify(args ...interface{}) (string, contentType) {
}
}
for i, arg := range args {
- args[i] = indirect(arg)
+ args[i] = indirectToStringerOrError(arg)
}
return fmt.Sprint(args...), contentTypePlain
}
diff --git a/libgo/go/html/template/content_test.go b/libgo/go/html/template/content_test.go
index c96a521a59c..3c32e5e89cf 100644
--- a/libgo/go/html/template/content_test.go
+++ b/libgo/go/html/template/content_test.go
@@ -6,6 +6,7 @@ package template
import (
"bytes"
+ "fmt"
"strings"
"testing"
)
@@ -219,3 +220,42 @@ func TestTypedContent(t *testing.T) {
}
}
}
+
+// Test that we print using the String method. Was issue 3073.
+type stringer struct {
+ v int
+}
+
+func (s *stringer) String() string {
+ return fmt.Sprintf("string=%d", s.v)
+}
+
+type errorer struct {
+ v int
+}
+
+func (s *errorer) Error() string {
+ return fmt.Sprintf("error=%d", s.v)
+}
+
+func TestStringer(t *testing.T) {
+ s := &stringer{3}
+ b := new(bytes.Buffer)
+ tmpl := Must(New("x").Parse("{{.}}"))
+ if err := tmpl.Execute(b, s); err != nil {
+ t.Fatal(err)
+ }
+ var expect = "string=3"
+ if b.String() != expect {
+ t.Errorf("expected %q got %q", expect, b.String())
+ }
+ e := &errorer{7}
+ b.Reset()
+ if err := tmpl.Execute(b, e); err != nil {
+ t.Fatal(err)
+ }
+ expect = "error=7"
+ if b.String() != expect {
+ t.Errorf("expected %q got %q", expect, b.String())
+ }
+}
diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go
index 6fe507abea4..7f60f3b9680 100644
--- a/libgo/go/html/template/doc.go
+++ b/libgo/go/html/template/doc.go
@@ -17,11 +17,11 @@ Introduction
This package wraps package text/template so you can share its template API
to parse and execute HTML templates safely.
- set, err := new(template.Set).Parse(...)
+ tmpl, err := template.New("name").Parse(...)
// Error checking elided
- err = set.Execute(out, "Foo", data)
+ err = tmpl.Execute(out, "Foo", data)
-If successful, set will now be injection-safe. Otherwise, err is an error
+If successful, tmpl will now be injection-safe. Otherwise, err is an error
defined in the docs for ErrorCode.
HTML templates treat data values as plain text which should be encoded so they
@@ -172,18 +172,18 @@ This package assumes that template authors are trusted, that Execute's data
parameter is not, and seeks to preserve the properties below in the face
of untrusted data:
-Structure Preservation Property
+Structure Preservation Property:
"... when a template author writes an HTML tag in a safe templating language,
the browser will interpret the corresponding portion of the output as a tag
regardless of the values of untrusted data, and similarly for other structures
such as attribute boundaries and JS and CSS string boundaries."
-Code Effect Property
+Code Effect Property:
"... only code specified by the template author should run as a result of
injecting the template output into a page and all code specified by the
template author should run as a result of the same."
-Least Surprise Property
+Least Surprise Property:
"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
knows that contextual autoescaping happens should be able to look at a {{.}}
and correctly infer what sanitization happens."
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index c6f723ae4a4..02fa3eaad6b 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -46,30 +46,30 @@ func escapeTemplates(tmpl *Template, names ...string) error {
// funcMap maps command names to functions that render their inputs safe.
var funcMap = template.FuncMap{
- "exp_template_html_attrescaper": attrEscaper,
- "exp_template_html_commentescaper": commentEscaper,
- "exp_template_html_cssescaper": cssEscaper,
- "exp_template_html_cssvaluefilter": cssValueFilter,
- "exp_template_html_htmlnamefilter": htmlNameFilter,
- "exp_template_html_htmlescaper": htmlEscaper,
- "exp_template_html_jsregexpescaper": jsRegexpEscaper,
- "exp_template_html_jsstrescaper": jsStrEscaper,
- "exp_template_html_jsvalescaper": jsValEscaper,
- "exp_template_html_nospaceescaper": htmlNospaceEscaper,
- "exp_template_html_rcdataescaper": rcdataEscaper,
- "exp_template_html_urlescaper": urlEscaper,
- "exp_template_html_urlfilter": urlFilter,
- "exp_template_html_urlnormalizer": urlNormalizer,
+ "html_template_attrescaper": attrEscaper,
+ "html_template_commentescaper": commentEscaper,
+ "html_template_cssescaper": cssEscaper,
+ "html_template_cssvaluefilter": cssValueFilter,
+ "html_template_htmlnamefilter": htmlNameFilter,
+ "html_template_htmlescaper": htmlEscaper,
+ "html_template_jsregexpescaper": jsRegexpEscaper,
+ "html_template_jsstrescaper": jsStrEscaper,
+ "html_template_jsvalescaper": jsValEscaper,
+ "html_template_nospaceescaper": htmlNospaceEscaper,
+ "html_template_rcdataescaper": rcdataEscaper,
+ "html_template_urlescaper": urlEscaper,
+ "html_template_urlfilter": urlFilter,
+ "html_template_urlnormalizer": urlNormalizer,
}
// equivEscapers matches contextual escapers to equivalent template builtins.
var equivEscapers = map[string]string{
- "exp_template_html_attrescaper": "html",
- "exp_template_html_htmlescaper": "html",
- "exp_template_html_nospaceescaper": "html",
- "exp_template_html_rcdataescaper": "html",
- "exp_template_html_urlescaper": "urlquery",
- "exp_template_html_urlnormalizer": "urlquery",
+ "html_template_attrescaper": "html",
+ "html_template_htmlescaper": "html",
+ "html_template_nospaceescaper": "html",
+ "html_template_rcdataescaper": "html",
+ "html_template_urlescaper": "urlquery",
+ "html_template_urlnormalizer": "urlquery",
}
// escaper collects type inferences about templates and changes needed to make
@@ -147,17 +147,17 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:
switch c.urlPart {
case urlPartNone:
- s = append(s, "exp_template_html_urlfilter")
+ s = append(s, "html_template_urlfilter")
fallthrough
case urlPartPreQuery:
switch c.state {
case stateCSSDqStr, stateCSSSqStr:
- s = append(s, "exp_template_html_cssescaper")
+ s = append(s, "html_template_cssescaper")
default:
- s = append(s, "exp_template_html_urlnormalizer")
+ s = append(s, "html_template_urlnormalizer")
}
case urlPartQueryOrFrag:
- s = append(s, "exp_template_html_urlescaper")
+ s = append(s, "html_template_urlescaper")
case urlPartUnknown:
return context{
state: stateError,
@@ -167,27 +167,27 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
panic(c.urlPart.String())
}
case stateJS:
- s = append(s, "exp_template_html_jsvalescaper")
+ s = append(s, "html_template_jsvalescaper")
// A slash after a value starts a div operator.
c.jsCtx = jsCtxDivOp
case stateJSDqStr, stateJSSqStr:
- s = append(s, "exp_template_html_jsstrescaper")
+ s = append(s, "html_template_jsstrescaper")
case stateJSRegexp:
- s = append(s, "exp_template_html_jsregexpescaper")
+ s = append(s, "html_template_jsregexpescaper")
case stateCSS:
- s = append(s, "exp_template_html_cssvaluefilter")
+ s = append(s, "html_template_cssvaluefilter")
case stateText:
- s = append(s, "exp_template_html_htmlescaper")
+ s = append(s, "html_template_htmlescaper")
case stateRCDATA:
- s = append(s, "exp_template_html_rcdataescaper")
+ s = append(s, "html_template_rcdataescaper")
case stateAttr:
// Handled below in delim check.
case stateAttrName, stateTag:
c.state = stateAttrName
- s = append(s, "exp_template_html_htmlnamefilter")
+ s = append(s, "html_template_htmlnamefilter")
default:
if isComment(c.state) {
- s = append(s, "exp_template_html_commentescaper")
+ s = append(s, "html_template_commentescaper")
} else {
panic("unexpected state " + c.state.String())
}
@@ -196,9 +196,9 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case delimNone:
// No extra-escaping needed for raw text content.
case delimSpaceOrTagEnd:
- s = append(s, "exp_template_html_nospaceescaper")
+ s = append(s, "html_template_nospaceescaper")
default:
- s = append(s, "exp_template_html_attrescaper")
+ s = append(s, "html_template_attrescaper")
}
e.editActionNode(n, s)
return c
@@ -260,22 +260,22 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
// for all x.
var redundantFuncs = map[string]map[string]bool{
- "exp_template_html_commentescaper": {
- "exp_template_html_attrescaper": true,
- "exp_template_html_nospaceescaper": true,
- "exp_template_html_htmlescaper": true,
+ "html_template_commentescaper": {
+ "html_template_attrescaper": true,
+ "html_template_nospaceescaper": true,
+ "html_template_htmlescaper": true,
},
- "exp_template_html_cssescaper": {
- "exp_template_html_attrescaper": true,
+ "html_template_cssescaper": {
+ "html_template_attrescaper": true,
},
- "exp_template_html_jsregexpescaper": {
- "exp_template_html_attrescaper": true,
+ "html_template_jsregexpescaper": {
+ "html_template_attrescaper": true,
},
- "exp_template_html_jsstrescaper": {
- "exp_template_html_attrescaper": true,
+ "html_template_jsstrescaper": {
+ "html_template_attrescaper": true,
},
- "exp_template_html_urlescaper": {
- "exp_template_html_urlnormalizer": true,
+ "html_template_urlescaper": {
+ "html_template_urlnormalizer": true,
},
}
@@ -505,7 +505,7 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
dt := e.template(dname)
if dt == nil {
dt = template.New(dname)
- dt.Tree = &parse.Tree{Name: dname, Root: cloneList(t.Root)}
+ dt.Tree = &parse.Tree{Name: dname, Root: t.Root.CopyList()}
e.derived[dname] = dt
}
t = dt
diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go
index 9ffe41413a8..b0bae7a54fb 100644
--- a/libgo/go/html/template/template.go
+++ b/libgo/go/html/template/template.go
@@ -50,7 +50,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
// ExecuteTemplate applies the template associated with t that has the given
// name to the specified data object and writes the output to wr.
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
- tmpl, err := t.lookupAndEscapeTemplate(wr, name)
+ tmpl, err := t.lookupAndEscapeTemplate(name)
if err != nil {
return err
}
@@ -60,7 +60,7 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// lookupAndEscapeTemplate guarantees that the template with the given name
// is escaped, or returns an error if it cannot be. It returns the named
// template.
-func (t *Template) lookupAndEscapeTemplate(wr io.Writer, name string) (tmpl *Template, err error) {
+func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
tmpl = t.set[name]
@@ -106,14 +106,71 @@ func (t *Template) Parse(src string) (*Template, error) {
return t, nil
}
-// AddParseTree is unimplemented.
-func (t *Template) AddParseTree(name string, tree *parse.Tree) error {
- return fmt.Errorf("html/template: AddParseTree unimplemented")
+// AddParseTree creates a new template with the name and parse tree
+// and associates it with t.
+//
+// It returns an error if t has already been executed.
+func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.escaped {
+ return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name())
+ }
+ text, err := t.text.AddParseTree(name, tree)
+ if err != nil {
+ return nil, err
+ }
+ ret := &Template{
+ false,
+ text,
+ t.nameSpace,
+ }
+ t.set[name] = ret
+ return ret, nil
}
-// Clone is unimplemented.
-func (t *Template) Clone(name string) error {
- return fmt.Errorf("html/template: Clone unimplemented")
+// Clone returns a duplicate of the template, including all associated
+// templates. The actual representation is not copied, but the name space of
+// associated templates is, so further calls to Parse in the copy will add
+// templates to the copy but not to the original. Clone can be used to prepare
+// common templates and use them with variant definitions for other templates
+// by adding the variants after the clone is made.
+//
+// It returns an error if t has already been executed.
+func (t *Template) Clone() (*Template, error) {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.escaped {
+ return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
+ }
+ textClone, err := t.text.Clone()
+ if err != nil {
+ return nil, err
+ }
+ ret := &Template{
+ false,
+ textClone,
+ &nameSpace{
+ set: make(map[string]*Template),
+ },
+ }
+ for _, x := range textClone.Templates() {
+ name := x.Name()
+ src := t.set[name]
+ if src == nil || src.escaped {
+ return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
+ }
+ x.Tree = &parse.Tree{
+ Name: x.Tree.Name,
+ Root: x.Tree.Root.CopyList(),
+ }
+ ret.set[name] = &Template{
+ false,
+ x,
+ ret.nameSpace,
+ }
+ }
+ return ret, nil
}
// New allocates a new HTML template with the given name.
diff --git a/libgo/go/image/decode_example_test.go b/libgo/go/image/decode_example_test.go
new file mode 100644
index 00000000000..aa5a841c0a5
--- /dev/null
+++ b/libgo/go/image/decode_example_test.go
@@ -0,0 +1,79 @@
+// Copyright 2012 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.
+
+// This example demonstrates decoding a JPEG image and examining its pixels.
+package image_test
+
+import (
+ "fmt"
+ "image"
+ "log"
+ "os"
+
+ // Package image/jpeg is not used explicitly in the code below,
+ // but is imported for its initialization side-effect, which allows
+ // image.Decode to understand JPEG formatted images. Uncomment these
+ // two lines to also understand GIF and PNG images:
+ // _ "image/gif"
+ // _ "image/png"
+ _ "image/jpeg"
+)
+
+func Example() {
+ // Open the file.
+ file, err := os.Open("testdata/video-001.jpeg")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer file.Close()
+
+ // Decode the image.
+ m, _, err := image.Decode(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ bounds := m.Bounds()
+
+ // Calculate a 16-bin histogram for m's red, green, blue and alpha components.
+ //
+ // An image's bounds do not necessarily start at (0, 0), so the two loops start
+ // at bounds.Min.Y and bounds.Min.X. Looping over Y first and X second is more
+ // likely to result in better memory access patterns than X first and Y second.
+ var histogram [16][4]int
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
+ // A color's RGBA method returns values in the range [0, 65535].
+ // Shifting by 12 reduces this to the range [0, 15].
+ histogram[r>>12][0]++
+ histogram[g>>12][1]++
+ histogram[b>>12][2]++
+ histogram[a>>12][3]++
+ }
+ }
+
+ // Print the results.
+ fmt.Printf("%-14s %6s %6s %6s %6s\n", "bin", "red", "green", "blue", "alpha")
+ for i, x := range histogram {
+ fmt.Printf("0x%04x-0x%04x: %6d %6d %6d %6d\n", i<<12, (i+1)<<12-1, x[0], x[1], x[2], x[3])
+ }
+ // Output:
+ // bin red green blue alpha
+ // 0x0000-0x0fff: 471 819 7596 0
+ // 0x1000-0x1fff: 576 2892 726 0
+ // 0x2000-0x2fff: 1038 2330 943 0
+ // 0x3000-0x3fff: 883 2321 1014 0
+ // 0x4000-0x4fff: 501 1295 525 0
+ // 0x5000-0x5fff: 302 962 242 0
+ // 0x6000-0x6fff: 219 358 150 0
+ // 0x7000-0x7fff: 352 281 192 0
+ // 0x8000-0x8fff: 3688 216 246 0
+ // 0x9000-0x9fff: 2277 237 283 0
+ // 0xa000-0xafff: 971 254 357 0
+ // 0xb000-0xbfff: 317 306 429 0
+ // 0xc000-0xcfff: 203 402 401 0
+ // 0xd000-0xdfff: 256 394 241 0
+ // 0xe000-0xefff: 378 343 173 0
+ // 0xf000-0xffff: 3018 2040 1932 15450
+}
diff --git a/libgo/go/image/ycbcr_test.go b/libgo/go/image/ycbcr_test.go
index eb8b1950bfe..b2373f79ba3 100644
--- a/libgo/go/image/ycbcr_test.go
+++ b/libgo/go/image/ycbcr_test.go
@@ -50,6 +50,9 @@ func TestYCbCr(t *testing.T) {
testYCbCr(t, r, subsampleRatio, delta)
}
}
+ if testing.Short() {
+ break
+ }
}
}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
index 645eed6abb8..42d2e675869 100644
--- a/libgo/go/io/ioutil/tempfile.go
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -49,7 +49,7 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextSuffix())
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
- if pe, ok := err.(*os.PathError); ok && pe.Err == os.EEXIST {
+ if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
@@ -76,7 +76,7 @@ func TempDir(dir, prefix string) (name string, err error) {
for i := 0; i < 10000; i++ {
try := filepath.Join(dir, prefix+nextSuffix())
err = os.Mkdir(try, 0700)
- if pe, ok := err.(*os.PathError); ok && pe.Err == os.EEXIST {
+ if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go
index 3eb5353e9a9..f53310cb0a1 100644
--- a/libgo/go/log/syslog/syslog.go
+++ b/libgo/go/log/syslog/syslog.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !windows,!plan9
+
// Package syslog provides a simple interface to the system log service. It
// can send messages to the syslog daemon using UNIX domain sockets, UDP, or
// TCP connections.
diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go
index 7f509b3666e..0fd6239059a 100644
--- a/libgo/go/log/syslog/syslog_test.go
+++ b/libgo/go/log/syslog/syslog_test.go
@@ -1,6 +1,9 @@
// 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.
+
+// +build !windows,!plan9
+
package syslog
import (
diff --git a/libgo/go/log/syslog/syslog_unix.go b/libgo/go/log/syslog/syslog_unix.go
index b1c929ad2fe..46a164dd577 100644
--- a/libgo/go/log/syslog/syslog_unix.go
+++ b/libgo/go/log/syslog/syslog_unix.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !windows,!plan9
+
package syslog
import (
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index 25e39273c0c..7f3f76dc36f 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -512,6 +512,9 @@ func TestStringPowers(t *testing.T) {
t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
}
}
+ if b >= 3 && testing.Short() {
+ break
+ }
}
}
diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go
index 89552192030..94f84a85fbe 100644
--- a/libgo/go/math/rand/rand.go
+++ b/libgo/go/math/rand/rand.go
@@ -49,9 +49,10 @@ func (r *Rand) Int() int {
}
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
- return 0
+ panic("invalid argument to Int63n")
}
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := r.Int63()
@@ -62,9 +63,10 @@ func (r *Rand) Int63n(n int64) int64 {
}
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
- return 0
+ panic("invalid argument to Int31n")
}
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := r.Int31()
@@ -75,7 +77,11 @@ func (r *Rand) Int31n(n int32) int32 {
}
// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Intn(n int) int {
+ if n <= 0 {
+ panic("invalid argument to Intn")
+ }
if n <= 1<<31-1 {
return int(r.Int31n(int32(n)))
}
@@ -125,12 +131,15 @@ func Int31() int32 { return globalRand.Int31() }
func Int() int { return globalRand.Int() }
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand.Int63n(n) }
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand.Int31n(n) }
// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Intn(n int) int { return globalRand.Intn(n) }
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go
index 0ba8f98c496..bbd44e3f8b1 100644
--- a/libgo/go/math/rand/rand_test.go
+++ b/libgo/go/math/rand/rand_test.go
@@ -141,6 +141,9 @@ func TestNonStandardNormalValues(t *testing.T) {
for m := 0.5; m < mmax; m *= 2 {
for _, seed := range testSeeds {
testNormalDistribution(t, numTestSamples, m, sd, seed)
+ if testing.Short() {
+ break
+ }
}
}
}
@@ -191,6 +194,9 @@ func TestNonStandardExponentialValues(t *testing.T) {
for rate := 0.05; rate < 10; rate *= 2 {
for _, seed := range testSeeds {
testExponentialDistribution(t, numTestSamples, rate, seed)
+ if testing.Short() {
+ break
+ }
}
}
}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index 81750a3d739..14356da4ce3 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -14,7 +14,7 @@ import (
)
// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
-var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
// fd is already connected to the destination, port 80.
// Run an HTTP request to fetch the appropriate page.
@@ -130,7 +130,7 @@ func TestDialGoogleIPv6(t *testing.T) {
return
}
// Only run tcp6 if the kernel will take it.
- if !*ipv6 || !supportsIPv6 {
+ if !*testIPv6 || !supportsIPv6 {
return
}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index bf0a387775d..ae1bf2614a2 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -252,7 +252,9 @@ func (s *pollServer) Run() {
} else {
netfd := s.LookupFD(fd, mode)
if netfd == nil {
- print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
+ // This can happen because the WaitFD runs without
+ // holding s's lock, so there might be a pending wakeup
+ // for an fd that has been evicted. No harm done.
continue
}
s.WakeFD(netfd, mode, nil)
@@ -506,7 +508,7 @@ func (fd *netFD) Write(p []byte) (int, error) {
}
defer fd.decref()
if fd.sysfile == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
var err error
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index efd846e5d8c..45f5c2d882f 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -335,7 +335,7 @@ func (fd *netFD) Close() error {
func (fd *netFD) shutdown(how int) error {
if fd == nil || fd.sysfd == syscall.InvalidHandle {
- return os.EINVAL
+ return syscall.EINVAL
}
err := syscall.Shutdown(fd.sysfd, how)
if err != nil {
@@ -369,7 +369,7 @@ func (o *readOp) Name() string {
func (fd *netFD) Read(buf []byte) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
fd.rio.Lock()
defer fd.rio.Unlock()
@@ -378,7 +378,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
}
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
var o readOp
o.Init(fd, buf, 'r')
@@ -408,7 +408,7 @@ func (o *readFromOp) Name() string {
func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
if fd == nil {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil, nil
@@ -447,7 +447,7 @@ func (o *writeOp) Name() string {
func (fd *netFD) Write(buf []byte) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
fd.wio.Lock()
defer fd.wio.Unlock()
@@ -478,7 +478,7 @@ func (o *writeToOp) Name() string {
func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil
@@ -490,7 +490,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
}
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
var o writeToOp
o.Init(fd, buf, 'w')
@@ -578,10 +578,12 @@ func (fd *netFD) dup() (*os.File, error) {
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
}
+var errNoSupport = errors.New("address family not supported")
+
func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
- return 0, 0, 0, nil, os.EAFNOSUPPORT
+ return 0, 0, 0, nil, errNoSupport
}
func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
- return 0, 0, os.EAFNOSUPPORT
+ return 0, 0, errNoSupport
}
diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go
index f9546dc930d..c95d16d64e7 100644
--- a/libgo/go/net/file.go
+++ b/libgo/go/net/file.go
@@ -28,7 +28,7 @@ func newFileFD(f *os.File) (*netFD, error) {
switch sa.(type) {
default:
closesocket(fd)
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
case *syscall.SockaddrInet4:
family = syscall.AF_INET
if proto == syscall.SOCK_DGRAM {
@@ -84,7 +84,7 @@ func FileConn(f *os.File) (c Conn, err error) {
return newIPConn(fd), nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
// FileListener returns a copy of the network listener corresponding
@@ -103,7 +103,7 @@ func FileListener(f *os.File) (l Listener, err error) {
return &UnixListener{fd, laddr.Name}, nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
// FilePacketConn returns a copy of the packet network connection
@@ -122,5 +122,5 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
return newUnixConn(fd), nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go
index 06d7cc89846..04f7ee0401b 100644
--- a/libgo/go/net/file_plan9.go
+++ b/libgo/go/net/file_plan9.go
@@ -6,6 +6,7 @@ package net
import (
"os"
+ "syscall"
)
// FileConn returns a copy of the network connection corresponding to
@@ -13,7 +14,7 @@ import (
// finished. Closing c does not affect f, and closing f does not
// affect c.
func FileConn(f *os.File) (c Conn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// FileListener returns a copy of the network listener corresponding
@@ -21,7 +22,7 @@ func FileConn(f *os.File) (c Conn, err error) {
// when finished. Closing c does not affect l, and closing l does not
// affect c.
func FileListener(f *os.File) (l Listener, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// FilePacketConn returns a copy of the packet network connection
@@ -29,5 +30,5 @@ func FileListener(f *os.File) (l Listener, err error) {
// responsibility to close f when finished. Closing c does not affect
// f, and closing f does not affect c.
func FilePacketConn(f *os.File) (c PacketConn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index 1bd00541c6d..064e7e43282 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -34,7 +34,7 @@ var hosttests = []hostTest{
func TestLookupStaticHost(t *testing.T) {
p := hostsPath
- hostsPath = "hosts_testdata"
+ hostsPath = "testdata/hosts"
for i := 0; i < len(hosttests); i++ {
tt := hosttests[i]
ips := lookupStaticHost(tt.host)
diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go
index 712350dfcef..1e9186a0581 100644
--- a/libgo/go/net/http/cookie_test.go
+++ b/libgo/go/net/http/cookie_test.go
@@ -128,6 +128,34 @@ var readSetCookiesTests = []struct {
Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
}},
},
+ {
+ Header{"Set-Cookie": {".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly"}},
+ []*Cookie{{
+ Name: ".ASPXAUTH",
+ Value: "7E3AA",
+ Path: "/",
+ Expires: time.Date(2012, 3, 7, 14, 25, 6, 0, time.UTC),
+ RawExpires: "Wed, 07-Mar-2012 14:25:06 GMT",
+ HttpOnly: true,
+ Raw: ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ }},
+ },
+ {
+ Header{"Set-Cookie": {"ASP.NET_SessionId=foo; path=/; HttpOnly"}},
+ []*Cookie{{
+ Name: "ASP.NET_SessionId",
+ Value: "foo",
+ Path: "/",
+ HttpOnly: true,
+ Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly",
+ }},
+ },
+
+ // TODO(bradfitz): users have reported seeing this in the
+ // wild, but do browsers handle it? RFC 6265 just says "don't
+ // do that" (section 3) and then never mentions header folding
+ // again.
+ // Header{"Set-Cookie": {"ASP.NET_SessionId=foo; path=/; HttpOnly, .ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly"}},
}
func toJSON(v interface{}) string {
diff --git a/libgo/go/net/http/example_test.go b/libgo/go/net/http/example_test.go
new file mode 100644
index 00000000000..2584afc439e
--- /dev/null
+++ b/libgo/go/net/http/example_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 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 http_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+)
+
+func ExampleHijacker() {
+ http.HandleFunc("/hijack", func(w http.ResponseWriter, r *http.Request) {
+ hj, ok := w.(http.Hijacker)
+ if !ok {
+ http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
+ return
+ }
+ conn, bufrw, err := hj.Hijack()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ // Don't forget to close the connection:
+ defer conn.Close()
+ bufrw.WriteString("Now we're speaking raw TCP. Say hi: ")
+ bufrw.Flush()
+ s, err := bufrw.ReadString('\n')
+ if err != nil {
+ log.Printf("error reading string: %v", err)
+ return
+ }
+ fmt.Fprintf(bufrw, "You said: %q\nBye.\n", s)
+ bufrw.Flush()
+ })
+}
+
+func ExampleGet() {
+ res, err := http.Get("http://www.google.com/robots.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ robots, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+ res.Body.Close()
+ fmt.Printf("%s", robots)
+}
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index 143617e95fc..0409008b675 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -6,6 +6,7 @@ package http_test
import (
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -131,7 +132,7 @@ func TestFileServerCleans(t *testing.T) {
ch := make(chan string, 1)
fs := FileServer(&testFileSystem{func(name string) (File, error) {
ch <- name
- return nil, os.ENOENT
+ return nil, errors.New("file does not exist")
}})
tests := []struct {
reqPath, openArg string
@@ -398,11 +399,15 @@ func TestLinuxSendfile(t *testing.T) {
return
}
- _, err = Get(fmt.Sprintf("http://%s/", ln.Addr()))
+ res, err := Get(fmt.Sprintf("http://%s/", ln.Addr()))
if err != nil {
- t.Errorf("http client error: %v", err)
- return
+ t.Fatalf("http client error: %v", err)
+ }
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != nil {
+ t.Fatalf("client body read error: %v", err)
}
+ res.Body.Close()
// Force child to exit cleanly.
Get(fmt.Sprintf("http://%s/quit", ln.Addr()))
diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go
index c065ccfb499..32f4662cc0e 100644
--- a/libgo/go/net/http/httputil/persist.go
+++ b/libgo/go/net/http/httputil/persist.go
@@ -13,12 +13,12 @@ import (
"net"
"net/http"
"net/textproto"
- "os"
"sync"
)
var (
ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
+ ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)
@@ -191,7 +191,7 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
}
if sc.c == nil { // connection closed by user in the meantime
defer sc.lk.Unlock()
- return os.EBADF
+ return ErrClosed
}
c := sc.c
if sc.nread <= sc.nwritten {
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index 0fe41b7d31b..06fcde1447f 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -22,9 +22,9 @@
//
// go tool pprof http://localhost:6060/debug/pprof/profile
//
-// Or to look at the thread creation profile:
+// Or to view all available profiles:
//
-// go tool pprof http://localhost:6060/debug/pprof/thread
+// go tool pprof http://localhost:6060/debug/pprof/
//
// For a study of the facility in action, visit
//
@@ -36,7 +36,9 @@ import (
"bufio"
"bytes"
"fmt"
+ "html/template"
"io"
+ "log"
"net/http"
"os"
"runtime"
@@ -47,11 +49,10 @@ import (
)
func init() {
+ http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
- http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
- http.Handle("/debug/pprof/thread", http.HandlerFunc(Thread))
}
// Cmdline responds with the running program's
@@ -62,20 +63,6 @@ func Cmdline(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}
-// Heap responds with the pprof-formatted heap profile.
-// The package initialization registers it as /debug/pprof/heap.
-func Heap(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- pprof.WriteHeapProfile(w)
-}
-
-// Thread responds with the pprof-formatted thread creation profile.
-// The package initialization registers it as /debug/pprof/thread.
-func Thread(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- pprof.WriteThreadProfile(w)
-}
-
// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
@@ -147,3 +134,61 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
w.Write(buf.Bytes())
}
+
+// Handler returns an HTTP handler that serves the named profile.
+func Handler(name string) http.Handler {
+ return handler(name)
+}
+
+type handler string
+
+func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ debug, _ := strconv.Atoi(r.FormValue("debug"))
+ p := pprof.Lookup(string(name))
+ if p == nil {
+ w.WriteHeader(404)
+ fmt.Fprintf(w, "Unknown profile: %s\n", name)
+ return
+ }
+ p.WriteTo(w, debug)
+ return
+}
+
+// Index responds with the pprof-formatted profile named by the request.
+// For example, "/debug/pprof/heap" serves the "heap" profile.
+// Index responds to a request for "/debug/pprof/" with an HTML page
+// listing the available profiles.
+func Index(w http.ResponseWriter, r *http.Request) {
+ if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
+ name := r.URL.Path[len("/debug/pprof/"):]
+ if name != "" {
+ handler(name).ServeHTTP(w, r)
+ return
+ }
+ }
+
+ profiles := pprof.Profiles()
+ if err := indexTmpl.Execute(w, profiles); err != nil {
+ log.Print(err)
+ }
+}
+
+var indexTmpl = template.Must(template.New("index").Parse(`<html>
+<head>
+<title>/debug/pprof/</title>
+</head>
+/debug/pprof/<br>
+<br>
+<body>
+profiles:<br>
+<table>
+{{range .}}
+<tr><td align=right>{{.Count}}<td><a href="/debug/pprof/{{.Name}}?debug=1">{{.Name}}</a>
+{{end}}
+</table>
+<br>
+<a href="/debug/pprof/goroutine?debug=2">full goroutine stack dump</a><br>
+</body>
+</html>
+`))
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index 0bbec53be71..5277657805d 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -186,7 +186,7 @@ func (r *Request) Cookies() []*Cookie {
return readCookies(r.Header, "")
}
-var ErrNoCookie = errors.New("http: named cookied not present")
+var ErrNoCookie = errors.New("http: named cookie not present")
// Cookie returns the named cookie provided in the request or
// ErrNoCookie if not found.
@@ -486,7 +486,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
rawurl = "http://" + rawurl
}
- if req.URL, err = url.ParseRequest(rawurl); err != nil {
+ if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
return nil, err
}
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index e2860c3edcf..b6a6b4c77d1 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -245,8 +245,7 @@ func TestServerTimeouts(t *testing.T) {
fmt.Fprintf(res, "req=%d", reqNum)
})
- const second = 1000000000 /* nanos */
- server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+ server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
go server.Serve(l)
url := fmt.Sprintf("http://%s/", addr)
@@ -277,7 +276,7 @@ func TestServerTimeouts(t *testing.T) {
if n != 0 || err != io.EOF {
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
}
- if latency < 200*time.Millisecond /* fudge from 0.25 above */ {
+ if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
}
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index e715c73cb6e..fa0df54a236 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -12,7 +12,6 @@ package http
import (
"bufio"
"bytes"
- "crypto/rand"
"crypto/tls"
"errors"
"fmt"
@@ -985,6 +984,7 @@ type Server struct {
ReadTimeout time.Duration // maximum duration before timing out read of the request
WriteTimeout time.Duration // maximum duration before timing out write of the response
MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
+ TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
}
// ListenAndServe listens on the TCP network address srv.Addr and then
@@ -1121,9 +1121,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
if addr == "" {
addr = ":https"
}
- config := &tls.Config{
- Rand: rand.Reader,
- NextProtos: []string{"http/1.1"},
+ config := &tls.Config{}
+ if srv.TLSConfig != nil {
+ *config = *srv.TLSConfig
+ }
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
}
var err error
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index a36571a4446..1a629c1727c 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -648,7 +648,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
tr := &Transport{}
c := &Client{Transport: tr}
- n0 := runtime.Goroutines()
+ n0 := runtime.NumGoroutine()
const numReq = 25
didReqCh := make(chan bool)
@@ -669,7 +669,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
<-gotReqCh
}
- nhigh := runtime.Goroutines()
+ nhigh := runtime.NumGoroutine()
// Tell all handlers to unblock and reply.
for i := 0; i < numReq; i++ {
@@ -685,7 +685,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
time.Sleep(100 * time.Millisecond)
runtime.GC()
runtime.GC() // even more.
- nfinal := runtime.Goroutines()
+ nfinal := runtime.NumGoroutine()
growth := nfinal - n0
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index 21038c629b1..15c2f3781b1 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -166,13 +166,13 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, err
}
}
- ifmat4 := parseProcNetIGMP(ifi)
- ifmat6 := parseProcNetIGMP6(ifi)
+ ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
+ ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
return append(ifmat4, ifmat6...), nil
}
-func parseProcNetIGMP(ifi *Interface) []Addr {
- fd, err := open("/proc/net/igmp")
+func parseProcNetIGMP(path string, ifi *Interface) []Addr {
+ fd, err := open(path)
if err != nil {
return nil
}
@@ -185,23 +185,26 @@ func parseProcNetIGMP(ifi *Interface) []Addr {
fd.readLine() // skip first line
b := make([]byte, IPv4len)
for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
- f := getFields(l)
- switch len(f) {
- case 4:
+ f := splitAtBytes(l, " :\r\t\n")
+ if len(f) < 4 {
+ continue
+ }
+ switch {
+ case l[0] != ' ' && l[0] != '\t': // new interface line
+ name = f[1]
+ case len(f[0]) == 8:
if ifi == nil || name == ifi.Name {
fmt.Sscanf(f[0], "%08x", &b)
ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
ifmat = append(ifmat, ifma.toAddr())
}
- case 5:
- name = f[1]
}
}
return ifmat
}
-func parseProcNetIGMP6(ifi *Interface) []Addr {
- fd, err := open("/proc/net/igmp6")
+func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
+ fd, err := open(path)
if err != nil {
return nil
}
@@ -210,7 +213,10 @@ func parseProcNetIGMP6(ifi *Interface) []Addr {
var ifmat []Addr
b := make([]byte, IPv6len)
for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
- f := getFields(l)
+ f := splitAtBytes(l, " \r\t\n")
+ if len(f) < 6 {
+ continue
+ }
if ifi == nil || f[1] == ifi.Name {
fmt.Sscanf(f[2], "%32x", &b)
ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
index 4ce01dc9061..769414e0eef 100644
--- a/libgo/go/net/interface_test.go
+++ b/libgo/go/net/interface_test.go
@@ -31,17 +31,17 @@ func TestInterfaces(t *testing.T) {
for _, ifi := range ift {
ifxi, err := InterfaceByIndex(ifi.Index)
if err != nil {
- t.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+ t.Fatalf("InterfaceByIndex(%q) failed: %v", ifi.Index, err)
}
if !sameInterface(ifxi, &ifi) {
- t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+ t.Fatalf("InterfaceByIndex(%q) = %v, want %v", ifi.Index, *ifxi, ifi)
}
ifxn, err := InterfaceByName(ifi.Name)
if err != nil {
- t.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+ t.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err)
}
if !sameInterface(ifxn, &ifi) {
- t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+ t.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, *ifxn, ifi)
}
t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
t.Logf("\thardware address %q", ifi.HardwareAddr.String())
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
index f9401c1104e..6136202727c 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/ipraw_test.go
@@ -7,6 +7,7 @@ package net
import (
"bytes"
"os"
+ "syscall"
"testing"
"time"
)
@@ -15,7 +16,7 @@ var icmpTests = []struct {
net string
laddr string
raddr string
- ipv6 bool
+ ipv6 bool // test with underlying AF_INET6 socket
}{
{"ip4:icmp", "", "127.0.0.1", false},
{"ip6:icmp", "", "::1", true},
@@ -34,15 +35,15 @@ func TestICMP(t *testing.T) {
}
id := os.Getpid() & 0xffff
seqnum++
- echo := newICMPEchoRequest(tt.ipv6, id, seqnum, 128, []byte("Go Go Gadget Ping!!!"))
- exchangeICMPEcho(t, tt.net, tt.laddr, tt.raddr, tt.ipv6, echo)
+ echo := newICMPEchoRequest(tt.net, id, seqnum, 128, []byte("Go Go Gadget Ping!!!"))
+ exchangeICMPEcho(t, tt.net, tt.laddr, tt.raddr, echo)
}
}
-func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, ipv6 bool, echo []byte) {
+func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, echo []byte) {
c, err := ListenPacket(net, laddr)
if err != nil {
- t.Errorf("ListenPacket(%#q, %#q) failed: %v", net, laddr, err)
+ t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
return
}
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
@@ -50,12 +51,12 @@ func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, ipv6 bool, echo []
ra, err := ResolveIPAddr(net, raddr)
if err != nil {
- t.Errorf("ResolveIPAddr(%#q, %#q) failed: %v", net, raddr, err)
+ t.Errorf("ResolveIPAddr(%q, %q) failed: %v", net, raddr, err)
return
}
waitForReady := make(chan bool)
- go icmpEchoTransponder(t, net, raddr, ipv6, waitForReady)
+ go icmpEchoTransponder(t, net, raddr, waitForReady)
<-waitForReady
_, err = c.WriteTo(echo, ra)
@@ -71,11 +72,15 @@ func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, ipv6 bool, echo []
t.Errorf("ReadFrom failed: %v", err)
return
}
- if !ipv6 && reply[0] != ICMP4_ECHO_REPLY {
- continue
- }
- if ipv6 && reply[0] != ICMP6_ECHO_REPLY {
- continue
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
+ if reply[0] != ICMP4_ECHO_REPLY {
+ continue
+ }
+ case syscall.AF_INET6:
+ if reply[0] != ICMP6_ECHO_REPLY {
+ continue
+ }
}
xid, xseqnum := parseICMPEchoReply(echo)
rid, rseqnum := parseICMPEchoReply(reply)
@@ -87,11 +92,11 @@ func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, ipv6 bool, echo []
}
}
-func icmpEchoTransponder(t *testing.T, net, raddr string, ipv6 bool, waitForReady chan bool) {
+func icmpEchoTransponder(t *testing.T, net, raddr string, waitForReady chan bool) {
c, err := Dial(net, raddr)
if err != nil {
waitForReady <- true
- t.Errorf("Dial(%#q, %#q) failed: %v", net, raddr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, raddr, err)
return
}
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
@@ -106,18 +111,23 @@ func icmpEchoTransponder(t *testing.T, net, raddr string, ipv6 bool, waitForRead
t.Errorf("Read failed: %v", err)
return
}
- if !ipv6 && echo[0] != ICMP4_ECHO_REQUEST {
- continue
- }
- if ipv6 && echo[0] != ICMP6_ECHO_REQUEST {
- continue
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
+ if echo[0] != ICMP4_ECHO_REQUEST {
+ continue
+ }
+ case syscall.AF_INET6:
+ if echo[0] != ICMP6_ECHO_REQUEST {
+ continue
+ }
}
break
}
- if !ipv6 {
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
echo[0] = ICMP4_ECHO_REPLY
- } else {
+ case syscall.AF_INET6:
echo[0] = ICMP6_ECHO_REPLY
}
@@ -135,11 +145,15 @@ const (
ICMP6_ECHO_REPLY = 129
)
-func newICMPEchoRequest(ipv6 bool, id, seqnum, msglen int, filler []byte) []byte {
- if !ipv6 {
+func newICMPEchoRequest(net string, id, seqnum, msglen int, filler []byte) []byte {
+ afnet, _, _ := parseDialNetwork(net)
+ switch afnet {
+ case "ip4":
return newICMPv4EchoRequest(id, seqnum, msglen, filler)
+ case "ip6":
+ return newICMPv6EchoRequest(id, seqnum, msglen, filler)
}
- return newICMPv6EchoRequest(id, seqnum, msglen, filler)
+ return nil
}
func newICMPv4EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go
index 382a4402770..43719fc99cd 100644
--- a/libgo/go/net/iprawsock_plan9.go
+++ b/libgo/go/net/iprawsock_plan9.go
@@ -7,7 +7,7 @@
package net
import (
- "os"
+ "syscall"
"time"
)
@@ -17,34 +17,34 @@ type IPConn bool
// SetDeadline implements the Conn SetDeadline method.
func (c *IPConn) SetDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *IPConn) SetReadDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *IPConn) SetWriteDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// Implementation of the Conn interface - see Conn for documentation.
// Read implements the Conn Read method.
func (c *IPConn) Read(b []byte) (int, error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// Write implements the Conn Write method.
func (c *IPConn) Write(b []byte) (int, error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// Close closes the IP connection.
func (c *IPConn) Close() error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// LocalAddr returns the local network address.
@@ -67,12 +67,12 @@ func (c *IPConn) RemoteAddr() Addr {
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
- return 0, nil, os.EPLAN9
+ return 0, nil, syscall.EPLAN9
}
// ReadFrom implements the PacketConn ReadFrom method.
func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
- return 0, nil, os.EPLAN9
+ return 0, nil, syscall.EPLAN9
}
// WriteToIP writes a IP packet to addr via c, copying the payload from b.
@@ -82,18 +82,18 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// WriteTo implements the PacketConn WriteTo method.
func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// DialIP connects to the remote address raddr on the network protocol netProto,
// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// ListenIP listens for incoming IP packets addressed to the
@@ -101,5 +101,5 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
// and WriteTo methods can be used to receive and send IP
// packets with per-packet addressing.
func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index c34ffeb121d..9caa86985a5 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.go
@@ -66,7 +66,7 @@ func (c *IPConn) Read(b []byte) (int, error) {
// Write implements the Conn Write method.
func (c *IPConn) Write(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
@@ -74,7 +74,7 @@ func (c *IPConn) Write(b []byte) (int, error) {
// Close closes the IP connection.
func (c *IPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -100,7 +100,7 @@ func (c *IPConn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *IPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(c.fd, t)
}
@@ -108,7 +108,7 @@ func (c *IPConn) SetDeadline(t time.Time) error {
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *IPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadDeadline(c.fd, t)
}
@@ -116,7 +116,7 @@ func (c *IPConn) SetReadDeadline(t time.Time) error {
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *IPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteDeadline(c.fd, t)
}
@@ -125,7 +125,7 @@ func (c *IPConn) SetWriteDeadline(t time.Time) error {
// receive buffer associated with the connection.
func (c *IPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadBuffer(c.fd, bytes)
}
@@ -134,7 +134,7 @@ func (c *IPConn) SetReadBuffer(bytes int) error {
// transmit buffer associated with the connection.
func (c *IPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -150,7 +150,7 @@ func (c *IPConn) SetWriteBuffer(bytes int) error {
// SetReadDeadline.
func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
@@ -173,7 +173,7 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
// ReadFrom implements the PacketConn ReadFrom method.
func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromIP(b)
return n, uaddr.toAddr(), err
@@ -187,7 +187,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
// On packet-oriented connections, write timeouts are rare.
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
sa, err := addr.sockaddr(c.fd.family)
if err != nil {
@@ -199,11 +199,11 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
// WriteTo implements the PacketConn WriteTo method.
func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*IPAddr)
if !ok {
- return 0, &OpError{"write", c.fd.net, addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
}
return c.WriteToIP(b, a)
}
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
index 597b1277544..eab0bf3e899 100644
--- a/libgo/go/net/ipsock_plan9.go
+++ b/libgo/go/net/ipsock_plan9.go
@@ -10,6 +10,7 @@ import (
"errors"
"io"
"os"
+ "syscall"
"time"
)
@@ -83,7 +84,7 @@ func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
// Read implements the Conn Read method.
func (c *plan9Conn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -102,7 +103,7 @@ func (c *plan9Conn) Read(b []byte) (n int, err error) {
// Write implements the Conn Write method.
func (c *plan9Conn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -116,7 +117,7 @@ func (c *plan9Conn) Write(b []byte) (n int, err error) {
// Close closes the connection.
func (c *plan9Conn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.ctl.Close()
if err != nil {
@@ -148,17 +149,17 @@ func (c *plan9Conn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *plan9Conn) SetDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *plan9Conn) SetReadDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *plan9Conn) SetWriteDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
@@ -280,7 +281,7 @@ func (l *plan9Listener) Accept() (c Conn, err error) {
func (l *plan9Listener) Close() error {
if l == nil || l.ctl == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return l.ctl.Close()
}
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index 4da18a5061a..4841057d6be 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -105,21 +105,20 @@ type sockaddr interface {
}
func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
- var oserr error
var la, ra syscall.Sockaddr
family := favoriteAddrFamily(net, laddr, raddr, mode)
if laddr != nil {
- if la, oserr = laddr.sockaddr(family); oserr != nil {
+ if la, err = laddr.sockaddr(family); err != nil {
goto Error
}
}
if raddr != nil {
- if ra, oserr = raddr.sockaddr(family); oserr != nil {
+ if ra, err = raddr.sockaddr(family); err != nil {
goto Error
}
}
- fd, oserr = socket(net, family, sotype, proto, la, ra, toAddr)
- if oserr != nil {
+ fd, err = socket(net, family, sotype, proto, la, ra, toAddr)
+ if err != nil {
goto Error
}
return fd, nil
@@ -129,7 +128,7 @@ Error:
if mode == "listen" {
addr = laddr
}
- return nil, &OpError{mode, net, addr, oserr}
+ return nil, &OpError{mode, net, addr, err}
}
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
index c0bb9225a7d..b08a9fb98e0 100644
--- a/libgo/go/net/lookup_plan9.go
+++ b/libgo/go/net/lookup_plan9.go
@@ -7,6 +7,7 @@ package net
import (
"errors"
"os"
+ "syscall"
)
func query(filename, query string, bufSize int) (res []string, err error) {
@@ -71,7 +72,7 @@ func queryDNS(addr string, typ string) (res []string, err error) {
func lookupProtocol(name string) (proto int, err error) {
// TODO: Implement this
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
func lookupHost(host string) (addrs []string, err error) {
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 9a39ca8a1eb..7b9ea844cd4 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -8,14 +8,14 @@
package net
import (
- "runtime"
+ "flag"
"testing"
)
-var avoidMacFirewall = runtime.GOOS == "darwin"
+var testExternal = flag.Bool("external", false, "allow use of external networks during test")
func TestGoogleSRV(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -38,7 +38,7 @@ func TestGoogleSRV(t *testing.T) {
}
func TestGmailMX(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -52,7 +52,7 @@ func TestGmailMX(t *testing.T) {
}
func TestGmailTXT(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -66,7 +66,7 @@ func TestGmailTXT(t *testing.T) {
}
func TestGoogleDNSAddr(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go
index f62580de66e..1d760c21051 100644
--- a/libgo/go/net/multicast_test.go
+++ b/libgo/go/net/multicast_test.go
@@ -5,30 +5,46 @@
package net
import (
+ "errors"
"os"
"runtime"
+ "syscall"
"testing"
)
-var listenMulticastUDPTests = []struct {
+var multicastListenerTests = []struct {
net string
gaddr *UDPAddr
flags Flags
- ipv6 bool
+ ipv6 bool // test with underlying AF_INET6 socket
}{
// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
+
{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
- {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+ {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
+
+ {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+ {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
+
{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
}
-func TestListenMulticastUDP(t *testing.T) {
+// TestMulticastListener tests both single and double listen to a test
+// listener with same address family, same group address and same port.
+func TestMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "netbsd", "openbsd", "plan9", "windows":
return
@@ -38,112 +54,142 @@ func TestListenMulticastUDP(t *testing.T) {
}
}
- for _, tt := range listenMulticastUDPTests {
+ for _, tt := range multicastListenerTests {
if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
continue
}
- ift, err := Interfaces()
+ ifi, err := availMulticastInterface(t, tt.flags)
if err != nil {
- t.Fatalf("Interfaces failed: %v", err)
- }
- var ifi *Interface
- for _, x := range ift {
- if x.Flags&tt.flags == tt.flags {
- ifi = &x
- break
- }
- }
- if ifi == nil {
- t.Logf("an appropriate multicast interface not found")
- return
+ continue
}
- c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
if err != nil {
- t.Fatalf("ListenMulticastUDP failed: %v", err)
+ t.Fatalf("First ListenMulticastUDP failed: %v", err)
}
- defer c.Close() // test to listen concurrently across multiple listeners
- if !tt.ipv6 {
- testIPv4MulticastSocketOptions(t, c.fd, ifi)
- } else {
- testIPv6MulticastSocketOptions(t, c.fd, ifi)
- }
- ifmat, err := ifi.MulticastAddrs()
+ checkMulticastListener(t, err, c1, tt.gaddr)
+ c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
if err != nil {
- t.Fatalf("MulticastAddrs failed: %v", err)
- }
- var found bool
- for _, ifma := range ifmat {
- if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
- found = true
- break
- }
+ t.Fatalf("Second ListenMulticastUDP failed: %v", err)
}
- if !found {
- t.Fatalf("%q not found in RIB", tt.gaddr.String())
+ checkMulticastListener(t, err, c2, tt.gaddr)
+ c2.Close()
+ switch c1.fd.family {
+ case syscall.AF_INET:
+ testIPv4MulticastSocketOptions(t, c1.fd, ifi)
+ case syscall.AF_INET6:
+ testIPv6MulticastSocketOptions(t, c1.fd, ifi)
}
+ c1.Close()
}
}
-func TestSimpleListenMulticastUDP(t *testing.T) {
+func TestSimpleMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "plan9":
return
}
- for _, tt := range listenMulticastUDPTests {
+ for _, tt := range multicastListenerTests {
if tt.ipv6 {
continue
}
- tt.flags = FlagUp | FlagMulticast
+ tt.flags = FlagUp | FlagMulticast // for windows testing
+ ifi, err := availMulticastInterface(t, tt.flags)
+ if err != nil {
+ continue
+ }
+ c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("First ListenMulticastUDP failed: %v", err)
+ }
+ checkSimpleMulticastListener(t, err, c1, tt.gaddr)
+ c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("Second ListenMulticastUDP failed: %v", err)
+ }
+ checkSimpleMulticastListener(t, err, c2, tt.gaddr)
+ c2.Close()
+ c1.Close()
+ }
+}
+
+func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
+ if !multicastRIBContains(t, gaddr.IP) {
+ t.Fatalf("%q not found in RIB", gaddr.String())
+ }
+ if c.LocalAddr().String() != gaddr.String() {
+ t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
+ }
+}
+
+func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
+ if c.LocalAddr().String() != gaddr.String() {
+ t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
+ }
+}
+
+func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) {
+ var ifi *Interface
+ if flags != Flags(0) {
ift, err := Interfaces()
if err != nil {
t.Fatalf("Interfaces failed: %v", err)
}
- var ifi *Interface
for _, x := range ift {
- if x.Flags&tt.flags == tt.flags {
+ if x.Flags&flags == flags {
ifi = &x
break
}
}
if ifi == nil {
- t.Logf("an appropriate multicast interface not found")
- return
+ return nil, errors.New("an appropriate multicast interface not found")
}
- c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ }
+ return ifi, nil
+}
+
+func multicastRIBContains(t *testing.T, ip IP) bool {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces failed: %v", err)
+ }
+ for _, ifi := range ift {
+ ifmat, err := ifi.MulticastAddrs()
if err != nil {
- t.Fatalf("ListenMulticastUDP failed: %v", err)
+ t.Fatalf("MulticastAddrs failed: %v", err)
+ }
+ for _, ifma := range ifmat {
+ if ifma.(*IPAddr).IP.Equal(ip) {
+ return true
+ }
}
- c.Close()
}
+ return false
}
func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
- ifmc, err := ipv4MulticastInterface(fd)
+ _, err := ipv4MulticastInterface(fd)
if err != nil {
t.Fatalf("ipv4MulticastInterface failed: %v", err)
}
- t.Logf("IPv4 multicast interface: %v", ifmc)
- err = setIPv4MulticastInterface(fd, ifi)
- if err != nil {
- t.Fatalf("setIPv4MulticastInterface failed: %v", err)
+ if ifi != nil {
+ err = setIPv4MulticastInterface(fd, ifi)
+ if err != nil {
+ t.Fatalf("setIPv4MulticastInterface failed: %v", err)
+ }
}
-
- ttl, err := ipv4MulticastTTL(fd)
+ _, err = ipv4MulticastTTL(fd)
if err != nil {
t.Fatalf("ipv4MulticastTTL failed: %v", err)
}
- t.Logf("IPv4 multicast TTL: %v", ttl)
err = setIPv4MulticastTTL(fd, 1)
if err != nil {
t.Fatalf("setIPv4MulticastTTL failed: %v", err)
}
-
- loop, err := ipv4MulticastLoopback(fd)
+ _, err = ipv4MulticastLoopback(fd)
if err != nil {
t.Fatalf("ipv4MulticastLoopback failed: %v", err)
}
- t.Logf("IPv4 multicast loopback: %v", loop)
err = setIPv4MulticastLoopback(fd, false)
if err != nil {
t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
@@ -151,31 +197,28 @@ func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
}
func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
- ifmc, err := ipv6MulticastInterface(fd)
+ _, err := ipv6MulticastInterface(fd)
if err != nil {
t.Fatalf("ipv6MulticastInterface failed: %v", err)
}
- t.Logf("IPv6 multicast interface: %v", ifmc)
- err = setIPv6MulticastInterface(fd, ifi)
- if err != nil {
- t.Fatalf("setIPv6MulticastInterface failed: %v", err)
+ if ifi != nil {
+ err = setIPv6MulticastInterface(fd, ifi)
+ if err != nil {
+ t.Fatalf("setIPv6MulticastInterface failed: %v", err)
+ }
}
-
- hoplim, err := ipv6MulticastHopLimit(fd)
+ _, err = ipv6MulticastHopLimit(fd)
if err != nil {
t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
}
- t.Logf("IPv6 multicast hop limit: %v", hoplim)
err = setIPv6MulticastHopLimit(fd, 1)
if err != nil {
t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
}
-
- loop, err := ipv6MulticastLoopback(fd)
+ _, err = ipv6MulticastLoopback(fd)
if err != nil {
t.Fatalf("ipv6MulticastLoopback failed: %v", err)
}
- t.Logf("IPv6 multicast loopback: %v", loop)
err = setIPv6MulticastLoopback(fd, false)
if err != nil {
t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 79d36a2a813..bf242ff8dd6 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -2,8 +2,41 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package net provides a portable interface to Unix networks sockets,
-// including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
+/*
+Package net provides a portable interface for network I/O, including
+TCP/IP, UDP, domain name resolution, and Unix domain sockets.
+
+Although the package provides access to low-level networking
+primitives, most clients will need only the basic interface provided
+by the Dial, Listen, and Accept functions and the associated
+Conn and Listener interfaces. The crypto/tls package uses
+the same interfaces and similar Dial and Listen functions.
+
+The Dial function connects to a server:
+
+ conn, err := net.Dial("tcp", "google.com:80")
+ if err != nil {
+ // handle error
+ }
+ fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
+ status, err := bufio.NewReader(conn).ReadString('\n')
+ // ...
+
+The Listen function creates servers:
+
+ ln, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ // handle error
+ }
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ // handle error
+ continue
+ }
+ go handleConnection(conn)
+ }
+*/
package net
// TODO(rsc):
@@ -42,21 +75,28 @@ type Conn interface {
RemoteAddr() Addr
// SetDeadline sets the read and write deadlines associated
- // with the connection.
+ // with the connection. It is equivalent to calling both
+ // SetReadDeadline and SetWriteDeadline.
+ //
+ // A deadline is an absolute time after which I/O operations
+ // fail with a timeout (see type Error) instead of
+ // blocking. The deadline applies to all future I/O, not just
+ // the immediately following call to Read or Write.
+ //
+ // An idle timeout can be implemented by repeatedly extending
+ // the deadline after successful Read or Write calls.
+ //
+ // A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for all Read calls to return.
- // If the deadline is reached, Read will fail with a timeout
- // (see type Error) instead of blocking.
+ // SetReadDeadline sets the deadline for Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for all Write calls to return.
- // If the deadline is reached, Write will fail with a timeout
- // (see type Error) instead of blocking.
- // A zero value for t means Write will not time out.
+ // SetWriteDeadline sets the deadline for Write calls.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
+ // A zero value for t means Write will not time out.
SetWriteDeadline(t time.Time) error
}
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
index 4c4200a49b7..7c87b42f6d9 100644
--- a/libgo/go/net/parse.go
+++ b/libgo/go/net/parse.go
@@ -67,7 +67,7 @@ func open(name string) (*file, error) {
if err != nil {
return nil, err
}
- return &file{fd, make([]byte, 1024)[0:0], false}, nil
+ return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
}
func byteIndex(s string, c byte) int {
diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go
index 8cfa033ccc3..62c7b1e6004 100644
--- a/libgo/go/net/rpc/server_test.go
+++ b/libgo/go/net/rpc/server_test.go
@@ -387,12 +387,12 @@ func (WriteFailCodec) WriteRequest(*Request, interface{}) error {
}
func (WriteFailCodec) ReadResponseHeader(*Response) error {
- time.Sleep(120 * time.Second)
+ select {}
panic("unreachable")
}
func (WriteFailCodec) ReadResponseBody(interface{}) error {
- time.Sleep(120 * time.Second)
+ select {}
panic("unreachable")
}
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 55691493aa9..b9862168153 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -95,7 +95,7 @@ func doTest(t *testing.T, network, listenaddr, dialaddr string) {
t.Logf("Test %q %q %q", network, listenaddr, dialaddr)
switch listenaddr {
case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skip wildcard listen during short test")
return
}
diff --git a/libgo/go/net/smtp/smtp.go b/libgo/go/net/smtp/smtp.go
index f600cc86482..59f6449f0ab 100644
--- a/libgo/go/net/smtp/smtp.go
+++ b/libgo/go/net/smtp/smtp.go
@@ -50,15 +50,14 @@ func Dial(addr string) (*Client, error) {
// server name to be used when authenticating.
func NewClient(conn net.Conn, host string) (*Client, error) {
text := textproto.NewConn(conn)
- _, msg, err := text.ReadResponse(220)
+ _, _, err := text.ReadResponse(220)
if err != nil {
text.Close()
return nil, err
}
c := &Client{Text: text, conn: conn, serverName: host}
- if strings.Contains(msg, "ESMTP") {
- err = c.ehlo()
- } else {
+ err = c.ehlo()
+ if err != nil {
err = c.helo()
}
return c, err
diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go
index ce887820531..c315d185c9d 100644
--- a/libgo/go/net/smtp/smtp_test.go
+++ b/libgo/go/net/smtp/smtp_test.go
@@ -8,9 +8,11 @@ import (
"bufio"
"bytes"
"io"
+ "net"
"net/textproto"
"strings"
"testing"
+ "time"
)
type authTest struct {
@@ -59,9 +61,12 @@ type faker struct {
io.ReadWriter
}
-func (f faker) Close() error {
- return nil
-}
+func (f faker) Close() error { return nil }
+func (f faker) LocalAddr() net.Addr { return nil }
+func (f faker) RemoteAddr() net.Addr { return nil }
+func (f faker) SetDeadline(time.Time) error { return nil }
+func (f faker) SetReadDeadline(time.Time) error { return nil }
+func (f faker) SetWriteDeadline(time.Time) error { return nil }
func TestBasic(t *testing.T) {
basicServer = strings.Join(strings.Split(basicServer, "\n"), "\r\n")
@@ -180,3 +185,87 @@ Goodbye.
.
QUIT
`
+
+func TestNewClient(t *testing.T) {
+ newClientServer = strings.Join(strings.Split(newClientServer, "\n"), "\r\n")
+ newClientClient = strings.Join(strings.Split(newClientClient, "\n"), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ out := func() string {
+ bcmdbuf.Flush()
+ return cmdbuf.String()
+ }
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(newClientServer)), bcmdbuf)
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v\n(after %v)", err, out())
+ }
+ if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
+ t.Fatalf("Expected AUTH supported")
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err)
+ }
+
+ actualcmds := out()
+ if newClientClient != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, newClientClient)
+ }
+}
+
+var newClientServer = `220 hello world
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+221 OK
+`
+
+var newClientClient = `EHLO localhost
+QUIT
+`
+
+func TestNewClient2(t *testing.T) {
+ newClient2Server = strings.Join(strings.Split(newClient2Server, "\n"), "\r\n")
+ newClient2Client = strings.Join(strings.Split(newClient2Client, "\n"), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(newClient2Server)), bcmdbuf)
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v", err)
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err)
+ }
+
+ bcmdbuf.Flush()
+ actualcmds := cmdbuf.String()
+ if newClient2Client != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, newClient2Client)
+ }
+}
+
+var newClient2Server = `220 hello world
+502 EH?
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+221 OK
+`
+
+var newClient2Client = `EHLO localhost
+HELO localhost
+QUIT
+`
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index 70064c307ef..dc139f04a25 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -33,13 +33,14 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
return nil, err
}
+ var bla syscall.Sockaddr
if la != nil {
- la, err = listenerSockaddr(s, f, la, toAddr)
+ bla, err = listenerSockaddr(s, f, la, toAddr)
if err != nil {
closesocket(s)
return nil, err
}
- err = syscall.Bind(s, la)
+ err = syscall.Bind(s, bla)
if err != nil {
closesocket(s)
return nil, err
@@ -61,7 +62,12 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
}
sa, _ := syscall.Getsockname(s)
- laddr := toAddr(sa)
+ var laddr Addr
+ if la != nil && bla != la {
+ laddr = toAddr(la)
+ } else {
+ laddr = toAddr(sa)
+ }
sa, _ = syscall.Getpeername(s)
raddr := toAddr(sa)
diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go
index 128766144dd..35f56966eae 100644
--- a/libgo/go/net/tcpsock_plan9.go
+++ b/libgo/go/net/tcpsock_plan9.go
@@ -7,7 +7,7 @@
package net
import (
- "os"
+ "syscall"
"time"
)
@@ -19,35 +19,35 @@ type TCPConn struct {
// SetDeadline implements the Conn SetDeadline method.
func (c *TCPConn) SetDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *TCPConn) SetReadDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *TCPConn) SetWriteDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// CloseRead shuts down the reading side of the TCP connection.
// Most callers should just use Close.
func (c *TCPConn) CloseRead() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return os.EPLAN9
+ return syscall.EPLAN9
}
// CloseWrite shuts down the writing side of the TCP connection.
// Most callers should just use Close.
func (c *TCPConn) CloseWrite() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return os.EPLAN9
+ return syscall.EPLAN9
}
// DialTCP connects to the remote address raddr on the network net,
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index 200ce91566c..e05bc10170e 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -9,6 +9,7 @@
package net
import (
+ "fmt"
"io"
"os"
"syscall"
@@ -26,6 +27,11 @@ func sockaddrToTCP(sa syscall.Sockaddr) Addr {
return &TCPAddr{sa.Addr[0:], sa.Port}
case *syscall.SockaddrInet6:
return &TCPAddr{sa.Addr[0:], sa.Port}
+ default:
+ if sa != nil {
+ // Diagnose when we will turn a non-nil sockaddr into a nil.
+ panic(fmt.Sprintf("unexpected type in sockaddrToTCP: %T", sa))
+ }
}
return nil
}
@@ -70,7 +76,7 @@ func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
// Read implements the Conn Read method.
func (c *TCPConn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
@@ -86,7 +92,7 @@ func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
// Write implements the Conn Write method.
func (c *TCPConn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
@@ -94,7 +100,7 @@ func (c *TCPConn) Write(b []byte) (n int, err error) {
// Close closes the TCP connection.
func (c *TCPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -105,7 +111,7 @@ func (c *TCPConn) Close() error {
// Most callers should just use Close.
func (c *TCPConn) CloseRead() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return c.fd.CloseRead()
}
@@ -114,7 +120,7 @@ func (c *TCPConn) CloseRead() error {
// Most callers should just use Close.
func (c *TCPConn) CloseWrite() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return c.fd.CloseWrite()
}
@@ -138,7 +144,7 @@ func (c *TCPConn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *TCPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(c.fd, t)
}
@@ -146,7 +152,7 @@ func (c *TCPConn) SetDeadline(t time.Time) error {
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *TCPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadDeadline(c.fd, t)
}
@@ -154,7 +160,7 @@ func (c *TCPConn) SetReadDeadline(t time.Time) error {
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *TCPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteDeadline(c.fd, t)
}
@@ -163,7 +169,7 @@ func (c *TCPConn) SetWriteDeadline(t time.Time) error {
// receive buffer associated with the connection.
func (c *TCPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadBuffer(c.fd, bytes)
}
@@ -172,7 +178,7 @@ func (c *TCPConn) SetReadBuffer(bytes int) error {
// transmit buffer associated with the connection.
func (c *TCPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -190,7 +196,7 @@ func (c *TCPConn) SetWriteBuffer(bytes int) error {
// data to be sent and acknowledged.
func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setLinger(c.fd, sec)
}
@@ -199,7 +205,7 @@ func (c *TCPConn) SetLinger(sec int) error {
// keepalive messages on the connection.
func (c *TCPConn) SetKeepAlive(keepalive bool) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setKeepAlive(c.fd, keepalive)
}
@@ -210,7 +216,7 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
// that data is sent as soon as possible after a Write.
func (c *TCPConn) SetNoDelay(noDelay bool) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setNoDelay(c.fd, noDelay)
}
@@ -259,6 +265,17 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
}
func selfConnect(fd *netFD) bool {
+ // The socket constructor can return an fd with raddr nil under certain
+ // unknown conditions. The errors in the calls there to Getpeername
+ // are discarded, but we can't catch the problem there because those
+ // calls are sometimes legally erroneous with a "socket not connected".
+ // Since this code (selfConnect) is already trying to work around
+ // a problem, we make sure if this happens we recognize trouble and
+ // ask the DialTCP routine to try again.
+ // TODO: try to understand what's really going on.
+ if fd.laddr == nil || fd.raddr == nil {
+ return true
+ }
l := fd.laddr.(*TCPAddr)
r := fd.raddr.(*TCPAddr)
return l.Port == r.Port && l.IP.Equal(r.IP)
@@ -294,7 +311,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
// and the remote address.
func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) {
if l == nil || l.fd == nil || l.fd.sysfd < 0 {
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
fd, err := l.fd.accept(sockaddrToTCP)
if err != nil {
@@ -317,7 +334,7 @@ func (l *TCPListener) Accept() (c Conn, err error) {
// Already Accepted connections are not closed.
func (l *TCPListener) Close() error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return l.fd.Close()
}
@@ -329,7 +346,7 @@ func (l *TCPListener) Addr() Addr { return l.fd.laddr }
// A zero time value disables the deadline.
func (l *TCPListener) SetDeadline(t time.Time) error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(l.fd, t)
}
diff --git a/libgo/go/net/testdata/hosts b/libgo/go/net/testdata/hosts
new file mode 100644
index 00000000000..b601763898b
--- /dev/null
+++ b/libgo/go/net/testdata/hosts
@@ -0,0 +1,12 @@
+255.255.255.255 broadcasthost
+127.0.0.2 odin
+127.0.0.3 odin # inline comment
+::2 odin
+127.1.1.1 thor
+# aliases
+127.1.1.2 ullr ullrhost
+# Bogus entries that must be ignored.
+123.123.123 loki
+321.321.321.321
+# TODO(yvesj): Should we be able to parse this? From a Darwin system.
+fe80::1%lo0 localhost
diff --git a/libgo/go/net/testdata/igmp b/libgo/go/net/testdata/igmp
new file mode 100644
index 00000000000..5f380a2c7db
--- /dev/null
+++ b/libgo/go/net/testdata/igmp
@@ -0,0 +1,24 @@
+Idx Device : Count Querier Group Users Timer Reporter
+1 lo : 1 V3
+ 010000E0 1 0:00000000 0
+2 eth0 : 2 V2
+ FB0000E0 1 0:00000000 1
+ 010000E0 1 0:00000000 0
+3 eth1 : 1 V3
+ 010000E0 1 0:00000000 0
+4 eth2 : 1 V3
+ 010000E0 1 0:00000000 0
+5 eth0.100 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+6 eth0.101 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+7 eth0.102 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+8 eth0.103 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+9 device1tap2: 1 V3
+ 010000E0 1 0:00000000 0
diff --git a/libgo/go/net/testdata/igmp6 b/libgo/go/net/testdata/igmp6
new file mode 100644
index 00000000000..6cd5a2d4d9d
--- /dev/null
+++ b/libgo/go/net/testdata/igmp6
@@ -0,0 +1,18 @@
+1 lo ff020000000000000000000000000001 1 0000000C 0
+2 eth0 ff0200000000000000000001ffac891e 1 00000006 0
+2 eth0 ff020000000000000000000000000001 1 0000000C 0
+3 eth1 ff0200000000000000000001ffac8928 2 00000006 0
+3 eth1 ff020000000000000000000000000001 1 0000000C 0
+4 eth2 ff0200000000000000000001ffac8932 2 00000006 0
+4 eth2 ff020000000000000000000000000001 1 0000000C 0
+5 eth0.100 ff0200000000000000000001ffac891e 1 00000004 0
+5 eth0.100 ff020000000000000000000000000001 1 0000000C 0
+6 pan0 ff020000000000000000000000000001 1 0000000C 0
+7 eth0.101 ff0200000000000000000001ffac891e 1 00000004 0
+7 eth0.101 ff020000000000000000000000000001 1 0000000C 0
+8 eth0.102 ff0200000000000000000001ffac891e 1 00000004 0
+8 eth0.102 ff020000000000000000000000000001 1 0000000C 0
+9 eth0.103 ff0200000000000000000001ffac891e 1 00000004 0
+9 eth0.103 ff020000000000000000000000000001 1 0000000C 0
+10 device1tap2 ff0200000000000000000001ff4cc3a3 1 00000004 0
+10 device1tap2 ff020000000000000000000000000001 1 0000000C 0
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
index 862cd536c46..125feb3e885 100644
--- a/libgo/go/net/textproto/reader.go
+++ b/libgo/go/net/textproto/reader.go
@@ -454,10 +454,14 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
// Key ends at first colon; must not have spaces.
i := bytes.IndexByte(kv, ':')
- if i < 0 || bytes.IndexByte(kv[0:i], ' ') >= 0 {
+ if i < 0 {
return m, ProtocolError("malformed MIME header line: " + string(kv))
}
- key := CanonicalMIMEHeaderKey(string(kv[0:i]))
+ key := string(kv[0:i])
+ if strings.Index(key, " ") >= 0 {
+ key = strings.TrimRight(key, " ")
+ }
+ key = CanonicalMIMEHeaderKey(key)
// Skip initial spaces in value.
i++ // skip colon
@@ -503,6 +507,11 @@ MustRewrite:
a := []byte(s)
upper := true
for i, v := range a {
+ if v == ' ' {
+ a[i] = '-'
+ upper = true
+ continue
+ }
if upper && 'a' <= v && v <= 'z' {
a[i] = v + 'A' - 'a'
}
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
index 4d036914801..7c5d16227ff 100644
--- a/libgo/go/net/textproto/reader_test.go
+++ b/libgo/go/net/textproto/reader_test.go
@@ -164,6 +164,29 @@ func TestLargeReadMIMEHeader(t *testing.T) {
}
}
+// Test that we read slightly-bogus MIME headers seen in the wild,
+// with spaces before colons, and spaces in keys.
+func TestReadMIMEHeaderNonCompliant(t *testing.T) {
+ // Invalid HTTP response header as sent by an Axis security
+ // camera: (this is handled by IE, Firefox, Chrome, curl, etc.)
+ r := reader("Foo: bar\r\n" +
+ "Content-Language: en\r\n" +
+ "SID : 0\r\n" +
+ "Audio Mode : None\r\n" +
+ "Privilege : 127\r\n\r\n")
+ m, err := r.ReadMIMEHeader()
+ want := MIMEHeader{
+ "Foo": {"bar"},
+ "Content-Language": {"en"},
+ "Sid": {"0"},
+ "Audio-Mode": {"None"},
+ "Privilege": {"127"},
+ }
+ if !reflect.DeepEqual(m, want) || err != nil {
+ t.Fatalf("ReadMIMEHeader =\n%v, %v; want:\n%v", m, err, want)
+ }
+}
+
type readResponseTest struct {
in string
inCode int
diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go
index 317ec72b0cc..ad5840cf7da 100644
--- a/libgo/go/net/textproto/textproto.go
+++ b/libgo/go/net/textproto/textproto.go
@@ -20,6 +20,9 @@
//
// Writer, to write dot-encoded text blocks.
//
+// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
+// with a single network connection.
+//
package textproto
import (
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
index f90a5fe9ab8..4f298a42f87 100644
--- a/libgo/go/net/udpsock_plan9.go
+++ b/libgo/go/net/udpsock_plan9.go
@@ -9,6 +9,7 @@ package net
import (
"errors"
"os"
+ "syscall"
"time"
)
@@ -20,17 +21,17 @@ type UDPConn struct {
// SetDeadline implements the Conn SetDeadline method.
func (c *UDPConn) SetDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *UDPConn) SetReadDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *UDPConn) SetWriteDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// UDP-specific methods.
@@ -43,7 +44,7 @@ func (c *UDPConn) SetWriteDeadline(t time.Time) error {
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -69,7 +70,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
return c.ReadFromUDP(b)
}
@@ -82,7 +83,7 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
// On packet-oriented connections, write timeouts are rare.
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -106,11 +107,11 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
// WriteTo implements the PacketConn WriteTo method.
func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UDPAddr)
if !ok {
- return 0, &OpError{"write", c.dir, addr, os.EINVAL}
+ return 0, &OpError{"write", c.dir, addr, syscall.EINVAL}
}
return c.WriteToUDP(b, a)
}
@@ -191,5 +192,5 @@ func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
// the interface to join. ListenMulticastUDP uses default
// multicast interface if ifi is nil.
func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index 6108373568a..1f99dc53867 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.go
@@ -63,7 +63,7 @@ func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
// Read implements the Conn Read method.
func (c *UDPConn) Read(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
@@ -71,7 +71,7 @@ func (c *UDPConn) Read(b []byte) (int, error) {
// Write implements the Conn Write method.
func (c *UDPConn) Write(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
@@ -79,7 +79,7 @@ func (c *UDPConn) Write(b []byte) (int, error) {
// Close closes the UDP connection.
func (c *UDPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -105,7 +105,7 @@ func (c *UDPConn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *UDPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(c.fd, t)
}
@@ -113,7 +113,7 @@ func (c *UDPConn) SetDeadline(t time.Time) error {
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *UDPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadDeadline(c.fd, t)
}
@@ -121,7 +121,7 @@ func (c *UDPConn) SetReadDeadline(t time.Time) error {
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *UDPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteDeadline(c.fd, t)
}
@@ -130,7 +130,7 @@ func (c *UDPConn) SetWriteDeadline(t time.Time) error {
// receive buffer associated with the connection.
func (c *UDPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadBuffer(c.fd, bytes)
}
@@ -139,7 +139,7 @@ func (c *UDPConn) SetReadBuffer(bytes int) error {
// transmit buffer associated with the connection.
func (c *UDPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -154,7 +154,7 @@ func (c *UDPConn) SetWriteBuffer(bytes int) error {
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) {
@@ -169,7 +169,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromUDP(b)
return n, uaddr.toAddr(), err
@@ -183,7 +183,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
// On packet-oriented connections, write timeouts are rare.
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.fd.isConnected {
return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
@@ -198,11 +198,11 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
// WriteTo implements the PacketConn WriteTo method.
func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UDPAddr)
if !ok {
- return 0, &OpError{"write", c.fd.net, addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
}
return c.WriteToUDP(b, a)
}
@@ -262,7 +262,7 @@ func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, e
return nil, UnknownNetworkError(net)
}
if gaddr == nil || gaddr.IP == nil {
- return nil, &OpError{"listenmulticastudp", "udp", nil, errMissingAddress}
+ return nil, &OpError{"listenmulticast", net, nil, errMissingAddress}
}
fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
if err != nil {
diff --git a/libgo/go/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go
index 1d9d7578f4f..7b4ae6bd116 100644
--- a/libgo/go/net/unixsock_plan9.go
+++ b/libgo/go/net/unixsock_plan9.go
@@ -7,7 +7,7 @@
package net
import (
- "os"
+ "syscall"
"time"
)
@@ -19,17 +19,17 @@ type UnixConn bool
// Read implements the Conn Read method.
func (c *UnixConn) Read(b []byte) (n int, err error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// Write implements the Conn Write method.
func (c *UnixConn) Write(b []byte) (n int, err error) {
- return 0, os.EPLAN9
+ return 0, syscall.EPLAN9
}
// Close closes the Unix domain connection.
func (c *UnixConn) Close() error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// LocalAddr returns the local network address, a *UnixAddr.
@@ -47,28 +47,28 @@ func (c *UnixConn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *UnixConn) SetDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *UnixConn) SetReadDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *UnixConn) SetWriteDeadline(t time.Time) error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
- err = os.EPLAN9
+ err = syscall.EPLAN9
return
}
// WriteTo implements the PacketConn WriteTo method.
func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
- err = os.EPLAN9
+ err = syscall.EPLAN9
return
}
@@ -76,7 +76,7 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
// which must be "unix" or "unixgram". If laddr is not nil, it is used
// as the local address for the connection.
func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// UnixListener is a Unix domain socket listener.
@@ -87,19 +87,19 @@ type UnixListener bool
// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
// Net must be "unix" (stream sockets).
func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// Accept implements the Accept method in the Listener interface;
// it waits for the next call and returns a generic Conn.
func (l *UnixListener) Accept() (c Conn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// Close stops listening on the Unix address.
// Already accepted connections are not closed.
func (l *UnixListener) Close() error {
- return os.EPLAN9
+ return syscall.EPLAN9
}
// Addr returns the listener's network address.
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index 10b79668511..3a94cf5c5ad 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -59,8 +59,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
f = sockaddrToUnixpacket
}
- fd, oserr := socket(net, syscall.AF_UNIX, sotype, 0, la, ra, f)
- if oserr != nil {
+ fd, err = socket(net, syscall.AF_UNIX, sotype, 0, la, ra, f)
+ if err != nil {
goto Error
}
return fd, nil
@@ -70,7 +70,7 @@ Error:
if mode == "listen" {
addr = laddr
}
- return nil, &OpError{Op: mode, Net: net, Addr: addr, Err: oserr}
+ return nil, &OpError{Op: mode, Net: net, Addr: addr, Err: err}
}
func sockaddrToUnix(sa syscall.Sockaddr) Addr {
@@ -123,7 +123,7 @@ func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
// Read implements the Conn Read method.
func (c *UnixConn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
@@ -131,7 +131,7 @@ func (c *UnixConn) Read(b []byte) (n int, err error) {
// Write implements the Conn Write method.
func (c *UnixConn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
@@ -139,7 +139,7 @@ func (c *UnixConn) Write(b []byte) (n int, err error) {
// Close closes the Unix domain connection.
func (c *UnixConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -168,7 +168,7 @@ func (c *UnixConn) RemoteAddr() Addr {
// SetDeadline implements the Conn SetDeadline method.
func (c *UnixConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(c.fd, t)
}
@@ -176,7 +176,7 @@ func (c *UnixConn) SetDeadline(t time.Time) error {
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *UnixConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadDeadline(c.fd, t)
}
@@ -184,7 +184,7 @@ func (c *UnixConn) SetReadDeadline(t time.Time) error {
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *UnixConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteDeadline(c.fd, t)
}
@@ -193,7 +193,7 @@ func (c *UnixConn) SetWriteDeadline(t time.Time) error {
// receive buffer associated with the connection.
func (c *UnixConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setReadBuffer(c.fd, bytes)
}
@@ -202,7 +202,7 @@ func (c *UnixConn) SetReadBuffer(bytes int) error {
// transmit buffer associated with the connection.
func (c *UnixConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -216,7 +216,7 @@ func (c *UnixConn) SetWriteBuffer(bytes int) error {
// see SetDeadline and SetReadDeadline.
func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) {
@@ -229,7 +229,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromUnix(b)
return n, uaddr.toAddr(), err
@@ -243,10 +243,10 @@ func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
// On packet-oriented connections, write timeouts are rare.
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if addr.Net != sotypeToNet(c.fd.sotype) {
- return 0, os.EAFNOSUPPORT
+ return 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
return c.fd.WriteTo(b, sa)
@@ -255,18 +255,18 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
// WriteTo implements the PacketConn WriteTo method.
func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UnixAddr)
if !ok {
- return 0, &OpError{"write", c.fd.net, addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
}
return c.WriteToUnix(b, a)
}
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
if !c.ok() {
- return 0, 0, 0, nil, os.EINVAL
+ return 0, 0, 0, nil, syscall.EINVAL
}
n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
switch sa := sa.(type) {
@@ -278,11 +278,11 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if !c.ok() {
- return 0, 0, os.EINVAL
+ return 0, 0, syscall.EINVAL
}
if addr != nil {
if addr.Net != sotypeToNet(c.fd.sotype) {
- return 0, 0, os.EAFNOSUPPORT
+ return 0, 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
return c.fd.WriteMsg(b, oob, sa)
@@ -339,7 +339,7 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
// and the remote address.
func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
if l == nil || l.fd == nil {
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
fd, err := l.fd.accept(sockaddrToUnix)
if err != nil {
@@ -363,7 +363,7 @@ func (l *UnixListener) Accept() (c Conn, err error) {
// Already accepted connections are not closed.
func (l *UnixListener) Close() error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
// The operating system doesn't clean up
@@ -391,7 +391,7 @@ func (l *UnixListener) Addr() Addr { return l.fd.laddr }
// A zero time value disables the deadline.
func (l *UnixListener) SetDeadline(t time.Time) (err error) {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return setDeadline(l.fd, t)
}
diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go
index a9ce3b31e24..88ff7ebfef3 100644
--- a/libgo/go/net/url/url.go
+++ b/libgo/go/net/url/url.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package URL parses URLs and implements query escaping.
+// Package url parses URLs and implements query escaping.
// See RFC 3986.
package url
@@ -321,19 +321,28 @@ func split(s string, c byte, cutc bool) (string, string) {
}
// Parse parses rawurl into a URL structure.
-// The string rawurl is assumed not to have a #fragment suffix.
-// (Web browsers strip #fragment before sending the URL to a web server.)
// The rawurl may be relative or absolute.
func Parse(rawurl string) (url *URL, err error) {
- return parse(rawurl, false)
+ // Cut off #frag
+ u, frag := split(rawurl, '#', true)
+ if url, err = parse(u, false); err != nil {
+ return nil, err
+ }
+ if frag == "" {
+ return url, nil
+ }
+ if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ return url, nil
}
-// ParseRequest parses rawurl into a URL structure. It assumes that
-// rawurl was received from an HTTP request, so the rawurl is interpreted
+// ParseRequestURI parses rawurl into a URL structure. It assumes that
+// rawurl was received in an HTTP request, so the rawurl is interpreted
// only as an absolute URI or an absolute path.
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
-func ParseRequest(rawurl string) (url *URL, err error) {
+func ParseRequestURI(rawurl string) (url *URL, err error) {
return parse(rawurl, true)
}
@@ -415,22 +424,6 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
return
}
-// ParseWithReference is like Parse but allows a trailing #fragment.
-func ParseWithReference(rawurlref string) (url *URL, err error) {
- // Cut off #frag
- rawurl, frag := split(rawurlref, '#', true)
- if url, err = Parse(rawurl); err != nil {
- return nil, err
- }
- if frag == "" {
- return url, nil
- }
- if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
- return nil, &Error{"parse", rawurlref, err}
- }
- return url, nil
-}
-
// String reassembles the URL into a valid URL string.
func (u *URL) String() string {
// TODO: Rewrite to use bytes.Buffer
@@ -589,15 +582,15 @@ func (u *URL) IsAbs() bool {
return u.Scheme != ""
}
-// Parse parses a URL in the context of a base URL. The URL in ref
+// Parse parses a URL in the context of the receiver. The provided URL
// may be relative or absolute. Parse returns nil, err on parse
// failure, otherwise its return value is the same as ResolveReference.
-func (base *URL) Parse(ref string) (*URL, error) {
+func (u *URL) Parse(ref string) (*URL, error) {
refurl, err := Parse(ref)
if err != nil {
return nil, err
}
- return base.ResolveReference(refurl), nil
+ return u.ResolveReference(refurl), nil
}
// ResolveReference resolves a URI reference to an absolute URI from
@@ -606,13 +599,13 @@ func (base *URL) Parse(ref string) (*URL, error) {
// URL instance, even if the returned URL is identical to either the
// base or reference. If ref is an absolute URL, then ResolveReference
// ignores base and returns a copy of ref.
-func (base *URL) ResolveReference(ref *URL) *URL {
+func (u *URL) ResolveReference(ref *URL) *URL {
if ref.IsAbs() {
url := *ref
return &url
}
// relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- url := *base
+ url := *u
url.RawQuery = ref.RawQuery
url.Fragment = ref.Fragment
if ref.Opaque != "" {
@@ -632,7 +625,7 @@ func (base *URL) ResolveReference(ref *URL) *URL {
url.Path = ref.Path
} else {
// The "rel_path" case.
- path := resolvePath(base.Path, ref.Path)
+ path := resolvePath(u.Path, ref.Path)
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go
index 9fe5ff886b7..2d911ed505a 100644
--- a/libgo/go/net/url/url_test.go
+++ b/libgo/go/net/url/url_test.go
@@ -188,22 +188,6 @@ var urltests = []URLTest{
},
"http://user:password@google.com",
},
-}
-
-var urlnofragtests = []URLTest{
- {
- "http://www.google.com/?q=go+language#foo",
- &URL{
- Scheme: "http",
- Host: "www.google.com",
- Path: "/",
- RawQuery: "q=go+language#foo",
- },
- "",
- },
-}
-
-var urlfragtests = []URLTest{
{
"http://www.google.com/?q=go+language#foo",
&URL{
@@ -257,12 +241,6 @@ func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests [
func TestParse(t *testing.T) {
DoTest(t, Parse, "Parse", urltests)
- DoTest(t, Parse, "Parse", urlnofragtests)
-}
-
-func TestParseWithReference(t *testing.T) {
- DoTest(t, ParseWithReference, "ParseWithReference", urltests)
- DoTest(t, ParseWithReference, "ParseWithReference", urlfragtests)
}
const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path"
@@ -281,16 +259,16 @@ var parseRequestUrlTests = []struct {
{"../dir/", false},
}
-func TestParseRequest(t *testing.T) {
+func TestParseRequestURI(t *testing.T) {
for _, test := range parseRequestUrlTests {
- _, err := ParseRequest(test.url)
+ _, err := ParseRequestURI(test.url)
valid := err == nil
if valid != test.expectedValid {
t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid)
}
}
- url, err := ParseRequest(pathThatLooksSchemeRelative)
+ url, err := ParseRequestURI(pathThatLooksSchemeRelative)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
@@ -319,9 +297,6 @@ func DoTestString(t *testing.T, parse func(string) (*URL, error), name string, t
func TestURLString(t *testing.T) {
DoTestString(t, Parse, "Parse", urltests)
- DoTestString(t, Parse, "Parse", urlnofragtests)
- DoTestString(t, ParseWithReference, "ParseWithReference", urltests)
- DoTestString(t, ParseWithReference, "ParseWithReference", urlfragtests)
}
type EscapeTest struct {
@@ -538,7 +513,7 @@ var resolveReferenceTests = []struct {
func TestResolveReference(t *testing.T) {
mustParse := func(url string) *URL {
- u, err := ParseWithReference(url)
+ u, err := Parse(url)
if err != nil {
t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
}
@@ -589,7 +564,7 @@ func TestResolveReference(t *testing.T) {
func TestResolveReferenceOpaque(t *testing.T) {
mustParse := func(url string) *URL {
- u, err := ParseWithReference(url)
+ u, err := Parse(url)
if err != nil {
t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
}
diff --git a/libgo/go/old/netchan/netchan_test.go b/libgo/go/old/netchan/netchan_test.go
index 53f0f787765..9a7c076d59c 100644
--- a/libgo/go/old/netchan/netchan_test.go
+++ b/libgo/go/old/netchan/netchan_test.go
@@ -291,6 +291,10 @@ func exportLoopback(exp *Exporter, t *testing.T) {
// This test checks that channel operations can proceed
// even when other concurrent operations are blocked.
func TestIndependentSends(t *testing.T) {
+ if testing.Short() {
+ t.Logf("disabled test during -short")
+ return
+ }
exp, imp := pair(t)
exportLoopback(exp, t)
@@ -378,6 +382,10 @@ const flowCount = 100
// test flow control from exporter to importer.
func TestExportFlowControl(t *testing.T) {
+ if testing.Short() {
+ t.Logf("disabled test during -short")
+ return
+ }
exp, imp := pair(t)
sendDone := make(chan bool, 1)
@@ -394,6 +402,10 @@ func TestExportFlowControl(t *testing.T) {
// test flow control from importer to exporter.
func TestImportFlowControl(t *testing.T) {
+ if testing.Short() {
+ t.Logf("disabled test during -short")
+ return
+ }
exp, imp := pair(t)
ch := make(chan int)
diff --git a/libgo/go/os/dir_plan9.go b/libgo/go/os/dir_plan9.go
index f2dc15409db..7fa4c7f4449 100644
--- a/libgo/go/os/dir_plan9.go
+++ b/libgo/go/os/dir_plan9.go
@@ -10,6 +10,9 @@ import (
"syscall"
)
+var errShortStat = errors.New("short stat message")
+var errBadStat = errors.New("bad stat message format")
+
func (file *File) readdir(n int) (fi []FileInfo, err error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
@@ -35,7 +38,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
break
}
if d.nbuf < syscall.STATFIXLEN {
- return result, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, errShortStat}
}
}
@@ -43,7 +46,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
m, _ := gbit16(d.buf[d.bufp:])
m += 2
if m < syscall.STATFIXLEN {
- return result, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, errShortStat}
}
dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
if e != nil {
@@ -138,7 +141,7 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
n, b = gbit16(b)
if int(n) != len(b) {
- return nil, Ebadstat
+ return nil, errBadStat
}
d = new(Dir)
@@ -155,7 +158,7 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
d.Muid, b = gstring(b)
if len(b) != 0 {
- return nil, Ebadstat
+ return nil, errBadStat
}
return d, nil
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
index 59350510ccf..eb265f24138 100644
--- a/libgo/go/os/env.go
+++ b/libgo/go/os/env.go
@@ -6,10 +6,7 @@
package os
-import (
- "errors"
- "syscall"
-)
+import "syscall"
// Expand replaces ${var} or $var in the string based on the mapping function.
// Invocations of undefined variables are replaced with the empty string.
@@ -77,26 +74,10 @@ func getShellName(s string) (string, int) {
return s[:i], i
}
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
- if len(key) == 0 {
- return "", EINVAL
- }
- val, found := syscall.Getenv(key)
- if !found {
- return "", ENOENV
- }
- return val, nil
-}
-
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
func Getenv(key string) string {
- v, _ := Getenverror(key)
+ v, _ := syscall.Getenv(key)
return v
}
diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go
index 135cdae1f9b..e0b83b5c22c 100644
--- a/libgo/go/os/error.go
+++ b/libgo/go/os/error.go
@@ -4,6 +4,18 @@
package os
+import (
+ "errors"
+)
+
+// Portable analogs of some common system call errors.
+var (
+ ErrInvalid = errors.New("invalid argument")
+ ErrPermission = errors.New("permission denied")
+ ErrExist = errors.New("file already exists")
+ ErrNotExist = errors.New("file does not exist")
+)
+
// PathError records an error and the operation and file path that caused it.
type PathError struct {
Op string
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index cc847e07743..159d685e7cd 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -4,34 +4,38 @@
package os
-import (
- "errors"
- "syscall"
-)
+// IsExist returns whether the error is known to report that a file already exists.
+func IsExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return contains(err.Error(), " exists")
+}
-var (
- Eshortstat = errors.New("stat buffer too small")
- Ebadstat = errors.New("malformed stat buffer")
- Ebadfd = errors.New("fd out of range or not open")
- Ebadarg = errors.New("bad arg in system call")
- Enotdir = errors.New("not a directory")
- Enonexist = errors.New("file does not exist")
- Eexist = errors.New("file already exists")
- Eio = errors.New("i/o error")
- Eperm = errors.New("permission denied")
+// IsNotExist returns whether the error is known to report that a file does not exist.
+func IsNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return contains(err.Error(), "does not exist")
+}
- EINVAL = Ebadarg
- ENOTDIR = Enotdir
- ENOENT = Enonexist
- EEXIST = Eexist
- EIO = Eio
- EACCES = Eperm
- EPERM = Eperm
- EISDIR = syscall.EISDIR
+// IsPermission returns whether the error is known to report that permission is denied.
+func IsPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return contains(err.Error(), "permission denied")
+}
- EBADF = errors.New("bad file descriptor")
- ENAMETOOLONG = errors.New("file name too long")
- ERANGE = errors.New("math result not representable")
- EPIPE = errors.New("Broken Pipe")
- EPLAN9 = errors.New("not supported by plan 9")
-)
+// contains is a local version of strings.Contains. It knows len(sep) > 1.
+func contains(s, sep string) bool {
+ n := len(sep)
+ c := sep[0]
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && s[i:i+n] == sep {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go
index 57c9b6f2786..74b75d11218 100644
--- a/libgo/go/os/error_posix.go
+++ b/libgo/go/os/error_posix.go
@@ -8,44 +8,29 @@ package os
import "syscall"
-// Commonly known Unix errors.
-var (
- EPERM error = syscall.EPERM
- ENOENT error = syscall.ENOENT
- ESRCH error = syscall.ESRCH
- EINTR error = syscall.EINTR
- EIO error = syscall.EIO
- E2BIG error = syscall.E2BIG
- ENOEXEC error = syscall.ENOEXEC
- EBADF error = syscall.EBADF
- ECHILD error = syscall.ECHILD
- EDEADLK error = syscall.EDEADLK
- ENOMEM error = syscall.ENOMEM
- EACCES error = syscall.EACCES
- EFAULT error = syscall.EFAULT
- EBUSY error = syscall.EBUSY
- EEXIST error = syscall.EEXIST
- EXDEV error = syscall.EXDEV
- ENODEV error = syscall.ENODEV
- ENOTDIR error = syscall.ENOTDIR
- EISDIR error = syscall.EISDIR
- EINVAL error = syscall.EINVAL
- ENFILE error = syscall.ENFILE
- EMFILE error = syscall.EMFILE
- ENOTTY error = syscall.ENOTTY
- EFBIG error = syscall.EFBIG
- ENOSPC error = syscall.ENOSPC
- ESPIPE error = syscall.ESPIPE
- EROFS error = syscall.EROFS
- EMLINK error = syscall.EMLINK
- EPIPE error = syscall.EPIPE
- EAGAIN error = syscall.EAGAIN
- EDOM error = syscall.EDOM
- ERANGE error = syscall.ERANGE
- EADDRINUSE error = syscall.EADDRINUSE
- ECONNREFUSED error = syscall.ECONNREFUSED
- ENAMETOOLONG error = syscall.ENAMETOOLONG
- EAFNOSUPPORT error = syscall.EAFNOSUPPORT
- ETIMEDOUT error = syscall.ETIMEDOUT
- ENOTCONN error = syscall.ENOTCONN
-)
+// IsExist returns whether the error is known to report that a file already exists.
+// It is satisfied by ErrExist as well as some syscall errors.
+func IsExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.EEXIST || err == ErrExist
+}
+
+// IsNotExist returns whether the error is known to report that a file does not exist.
+// It is satisfied by ErrNotExist as well as some syscall errors.
+func IsNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.ENOENT || err == ErrNotExist
+}
+
+// IsPermission returns whether the error is known to report that permission is denied.
+// It is satisfied by ErrPermission as well as some syscall errors.
+func IsPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
+}
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index fe254672169..ebe92a9fba3 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -79,9 +79,9 @@ type Cmd struct {
// Process is the underlying process, once started.
Process *os.Process
- // Waitmsg contains information about an exited process,
+ // ProcessState contains information about an exited process,
// available after a call to Wait or Run.
- Waitmsg *os.Waitmsg
+ ProcessState *os.ProcessState
err error // last error (from LookPath, stdin, stdout, stderr)
finished bool // when Wait was called
@@ -266,11 +266,11 @@ func (c *Cmd) Start() error {
// An ExitError reports an unsuccessful exit by a command.
type ExitError struct {
- *os.Waitmsg
+ *os.ProcessState
}
func (e *ExitError) Error() string {
- return e.Waitmsg.String()
+ return e.ProcessState.String()
}
// Wait waits for the command to exit.
@@ -291,8 +291,8 @@ func (c *Cmd) Wait() error {
return errors.New("exec: Wait was already called")
}
c.finished = true
- msg, err := c.Process.Wait(0)
- c.Waitmsg = msg
+ state, err := c.Process.Wait()
+ c.ProcessState = state
var copyError error
for _ = range c.goroutine {
@@ -307,8 +307,8 @@ func (c *Cmd) Wait() error {
if err != nil {
return err
- } else if !msg.Exited() || msg.ExitStatus() != 0 {
- return &ExitError{msg}
+ } else if !state.Success() {
+ return &ExitError{state}
}
return copyError
diff --git a/libgo/go/os/exec/lp_plan9.go b/libgo/go/os/exec/lp_plan9.go
index d88cd0df959..0e229e03ee7 100644
--- a/libgo/go/os/exec/lp_plan9.go
+++ b/libgo/go/os/exec/lp_plan9.go
@@ -8,6 +8,7 @@ import (
"errors"
"os"
"strings"
+ "syscall"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
@@ -21,7 +22,7 @@ func findExecutable(file string) error {
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
- return os.EPERM
+ return syscall.EPERM
}
// LookPath searches for an executable binary named file
diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go
index 2d3a919dc6e..21632219972 100644
--- a/libgo/go/os/exec/lp_unix.go
+++ b/libgo/go/os/exec/lp_unix.go
@@ -23,7 +23,7 @@ func findExecutable(file string) error {
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
- return os.EPERM
+ return os.ErrPermission
}
// LookPath searches for an executable binary named file
diff --git a/libgo/go/os/exec/lp_windows.go b/libgo/go/os/exec/lp_windows.go
index b7efcd68b80..d8351d7e6d3 100644
--- a/libgo/go/os/exec/lp_windows.go
+++ b/libgo/go/os/exec/lp_windows.go
@@ -19,7 +19,7 @@ func chkStat(file string) error {
return err
}
if d.IsDir() {
- return os.EPERM
+ return os.ErrPermission
}
return nil
}
@@ -39,7 +39,7 @@ func findExecutable(file string, exts []string) (string, error) {
return f, nil
}
}
- return ``, os.ENOENT
+ return ``, os.ErrNotExist
}
// LookPath searches for an executable binary named file
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index 08f16b86d54..1c9e2b997f8 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -8,6 +8,7 @@ import (
"errors"
"runtime"
"syscall"
+ "time"
)
// StartProcess starts a new process with the program, arguments and attributes
@@ -20,18 +21,10 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
Sys: attr.Sys,
}
- // Create array of integer (system) fds.
- intfd := make([]int, len(attr.Files))
- for i, f := range attr.Files {
- if f == nil {
- intfd[i] = -1
- } else {
- intfd[i] = f.Fd()
- }
+ for _, f := range attr.Files {
+ sysattr.Files = append(sysattr.Files, f.Fd())
}
- sysattr.Files = intfd
-
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if e != nil {
return nil, &PathError{"fork/exec", name, e}
@@ -72,19 +65,13 @@ func (p *Process) Kill() error {
return e
}
-// Waitmsg stores the information about an exited process as reported by Wait.
-type Waitmsg struct {
- syscall.Waitmsg
-}
-
// Wait waits for the Process to exit or stop, and then returns a
-// Waitmsg describing its status and an error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-func (p *Process) Wait(options int) (w *Waitmsg, err error) {
+// ProcessState describing its status and an error, if any.
+func (p *Process) Wait() (ps *ProcessState, err error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
- return nil, EINVAL
+ return nil, ErrInvalid
}
for true {
@@ -100,21 +87,11 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
}
}
- return &Waitmsg{waitmsg}, nil
-}
-
-// Wait waits for process pid to exit or stop, and then returns a
-// Waitmsg describing its status and an error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-// Wait is equivalent to calling FindProcess and then Wait
-// and Release on the result.
-func Wait(pid int, options int) (w *Waitmsg, err error) {
- p, e := FindProcess(pid)
- if e != nil {
- return nil, e
+ ps = &ProcessState{
+ pid: waitmsg.Pid,
+ status: &waitmsg,
}
- defer p.Release()
- return p.Wait(options)
+ return ps, nil
}
// Release releases any resources associated with the Process.
@@ -131,9 +108,57 @@ func findProcess(pid int) (p *Process, err error) {
return newProcess(pid, 0), nil
}
-func (w *Waitmsg) String() string {
- if w == nil {
+// ProcessState stores information about process as reported by Wait.
+type ProcessState struct {
+ pid int // The process's id.
+ status *syscall.Waitmsg // System-dependent status info.
+}
+
+// Pid returns the process id of the exited process.
+func (p *ProcessState) Pid() int {
+ return p.pid
+}
+
+// Exited returns whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.status.Exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.status.ExitStatus() == 0
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as *syscall.Waitmsg on Plan 9, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.status
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Waitmsg on Plan 9, to access its contents.
+func (p *ProcessState) SysUsage() interface{} {
+ return p.status
+}
+
+// UserTime returns the user CPU time of the exited process and its children.
+// It is always reported as 0 on Windows.
+func (p *ProcessState) UserTime() time.Duration {
+ return time.Duration(p.status.Time[0]) * time.Millisecond
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+// It is always reported as 0 on Windows.
+func (p *ProcessState) SystemTime() time.Duration {
+ return time.Duration(p.status.Time[1]) * time.Millisecond
+}
+
+func (p *ProcessState) String() string {
+ if p == nil {
return "<nil>"
}
- return "exit status: " + w.Msg
+ return "exit status: " + p.status.Msg
}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 33a689eb045..4a75cb67fb5 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -42,32 +42,41 @@ func (p *Process) Kill() error {
return p.Signal(Kill)
}
-// TODO(rsc): Should os implement its own syscall.WaitStatus
-// wrapper with the methods, or is exposing the underlying one enough?
-//
-// TODO(rsc): Certainly need to have Rusage struct,
-// since syscall one might have different field types across
-// different OS.
-
-// Waitmsg stores the information about an exited process as reported by Wait.
-type Waitmsg struct {
- Pid int // The process's id.
- syscall.WaitStatus // System-dependent status info.
- Rusage *syscall.Rusage // System-dependent resource usage info.
+// ProcessState stores information about process as reported by Wait.
+type ProcessState struct {
+ pid int // The process's id.
+ status syscall.WaitStatus // System-dependent status info.
+ rusage *syscall.Rusage
}
-// Wait waits for process pid to exit or stop, and then returns a
-// Waitmsg describing its status and an error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-// Wait is equivalent to calling FindProcess and then Wait
-// and Release on the result.
-func Wait(pid int, options int) (w *Waitmsg, err error) {
- p, e := FindProcess(pid)
- if e != nil {
- return nil, e
- }
- defer p.Release()
- return p.Wait(options)
+// Pid returns the process id of the exited process.
+func (p *ProcessState) Pid() int {
+ return p.pid
+}
+
+// Exited returns whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.status.Exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.status.ExitStatus() == 0
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as syscall.WaitStatus on Unix, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.status
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Rusage on Unix, to access its contents.
+func (p *ProcessState) SysUsage() interface{} {
+ return p.rusage
}
// Convert i to decimal string.
@@ -97,26 +106,26 @@ func itod(i int) string {
return string(b[bp:])
}
-func (w *Waitmsg) String() string {
- if w == nil {
+func (p *ProcessState) String() string {
+ if p == nil {
return "<nil>"
}
- // TODO(austin) Use signal names when possible?
+ status := p.Sys().(syscall.WaitStatus)
res := ""
switch {
- case w.Exited():
- res = "exit status " + itod(w.ExitStatus())
- case w.Signaled():
- res = "signal " + itod(int(w.Signal()))
- case w.Stopped():
- res = "stop signal " + itod(int(w.StopSignal()))
- if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
- res += " (trap " + itod(w.TrapCause()) + ")"
+ case status.Exited():
+ res = "exit status " + itod(status.ExitStatus())
+ case status.Signaled():
+ res = "signal " + itod(int(status.Signal()))
+ case status.Stopped():
+ res = "stop signal " + itod(int(status.StopSignal()))
+ if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
+ res += " (trap " + itod(status.TrapCause()) + ")"
}
- case w.Continued():
+ case status.Continued():
res = "continued"
}
- if w.CoreDump() {
+ if status.CoreDump() {
res += " (core dumped)"
}
return res
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 7fe7c2fe8cd..8d000e9ef15 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -10,46 +10,30 @@ import (
"errors"
"runtime"
"syscall"
+ "time"
)
-// Options for Wait.
-const (
- WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
- WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
- WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
- WRUSAGE = 1 << 20 // Record resource usage.
-)
-
-// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
-// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
-// the options
-
// Wait waits for the Process to exit or stop, and then returns a
-// Waitmsg describing its status and an error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-func (p *Process) Wait(options int) (w *Waitmsg, err error) {
+// ProcessState describing its status and an error, if any.
+func (p *Process) Wait() (ps *ProcessState, err error) {
if p.Pid == -1 {
- return nil, EINVAL
+ return nil, syscall.EINVAL
}
var status syscall.WaitStatus
- var rusage *syscall.Rusage
- if options&WRUSAGE != 0 {
- rusage = new(syscall.Rusage)
- options ^= WRUSAGE
- }
- pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
+ var rusage syscall.Rusage
+ pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
if e != nil {
return nil, NewSyscallError("wait", e)
}
- // With WNOHANG pid is 0 if child has not exited.
- if pid1 != 0 && options&WSTOPPED == 0 {
+ if pid1 != 0 {
p.done = true
}
- w = new(Waitmsg)
- w.Pid = pid1
- w.WaitStatus = status
- w.Rusage = rusage
- return w, nil
+ ps = &ProcessState{
+ pid: pid1,
+ status: status,
+ rusage: &rusage,
+ }
+ return ps, nil
}
// Signal sends a signal to the Process.
@@ -80,3 +64,13 @@ func findProcess(pid int) (p *Process, err error) {
// NOOP for unix.
return newProcess(pid, 0), nil
}
+
+// UserTime returns the user CPU time of the exited process and its children.
+func (p *ProcessState) UserTime() time.Duration {
+ return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+func (p *ProcessState) SystemTime() time.Duration {
+ return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond
+}
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index f357a3034b1..dab0dc97571 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -8,12 +8,13 @@ import (
"errors"
"runtime"
"syscall"
+ "time"
"unsafe"
)
// Wait waits for the Process to exit or stop, and then returns a
-// Waitmsg describing its status and an error, if any.
-func (p *Process) Wait(options int) (w *Waitmsg, err error) {
+// ProcessState describing its status and an error, if any.
+func (p *Process) Wait() (ps *ProcessState, err error) {
s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
switch s {
case syscall.WAIT_OBJECT_0:
@@ -29,7 +30,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
p.done = true
- return &Waitmsg{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil
+ return &ProcessState{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil
}
// Signal sends a signal to the Process.
@@ -48,7 +49,7 @@ func (p *Process) Signal(sig Signal) error {
// Release releases any resources associated with the Process.
func (p *Process) Release() error {
if p.handle == uintptr(syscall.InvalidHandle) {
- return EINVAL
+ return syscall.EINVAL
}
e := syscall.CloseHandle(syscall.Handle(p.handle))
if e != nil {
@@ -83,3 +84,15 @@ func init() {
Args[i] = string(syscall.UTF16ToString((*v)[:]))
}
}
+
+// UserTime returns the user CPU time of the exited process and its children.
+// For now, it is always reported as 0 on Windows.
+func (p *ProcessState) UserTime() time.Duration {
+ return 0
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+// For now, it is always reported as 0 on Windows.
+func (p *ProcessState) SystemTime() time.Duration {
+ return 0
+}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 85f151e2840..1c3d0172d34 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -7,11 +7,33 @@
// Go-like; failing calls return values of type error rather than error numbers.
// Often, more information is available within the error. For example,
// if a call that takes a file name fails, such as Open or Stat, the error
-// will include failing file name when printed and will be of type *PathError,
-// which may be unpacked for more information.
+// will include the failing file name when printed and will be of type
+// *PathError, which may be unpacked for more information.
//
// The os interface is intended to be uniform across all operating systems.
// Features not generally available appear in the system-specific package syscall.
+//
+// Here is a simple example, opening a file and reading some of it.
+//
+// file, err := os.Open("file.go") // For read access.
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// If the open fails, the error string will be self-explanatory, like
+//
+// open file.go: no such file or directory
+//
+// The file's data can then be read into a slice of bytes. Read and
+// Write take their byte counts from the length of the artument slice.
+//
+// data := make([]byte, 100)
+// count, err := file.Read(data)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("read %d bytes: %q\n", count, data[:count])
+//
package os
import (
@@ -50,12 +72,25 @@ const (
SEEK_END int = 2 // seek relative to the end
)
+// LinkError records an error during a link or symlink or rename
+// system call and the paths that caused it.
+type LinkError struct {
+ Op string
+ Old string
+ New string
+ Err error
+}
+
+func (e *LinkError) Error() string {
+ return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
+}
+
// Read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
// EOF is signaled by a zero count with err set to io.EOF.
func (f *File) Read(b []byte) (n int, err error) {
if f == nil {
- return 0, EINVAL
+ return 0, ErrInvalid
}
n, e := f.read(b)
if n < 0 {
@@ -76,7 +111,7 @@ func (f *File) Read(b []byte) (n int, err error) {
// At end of file, that error is io.EOF.
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
if f == nil {
- return 0, EINVAL
+ return 0, ErrInvalid
}
for len(b) > 0 {
m, e := f.pread(b, off)
@@ -99,7 +134,7 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
if f == nil {
- return 0, EINVAL
+ return 0, ErrInvalid
}
n, e := f.write(b)
if n < 0 {
@@ -119,7 +154,7 @@ func (f *File) Write(b []byte) (n int, err error) {
// WriteAt returns a non-nil error when n != len(b).
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
if f == nil {
- return 0, EINVAL
+ return 0, ErrInvalid
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
@@ -153,7 +188,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
// an array of bytes.
func (f *File) WriteString(s string) (ret int, err error) {
if f == nil {
- return 0, EINVAL
+ return 0, ErrInvalid
}
return f.Write([]byte(s))
}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index fed2b809175..cb0e9ef9289 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -5,11 +5,14 @@
package os
import (
+ "errors"
"runtime"
"syscall"
"time"
)
+var ErrPlan9 = errors.New("unimplemented on Plan 9")
+
// File represents an open file descriptor.
type File struct {
*file
@@ -26,19 +29,20 @@ type file struct {
}
// Fd returns the integer Unix file descriptor referencing the open file.
-func (file *File) Fd() int {
- if file == nil {
- return -1
+func (f *File) Fd() uintptr {
+ if f == nil {
+ return ^(uintptr(0))
}
- return file.fd
+ return uintptr(f.fd)
}
// NewFile returns a new File with the given file descriptor and name.
-func NewFile(fd int, name string) *File {
- if fd < 0 {
+func NewFile(fd uintptr, name string) *File {
+ fdi := int(fd)
+ if fdi < 0 {
return nil
}
- f := &File{&file{fd: fd, name: name}}
+ f := &File{&file{fd: fdi, name: name}}
runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -128,7 +132,7 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
}
}
- return NewFile(fd, name), nil
+ return NewFile(uintptr(fd), name), nil
}
// Close closes the File, rendering it unusable for I/O.
@@ -139,7 +143,7 @@ func (file *File) Close() error {
func (file *file) close() error {
if file == nil || file.fd < 0 {
- return Ebadfd
+ return ErrInvalid
}
var err error
syscall.ForkLock.RLock()
@@ -202,7 +206,7 @@ func (f *File) Chmod(mode FileMode) error {
// of recently written data to disk.
func (f *File) Sync() (err error) {
if f == nil {
- return EINVAL
+ return ErrInvalid
}
var d Dir
@@ -272,7 +276,6 @@ func Remove(name string) error {
}
// Rename renames a file.
-// If there is an error, it will be of type *PathError.
func Rename(oldname, newname string) error {
var d Dir
d.Null()
@@ -330,34 +333,37 @@ func Pipe() (r *File, w *File, err error) {
}
syscall.ForkLock.RUnlock()
- return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+ return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
}
// not supported on Plan 9
// Link creates a hard link.
+// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
- return EPLAN9
+ return &LinkError{"link", oldname, newname, ErrPlan9}
}
+// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
- return EPLAN9
+ return &LinkError{"symlink", oldname, newname, ErrPlan9}
}
func Readlink(name string) (string, error) {
- return "", EPLAN9
+ return "", ErrPlan9
}
func Chown(name string, uid, gid int) error {
- return EPLAN9
+ return ErrPlan9
}
func Lchown(name string, uid, gid int) error {
- return EPLAN9
+ return ErrPlan9
}
func (f *File) Chown(uid, gid int) error {
- return EPLAN9
+ return ErrPlan9
}
// TempDir returns the default directory to use for temporary files.
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index 8d3a00b6c5a..073bd56a471 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -24,20 +24,8 @@ func epipecheck(file *File, e error) {
}
}
-// LinkError records an error during a link or symlink or rename
-// system call and the paths that caused it.
-type LinkError struct {
- Op string
- Old string
- New string
- Err error
-}
-
-func (e *LinkError) Error() string {
- return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
-}
-
// Link creates newname as a hard link to the oldname file.
+// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
e := syscall.Link(oldname, newname)
if e != nil {
@@ -47,6 +35,7 @@ func Link(oldname, newname string) error {
}
// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
e := syscall.Symlink(oldname, newname)
if e != nil {
@@ -160,7 +149,7 @@ func (f *File) Truncate(size int64) error {
// of recently written data to disk.
func (f *File) Sync() (err error) {
if f == nil {
- return EINVAL
+ return syscall.EINVAL
}
if e := syscall.Fsync(f.fd); e != nil {
return NewSyscallError("fsync", e)
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 3d659efe061..a69680cb8c9 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -89,7 +89,7 @@ func (f *File) Close() error {
func (file *file) close() error {
if file == nil || file.fd < 0 {
- return EINVAL
+ return syscall.EINVAL
}
var err error
if e := syscall.Close(file.fd); e != nil {
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index 56836434dbe..81d8fed926e 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -52,7 +52,7 @@ func Getwd() (pwd string, err error) {
pwd = ""
for parent := ".."; ; parent = "../" + parent {
if len(parent) >= 1024 { // Sanity check
- return "", ENAMETOOLONG
+ return "", syscall.ENAMETOOLONG
}
fd, err := Open(parent)
if err != nil {
@@ -74,7 +74,7 @@ func Getwd() (pwd string, err error) {
}
}
fd.Close()
- return "", ENOENT
+ return "", ErrNotExist
Found:
pd, err := fd.Stat()
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 27436dadcda..cff35fcef75 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -13,6 +13,7 @@ import (
"path/filepath"
"runtime"
"strings"
+ "syscall"
"testing"
"time"
)
@@ -538,7 +539,7 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
t.Errorf("exec %q returned %q wanted %q",
strings.Join(append([]string{cmd}, args...), " "), output, expect)
}
- p.Wait(0)
+ p.Wait()
}
func TestStartProcess(t *testing.T) {
@@ -767,7 +768,7 @@ func TestSeek(t *testing.T) {
for i, tt := range tests {
off, err := f.Seek(tt.in, tt.whence)
if off != tt.out || err != nil {
- if e, ok := err.(*PathError); ok && e.Err == EINVAL && tt.out > 1<<32 {
+ if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
// Reiserfs rejects the big seeks.
// http://code.google.com/p/go/issues/detail?id=91
break
@@ -787,17 +788,17 @@ var openErrorTests = []openErrorTest{
{
sfdir + "/no-such-file",
O_RDONLY,
- ENOENT,
+ syscall.ENOENT,
},
{
sfdir,
O_WRONLY,
- EISDIR,
+ syscall.EISDIR,
},
{
sfdir + "/" + sfname + "/no-such-file",
O_WRONLY,
- ENOTDIR,
+ syscall.ENOTDIR,
},
}
@@ -850,7 +851,7 @@ func run(t *testing.T, cmd []string) string {
var b bytes.Buffer
io.Copy(&b, r)
- _, err = p.Wait(0)
+ _, err = p.Wait()
if err != nil {
t.Fatalf("run hostname Wait: %v", err)
}
@@ -983,32 +984,31 @@ func TestAppend(t *testing.T) {
}
func TestStatDirWithTrailingSlash(t *testing.T) {
- // Create new dir, in _test so it will get
- // cleaned up by make if not by us.
- path := "_test/_TestStatDirWithSlash_"
- err := MkdirAll(path, 0777)
+ // Create new temporary directory and arrange to clean it up.
+ path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_")
if err != nil {
- t.Fatalf("MkdirAll %q: %s", path, err)
+ t.Fatalf("TempDir: %s", err)
}
defer RemoveAll(path)
// Stat of path should succeed.
_, err = Stat(path)
if err != nil {
- t.Fatal("stat failed:", err)
+ t.Fatalf("stat %s failed: %s", path, err)
}
// Stat of path+"/" should succeed too.
- _, err = Stat(path + "/")
+ path += "/"
+ _, err = Stat(path)
if err != nil {
- t.Fatal("stat failed:", err)
+ t.Fatalf("stat %s failed: %s", path, err)
}
}
-func TestNilWaitmsgString(t *testing.T) {
- var w *Waitmsg
- s := w.String()
+func TestNilProcessStateString(t *testing.T) {
+ var ps *ProcessState
+ s := ps.String()
if s != "<nil>" {
- t.Errorf("(*Waitmsg)(nil).String() = %q, want %q", s, "<nil>")
+ t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
}
}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index e962f3e397b..02a77ec8051 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -4,7 +4,10 @@
package os
-import "io"
+import (
+ "io"
+ "syscall"
+)
// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
@@ -20,7 +23,7 @@ func MkdirAll(path string, perm FileMode) error {
if dir.IsDir() {
return nil
}
- return &PathError{"mkdir", path, ENOTDIR}
+ return &PathError{"mkdir", path, syscall.ENOTDIR}
}
// Doesn't already exist; make sure parent does.
@@ -70,7 +73,7 @@ func RemoveAll(path string) error {
// Otherwise, is this a directory we need to recurse into?
dir, serr := Lstat(path)
if serr != nil {
- if serr, ok := serr.(*PathError); ok && (serr.Err == ENOENT || serr.Err == ENOTDIR) {
+ if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
return nil
}
return serr
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index 18634ba410e..c1e3fb35436 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -8,18 +8,18 @@ import (
. "os"
"path/filepath"
"runtime"
+ "syscall"
"testing"
)
func TestMkdirAll(t *testing.T) {
- // Create new dir, in _test so it will get
- // cleaned up by make if not by us.
- path := "_test/_TestMkdirAll_/dir/./dir2"
+ tmpDir := TempDir()
+ path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
- defer RemoveAll("_test/_TestMkdirAll_")
+ defer RemoveAll(tmpDir + "/_TestMkdirAll_")
// Already exists, should succeed.
err = MkdirAll(path, 0777)
@@ -63,7 +63,7 @@ func TestMkdirAll(t *testing.T) {
}
if runtime.GOOS == "windows" {
- path := `_test\_TestMkdirAll_\dir\.\dir2\`
+ path := tmpDir + `\_TestMkdirAll_\dir\.\dir2\`
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
@@ -72,8 +72,9 @@ func TestMkdirAll(t *testing.T) {
}
func TestRemoveAll(t *testing.T) {
+ tmpDir := TempDir()
// Work directory.
- path := "_test/_TestRemoveAll_"
+ path := tmpDir + "/_TestRemoveAll_"
fpath := path + "/file"
dpath := path + "/dir"
@@ -170,19 +171,22 @@ func TestMkdirAllWithSymlink(t *testing.T) {
return
}
- err := Mkdir("_test/dir", 0755)
+ tmpDir := TempDir()
+ dir := tmpDir + "/dir"
+ err := Mkdir(dir, 0755)
if err != nil {
- t.Fatal(`Mkdir "_test/dir":`, err)
+ t.Fatalf("Mkdir %s: %s", dir, err)
}
- defer RemoveAll("_test/dir")
+ defer RemoveAll(dir)
- err = Symlink("dir", "_test/link")
+ link := tmpDir + "/link"
+ err = Symlink("dir", link)
if err != nil {
- t.Fatal(`Symlink "dir", "_test/link":`, err)
+ t.Fatalf("Symlink %s: %s", link, err)
}
- defer RemoveAll("_test/link")
+ defer RemoveAll(link)
- path := "_test/link/foo"
+ path := link + "/foo"
err = MkdirAll(path, 0755)
if err != nil {
t.Errorf("MkdirAll %q: %s", path, err)
@@ -198,7 +202,7 @@ func TestMkdirAllAtSlash(t *testing.T) {
if err != nil {
pathErr, ok := err.(*PathError)
// common for users not to be able to write to /
- if ok && pathErr.Err == EACCES {
+ if ok && pathErr.Err == syscall.EACCES {
return
}
t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
diff --git a/libgo/go/os/signal/signal_stub.go b/libgo/go/os/signal/signal_stub.go
new file mode 100644
index 00000000000..fc227cf4c2d
--- /dev/null
+++ b/libgo/go/os/signal/signal_stub.go
@@ -0,0 +1,11 @@
+// Copyright 2012 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.
+
+// +build plan9
+
+package signal
+
+import "os"
+
+func enableSignal(sig os.Signal) {}
diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go
index 00622581f4f..a7990a359ec 100644
--- a/libgo/go/os/stat_plan9.go
+++ b/libgo/go/os/stat_plan9.go
@@ -62,7 +62,7 @@ func dirstat(arg interface{}) (d *Dir, err error) {
return nil, &PathError{"stat", name, err}
}
if n < syscall.STATFIXLEN {
- return nil, &PathError{"stat", name, Eshortstat}
+ return nil, &PathError{"stat", name, errShortStat}
}
// Pull the real size out of the stat message.
@@ -79,7 +79,7 @@ func dirstat(arg interface{}) (d *Dir, err error) {
return
}
}
- return nil, &PathError{"stat", name, Ebadstat}
+ return nil, &PathError{"stat", name, errBadStat}
}
// Stat returns a FileInfo structure describing the named file.
diff --git a/libgo/go/path/example_test.go b/libgo/go/path/example_test.go
index f0ac1301408..ca18b32305e 100644
--- a/libgo/go/path/example_test.go
+++ b/libgo/go/path/example_test.go
@@ -11,17 +11,11 @@ import (
"path"
)
-// b
func ExampleBase() {
fmt.Println(path.Base("/a/b"))
+ // Output: b
}
-// Clean("a/c") = "a/c"
-// Clean("a//c") = "a/c"
-// Clean("a/c/.") = "a/c"
-// Clean("a/c/b/..") = "a/c"
-// Clean("/../a/c") = "/a/c"
-// Clean("/../a/b/../././/c") = "/a/c"
func ExampleClean() {
paths := []string{
"a/c",
@@ -35,31 +29,39 @@ func ExampleClean() {
for _, p := range paths {
fmt.Printf("Clean(%q) = %q\n", p, path.Clean(p))
}
+
+ // Output:
+ // Clean("a/c") = "a/c"
+ // Clean("a//c") = "a/c"
+ // Clean("a/c/.") = "a/c"
+ // Clean("a/c/b/..") = "a/c"
+ // Clean("/../a/c") = "/a/c"
+ // Clean("/../a/b/../././/c") = "/a/c"
}
-// /a/b
func ExampleDir() {
fmt.Println(path.Dir("/a/b/c"))
+ // Output: /a/b
}
-// .css
func ExampleExt() {
fmt.Println(path.Ext("/a/b/c/bar.css"))
+ // Output: .css
}
-// true
func ExampleIsAbs() {
fmt.Println(path.IsAbs("/dev/null"))
+ // Output: true
}
-// a/b/c
func ExampleJoin() {
fmt.Println(path.Join("a", "b", "c"))
+ // Output: a/b/c
}
-// static/ myfile.css
func ExampleSplit() {
fmt.Println(path.Split("static/myfile.css"))
+ // Output: static/ myfile.css
}
*/
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go
index c3678f541d4..38d264fb97a 100644
--- a/libgo/go/path/filepath/match.go
+++ b/libgo/go/path/filepath/match.go
@@ -12,6 +12,7 @@ import (
"unicode/utf8"
)
+// ErrBadPattern indicates a globbing pattern was malformed.
var ErrBadPattern = errors.New("syntax error in pattern")
// Match returns true if name matches the shell file name pattern.
@@ -33,7 +34,8 @@ var ErrBadPattern = errors.New("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of name, not just a substring.
-// The only possible error return occurs when the pattern is malformed.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
//
func Match(pattern, name string) (matched bool, err error) {
Pattern:
@@ -211,7 +213,6 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
// if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/').
-// The only possible error return occurs when the pattern is malformed.
//
func Glob(pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
@@ -253,7 +254,6 @@ func Glob(pattern string) (matches []string, err error) {
// and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are
// added in lexicographical order.
-// The only possible error return occurs when the pattern is malformed.
func glob(dir, pattern string, matches []string) (m []string, e error) {
m = matches
fi, err := os.Stat(dir)
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index 3dc52aab467..f468d33264b 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -36,7 +36,7 @@ const (
// returns the string ".".
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
-// Getting Dot-Dot right,''
+// Getting Dot-Dot Right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string {
vol := VolumeName(path)
@@ -118,7 +118,8 @@ func Clean(path string) string {
}
// ToSlash returns the result of replacing each separator character
-// in path with a slash ('/') character.
+// in path with a slash ('/') character. Multiple separators are
+// replaced by multiple slashes.
func ToSlash(path string) string {
if Separator == '/' {
return path
@@ -127,7 +128,8 @@ func ToSlash(path string) string {
}
// FromSlash returns the result of replacing each slash ('/') character
-// in path with a separator character.
+// in path with a separator character. Multiple slashes are replaced
+// by multiple separators.
func FromSlash(path string) string {
if Separator == '/' {
return path
@@ -135,7 +137,8 @@ func FromSlash(path string) string {
return strings.Replace(path, "/", string(Separator), -1)
}
-// SplitList splits a list of paths joined by the OS-specific ListSeparator.
+// SplitList splits a list of paths joined by the OS-specific ListSeparator,
+// usually found in PATH or GOPATH environment variables.
func SplitList(path string) []string {
if path == "" {
return []string{}
@@ -158,7 +161,8 @@ func Split(path string) (dir, file string) {
}
// Join joins any number of path elements into a single path, adding
-// a Separator if necessary. All empty strings are ignored.
+// a Separator if necessary. The result is Cleaned, in particular
+// all empty strings are ignored.
func Join(elem ...string) string {
for i, e := range elem {
if e != "" {
@@ -183,7 +187,8 @@ func Ext(path string) string {
// EvalSymlinks returns the path name after the evaluation of any symbolic
// links.
-// If path is relative it will be evaluated relative to the current directory.
+// If path is relative the result will be relative to the current directory,
+// unless one of the components is an absolute symbolic link.
func EvalSymlinks(path string) (string, error) {
if runtime.GOOS == "windows" {
// Symlinks are not supported under windows.
@@ -443,7 +448,7 @@ func Base(path string) string {
return path
}
-// Dir returns the all but the last element of path, typically the path's directory.
+// Dir returns all but the last element of path, typically the path's directory.
// Trailing path separators are removed before processing.
// If the path is empty, Dir returns ".".
// If the path consists entirely of separators, Dir returns a single separator.
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index 36ab422c930..93cca1e4c2b 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -558,6 +558,7 @@ var EvalSymlinksTestDirs = []EvalSymlinksTest{
{"test/dir/link3", "../../"},
{"test/link1", "../test"},
{"test/link2", "dir"},
+ {"test/linkabs", "/"},
}
var EvalSymlinksTests = []EvalSymlinksTest{
@@ -570,6 +571,7 @@ var EvalSymlinksTests = []EvalSymlinksTest{
{"test/link2/..", "test"},
{"test/dir/link3", "."},
{"test/link2/link3/test", "test"},
+ {"test/linkabs", "/"},
}
var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
@@ -628,6 +630,9 @@ func TestEvalSymlinks(t *testing.T) {
for _, d := range tests {
path := simpleJoin(tmpDir, d.path)
dest := simpleJoin(tmpDir, d.dest)
+ if filepath.IsAbs(d.dest) {
+ dest = d.dest
+ }
if p, err := filepath.EvalSymlinks(path); err != nil {
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if filepath.Clean(p) != filepath.Clean(dest) {
diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go
index ba7e4de321e..8154bf60251 100644
--- a/libgo/go/path/match.go
+++ b/libgo/go/path/match.go
@@ -10,6 +10,7 @@ import (
"unicode/utf8"
)
+// ErrBadPattern indicates a globbing pattern was malformed.
var ErrBadPattern = errors.New("syntax error in pattern")
// Match returns true if name matches the shell file name pattern.
@@ -31,7 +32,8 @@ var ErrBadPattern = errors.New("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of name, not just a substring.
-// The only possible error return is when pattern is malformed.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
//
func Match(pattern, name string) (matched bool, err error) {
Pattern:
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
index 20d89c9ff0c..13abed0b09d 100644
--- a/libgo/go/path/path.go
+++ b/libgo/go/path/path.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package path implements utility routines for manipulating slash-separated
-// filename paths.
+// paths.
package path
import (
@@ -25,7 +25,7 @@ import (
// returns the string ".".
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
-// Getting Dot-Dot right,''
+// Getting Dot-Dot Right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string {
if path == "" {
@@ -100,17 +100,19 @@ func Clean(path string) string {
return string(buf[0:w])
}
-// Split splits path immediately following the final path separator,
+// Split splits path immediately following the final slash.
// separating it into a directory and file name component.
-// If there is no separator in path, Split returns an empty dir and
+// If there is no slash path, Split returns an empty dir and
// file set to path.
+// The returned values have the property that path = dir+file.
func Split(path string) (dir, file string) {
i := strings.LastIndex(path, "/")
return path[:i+1], path[i+1:]
}
// Join joins any number of path elements into a single path, adding a
-// separating slash if necessary. All empty strings are ignored.
+// separating slash if necessary. The result is Cleaned; in particular,
+// all empty strings are ignored.
func Join(elem ...string) string {
for i, e := range elem {
if e != "" {
@@ -161,11 +163,12 @@ func IsAbs(path string) bool {
return len(path) > 0 && path[0] == '/'
}
-// Dir returns the all but the last element of path, typically the path's directory.
-// Trailing path separators are removed before processing.
+// Dir returns all but the last element of path, typically the path's directory.
+// The path is Cleaned and trailing slashes are removed before processing.
// If the path is empty, Dir returns ".".
-// If the path consists entirely of separators, Dir returns a single separator.
-// The returned path does not end in a separator unless it is the root directory.
+// If the path consists entirely of slashes followed by non-slash bytes, Dir
+// returns a single slash. In any other case, the returned path does not end in a
+// slash.
func Dir(path string) string {
dir, _ := Split(path)
dir = Clean(dir)
diff --git a/libgo/go/runtime/debug.go b/libgo/go/runtime/debug.go
index bd6dcc971a1..b802fc63f71 100644
--- a/libgo/go/runtime/debug.go
+++ b/libgo/go/runtime/debug.go
@@ -26,23 +26,11 @@ func GOMAXPROCS(n int) int
// NumCPU returns the number of logical CPUs on the local machine.
func NumCPU() int
-// Cgocalls returns the number of cgo calls made by the current process.
-func Cgocalls() int64
+// NumCgoCall returns the number of cgo calls made by the current process.
+func NumCgoCall() int64
-// Goroutines returns the number of goroutines that currently exist.
-func Goroutines() int32
-
-// Alloc allocates a block of the given size.
-// FOR TESTING AND DEBUGGING ONLY.
-func Alloc(uintptr) *byte
-
-// Free frees the block starting at the given pointer.
-// FOR TESTING AND DEBUGGING ONLY.
-func Free(*byte)
-
-// Lookup returns the base and size of the block containing the given pointer.
-// FOR TESTING AND DEBUGGING ONLY.
-func Lookup(*byte) (*byte, uintptr)
+// NumGoroutine returns the number of goroutines that currently exist.
+func NumGoroutine() int
// MemProfileRate controls the fraction of memory allocations
// that are recorded and reported in the memory profile.
@@ -101,15 +89,14 @@ func (r *MemProfileRecord) Stack() []uintptr {
// of calling MemProfile directly.
func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
-// A ThreadProfileRecord describes the execution stack that
-// caused a new thread to be created.
-type ThreadProfileRecord struct {
+// A StackRecord describes a single execution stack.
+type StackRecord struct {
Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
}
// Stack returns the stack trace associated with the record,
// a prefix of r.Stack0.
-func (r *ThreadProfileRecord) Stack() []uintptr {
+func (r *StackRecord) Stack() []uintptr {
for i, v := range r.Stack0 {
if v == 0 {
return r.Stack0[0:i]
@@ -118,13 +105,21 @@ func (r *ThreadProfileRecord) Stack() []uintptr {
return r.Stack0[0:]
}
-// ThreadProfile returns n, the number of records in the current thread profile.
-// If len(p) >= n, ThreadProfile copies the profile into p and returns n, true.
-// If len(p) < n, ThreadProfile does not change p and returns n, false.
+// ThreadCreateProfile returns n, the number of records in the thread creation profile.
+// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
+// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
//
// Most clients should use the runtime/pprof package instead
-// of calling ThreadProfile directly.
-func ThreadProfile(p []ThreadProfileRecord) (n int, ok bool)
+// of calling ThreadCreateProfile directly.
+func ThreadCreateProfile(p []StackRecord) (n int, ok bool)
+
+// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
+// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
+// If len(p) < n, GoroutineProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling GoroutineProfile directly.
+func GoroutineProfile(p []StackRecord) (n int, ok bool)
// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
// blocking until data is available. If profiling is turned off and all the profile
@@ -142,3 +137,9 @@ func CPUProfile() []byte
// the testing package's -test.cpuprofile flag instead of calling
// SetCPUProfileRate directly.
func SetCPUProfileRate(hz int)
+
+// Stack formats a stack trace of the calling goroutine into buf
+// and returns the number of bytes written to buf.
+// If all is true, Stack formats stack traces of all other goroutines
+// into buf after the trace for the current goroutine.
+func Stack(buf []byte, all bool) int
diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go
index eafa2f19f19..5fbfe547e46 100644
--- a/libgo/go/runtime/extern.go
+++ b/libgo/go/runtime/extern.go
@@ -68,17 +68,6 @@ func funcline_go(*Func, uintptr) (string, int)
// mid returns the current os thread (m) id.
func mid() uint32
-// Semacquire waits until *s > 0 and then atomically decrements it.
-// It is intended as a simple sleep primitive for use by the synchronization
-// library and should not be used directly.
-func Semacquire(s *uint32)
-
-// Semrelease atomically increments *s and notifies a waiting goroutine
-// if one is blocked in Semacquire.
-// It is intended as a simple wakeup primitive for use by the synchronization
-// library and should not be used directly.
-func Semrelease(s *uint32)
-
// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
@@ -141,10 +130,10 @@ func Version() string {
return theVersion
}
-// GOOS is the Go tree's operating system target:
+// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos
-// GOARCH is the Go tree's architecture target:
+// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
diff --git a/gcc/testsuite/go.test/test/malloc1.go b/libgo/go/runtime/malloc1.go
index 0f7f0b267a0..da92f4c2fbf 100644
--- a/gcc/testsuite/go.test/test/malloc1.go
+++ b/libgo/go/runtime/malloc1.go
@@ -1,9 +1,9 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
-
// 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.
+// +build ignore
+
// trivial malloc test
package main
diff --git a/gcc/testsuite/go.test/test/mallocrand.go b/libgo/go/runtime/mallocrand.go
index 69d07cec5d2..f1bcb89cfa4 100644
--- a/gcc/testsuite/go.test/test/mallocrand.go
+++ b/libgo/go/runtime/mallocrand.go
@@ -1,9 +1,9 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
-
// 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.
+// +build ignore
+
// Random malloc test.
package main
diff --git a/gcc/testsuite/go.test/test/mallocrep.go b/libgo/go/runtime/mallocrep.go
index 4188da9b833..03ee71edb42 100644
--- a/gcc/testsuite/go.test/test/mallocrep.go
+++ b/libgo/go/runtime/mallocrep.go
@@ -1,11 +1,11 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
-
// 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.
// Repeated malloc test.
+// +build ignore
+
package main
import (
diff --git a/gcc/testsuite/go.test/test/mallocrep1.go b/libgo/go/runtime/mallocrep1.go
index f9d7286efd9..41c104c0ba7 100644
--- a/gcc/testsuite/go.test/test/mallocrep1.go
+++ b/libgo/go/runtime/mallocrep1.go
@@ -1,9 +1,9 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
-
// 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.
+// +build ignore
+
// Repeated malloc test.
package main
diff --git a/libgo/go/runtime/mem.go b/libgo/go/runtime/mem.go
index 1301674c027..95e8aa7a533 100644
--- a/libgo/go/runtime/mem.go
+++ b/libgo/go/runtime/mem.go
@@ -17,11 +17,12 @@ type MemStats struct {
Frees uint64 // number of frees
// Main allocation heap statistics.
- HeapAlloc uint64 // bytes allocated and still in use
- HeapSys uint64 // bytes obtained from system
- HeapIdle uint64 // bytes in idle spans
- HeapInuse uint64 // bytes in non-idle span
- HeapObjects uint64 // total number of allocated objects
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapReleased uint64 // bytes released to the OS
+ HeapObjects uint64 // total number of allocated objects
// Low-level fixed-size structure allocator statistics.
// Inuse is bytes used now.
@@ -35,7 +36,8 @@ type MemStats struct {
BuckHashSys uint64 // profiling bucket hash table
// Garbage collector statistics.
- NextGC uint64
+ NextGC uint64 // next run in HeapAlloc time (bytes)
+ LastGC uint64 // last run in absolute time (ns)
PauseTotalNs uint64
PauseNs [256]uint64 // most recent GC pause times
NumGC uint32
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 42f04f320a7..099bb6a92f9 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -10,19 +10,354 @@ package pprof
import (
"bufio"
+ "bytes"
"fmt"
"io"
"runtime"
+ "sort"
+ "strings"
"sync"
+ "text/tabwriter"
)
// BUG(rsc): CPU profiling is broken on OS X, due to an Apple kernel bug.
// For details, see http://code.google.com/p/go/source/detail?r=35b716c94225.
-// WriteHeapProfile writes a pprof-formatted heap profile to w.
-// If a write to w returns an error, WriteHeapProfile returns that error.
-// Otherwise, WriteHeapProfile returns nil.
+// A Profile is a collection of stack traces showing the call sequences
+// that led to instances of a particular event, such as allocation.
+// Packages can create and maintain their own profiles; the most common
+// use is for tracking resources that must be explicitly closed, such as files
+// or network connections.
+//
+// A Profile's methods can be called from multiple goroutines simultaneously.
+//
+// Each Profile has a unique name. A few profiles are predefined:
+//
+// goroutine - stack traces of all current goroutines
+// heap - a sampling of all heap allocations
+// threadcreate - stack traces that led to the creation of new OS threads
+//
+// These predefine profiles maintain themselves and panic on an explicit
+// Add or Remove method call.
+//
+// The CPU profile is not available as a Profile. It has a special API,
+// the StartCPUProfile and StopCPUProfile functions, because it streams
+// output to a writer during profiling.
+//
+type Profile struct {
+ name string
+ mu sync.Mutex
+ m map[interface{}][]uintptr
+ count func() int
+ write func(io.Writer, int) error
+}
+
+// profiles records all registered profiles.
+var profiles struct {
+ mu sync.Mutex
+ m map[string]*Profile
+}
+
+var goroutineProfile = &Profile{
+ name: "goroutine",
+ count: countGoroutine,
+ write: writeGoroutine,
+}
+
+var threadcreateProfile = &Profile{
+ name: "threadcreate",
+ count: countThreadCreate,
+ write: writeThreadCreate,
+}
+
+var heapProfile = &Profile{
+ name: "heap",
+ count: countHeap,
+ write: writeHeap,
+}
+
+func lockProfiles() {
+ profiles.mu.Lock()
+ if profiles.m == nil {
+ // Initial built-in profiles.
+ profiles.m = map[string]*Profile{
+ "goroutine": goroutineProfile,
+ "threadcreate": threadcreateProfile,
+ "heap": heapProfile,
+ }
+ }
+}
+
+func unlockProfiles() {
+ profiles.mu.Unlock()
+}
+
+// NewProfile creates a new profile with the given name.
+// If a profile with that name already exists, NewProfile panics.
+// The convention is to use a 'import/path.' prefix to create
+// separate name spaces for each package.
+func NewProfile(name string) *Profile {
+ lockProfiles()
+ defer unlockProfiles()
+ if name == "" {
+ panic("pprof: NewProfile with empty name")
+ }
+ if profiles.m[name] != nil {
+ panic("pprof: NewProfile name already in use: " + name)
+ }
+ p := &Profile{
+ name: name,
+ m: map[interface{}][]uintptr{},
+ }
+ profiles.m[name] = p
+ return p
+}
+
+// Lookup returns the profile with the given name, or nil if no such profile exists.
+func Lookup(name string) *Profile {
+ lockProfiles()
+ defer unlockProfiles()
+ return profiles.m[name]
+}
+
+// Profiles returns a slice of all the known profiles, sorted by name.
+func Profiles() []*Profile {
+ lockProfiles()
+ defer unlockProfiles()
+
+ var all []*Profile
+ for _, p := range profiles.m {
+ all = append(all, p)
+ }
+
+ sort.Sort(byName(all))
+ return all
+}
+
+type byName []*Profile
+
+func (x byName) Len() int { return len(x) }
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byName) Less(i, j int) bool { return x[i].name < x[j].name }
+
+// Name returns this profile's name, which can be passed to Lookup to reobtain the profile.
+func (p *Profile) Name() string {
+ return p.name
+}
+
+// Count returns the number of execution stacks currently in the profile.
+func (p *Profile) Count() int {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.count != nil {
+ return p.count()
+ }
+ return len(p.m)
+}
+
+// Add adds the current execution stack to the profile, associated with value.
+// Add stores value in an internal map, so value must be suitable for use as
+// a map key and will not be garbage collected until the corresponding
+// call to Remove. Add panics if the profile already contains a stack for value.
+//
+// The skip parameter has the same meaning as runtime.Caller's skip
+// and controls where the stack trace begins. Passing skip=0 begins the
+// trace in the function calling Add. For example, given this
+// execution stack:
+//
+// Add
+// called from rpc.NewClient
+// called from mypkg.Run
+// called from main.main
+//
+// Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient.
+// Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run.
+//
+func (p *Profile) Add(value interface{}, skip int) {
+ if p.name == "" {
+ panic("pprof: use of uninitialized Profile")
+ }
+ if p.write != nil {
+ panic("pprof: Add called on built-in Profile " + p.name)
+ }
+
+ stk := make([]uintptr, 32)
+ n := runtime.Callers(skip+1, stk[:])
+
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.m[value] != nil {
+ panic("pprof: Profile.Add of duplicate value")
+ }
+ p.m[value] = stk[:n]
+}
+
+// Remove removes the execution stack associated with value from the profile.
+// It is a no-op if the value is not in the profile.
+func (p *Profile) Remove(value interface{}) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ delete(p.m, value)
+}
+
+// WriteTo writes a pprof-formatted snapshot of the profile to w.
+// If a write to w returns an error, WriteTo returns that error.
+// Otherwise, WriteTo returns nil.
+//
+// The debug parameter enables additional output.
+// Passing debug=0 prints only the hexadecimal addresses that pprof needs.
+// Passing debug=1 adds comments translating addresses to function names
+// and line numbers, so that a programmer can read the profile without tools.
+//
+// The predefined profiles may assign meaning to other debug values;
+// for example, when printing the "goroutine" profile, debug=2 means to
+// print the goroutine stacks in the same form that a Go program uses
+// when dying due to an unrecovered panic.
+func (p *Profile) WriteTo(w io.Writer, debug int) error {
+ if p.name == "" {
+ panic("pprof: use of zero Profile")
+ }
+ if p.write != nil {
+ return p.write(w, debug)
+ }
+
+ // Obtain consistent snapshot under lock; then process without lock.
+ var all [][]uintptr
+ p.mu.Lock()
+ for _, stk := range p.m {
+ all = append(all, stk)
+ }
+ p.mu.Unlock()
+
+ // Map order is non-deterministic; make output deterministic.
+ sort.Sort(stackProfile(all))
+
+ return printCountProfile(w, debug, p.name, stackProfile(all))
+}
+
+type stackProfile [][]uintptr
+
+func (x stackProfile) Len() int { return len(x) }
+func (x stackProfile) Stack(i int) []uintptr { return x[i] }
+func (x stackProfile) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x stackProfile) Less(i, j int) bool {
+ t, u := x[i], x[j]
+ for k := 0; k < len(t) && k < len(u); k++ {
+ if t[k] != u[k] {
+ return t[k] < u[k]
+ }
+ }
+ return len(t) < len(u)
+}
+
+// A countProfile is a set of stack traces to be printed as counts
+// grouped by stack trace. There are multiple implementations:
+// all that matters is that we can find out how many traces there are
+// and obtain each trace in turn.
+type countProfile interface {
+ Len() int
+ Stack(i int) []uintptr
+}
+
+// printCountProfile prints a countProfile at the specified debug level.
+func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
+ fmt.Fprintf(w, "%s profile: total %d\n", name, p.Len())
+
+ // Build count of each stack.
+ var buf bytes.Buffer
+ key := func(stk []uintptr) string {
+ buf.Reset()
+ fmt.Fprintf(&buf, "@")
+ for _, pc := range stk {
+ fmt.Fprintf(&buf, " %#x", pc)
+ }
+ return buf.String()
+ }
+ m := map[string]int{}
+ n := p.Len()
+ for i := 0; i < n; i++ {
+ m[key(p.Stack(i))]++
+ }
+
+ // Print stacks, listing count on first occurrence of a unique stack.
+ for i := 0; i < n; i++ {
+ stk := p.Stack(i)
+ s := key(stk)
+ if count := m[s]; count != 0 {
+ fmt.Fprintf(w, "%d %s\n", count, s)
+ if debug > 0 {
+ printStackRecord(w, stk, false)
+ }
+ delete(m, s)
+ }
+ }
+
+ if tw != nil {
+ tw.Flush()
+ }
+ return b.Flush()
+}
+
+// printStackRecord prints the function + source line information
+// for a single stack trace.
+func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
+ show := allFrames
+ for _, pc := range stk {
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ show = true
+ fmt.Fprintf(w, "#\t%#x\n", pc)
+ } else {
+ file, line := f.FileLine(pc)
+ name := f.Name()
+ // Hide runtime.goexit and any runtime functions at the beginning.
+ // This is useful mainly for allocation traces.
+ if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
+ continue
+ }
+ show = true
+ fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, f.Name(), pc-f.Entry(), file, line)
+ }
+ }
+ if !show {
+ // We didn't print anything; do it again,
+ // and this time include runtime functions.
+ printStackRecord(w, stk, true)
+ return
+ }
+ fmt.Fprintf(w, "\n")
+}
+
+// Interface to system profiles.
+
+type byInUseBytes []runtime.MemProfileRecord
+
+func (x byInUseBytes) Len() int { return len(x) }
+func (x byInUseBytes) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byInUseBytes) Less(i, j int) bool { return x[i].InUseBytes() > x[j].InUseBytes() }
+
+// WriteHeapProfile is shorthand for Lookup("heap").WriteTo(w, 0).
+// It is preserved for backwards compatibility.
func WriteHeapProfile(w io.Writer) error {
+ return writeHeap(w, 0)
+}
+
+// countHeap returns the number of records in the heap profile.
+func countHeap() int {
+ n, _ := runtime.MemProfile(nil, false)
+ return n
+}
+
+// writeHeapProfile writes the current runtime heap profile to w.
+func writeHeap(w io.Writer, debug int) error {
// Find out how many records there are (MemProfile(nil, false)),
// allocate that many records, and get the data.
// There's a race—more records might be added between
@@ -44,6 +379,16 @@ func WriteHeapProfile(w io.Writer) error {
// Profile grew; try again.
}
+ sort.Sort(byInUseBytes(p))
+
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
var total runtime.MemProfileRecord
for i := range p {
r := &p[i]
@@ -56,78 +401,120 @@ func WriteHeapProfile(w io.Writer) error {
// Technically the rate is MemProfileRate not 2*MemProfileRate,
// but early versions of the C++ heap profiler reported 2*MemProfileRate,
// so that's what pprof has come to expect.
- b := bufio.NewWriter(w)
- fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
+ fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
total.InUseObjects(), total.InUseBytes(),
total.AllocObjects, total.AllocBytes,
2*runtime.MemProfileRate)
for i := range p {
r := &p[i]
- fmt.Fprintf(b, "%d: %d [%d: %d] @",
+ fmt.Fprintf(w, "%d: %d [%d: %d] @",
r.InUseObjects(), r.InUseBytes(),
r.AllocObjects, r.AllocBytes)
for _, pc := range r.Stack() {
- fmt.Fprintf(b, " %#x", pc)
+ fmt.Fprintf(w, " %#x", pc)
+ }
+ fmt.Fprintf(w, "\n")
+ if debug > 0 {
+ printStackRecord(w, r.Stack(), false)
}
- fmt.Fprintf(b, "\n")
}
// Print memstats information too.
- // Pprof will ignore, but useful for people.
- s := new(runtime.MemStats)
- runtime.ReadMemStats(s)
- fmt.Fprintf(b, "\n# runtime.MemStats\n")
- fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
- fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
- fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
- fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
- fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
-
- fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
- fmt.Fprintf(b, "# HeapSys = %d\n", s.HeapSys)
- fmt.Fprintf(b, "# HeapIdle = %d\n", s.HeapIdle)
- fmt.Fprintf(b, "# HeapInuse = %d\n", s.HeapInuse)
-
- fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
- fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
- fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
- fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys)
-
- fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
- fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
- fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
- fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
- fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
-
- fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
- fmt.Fprintf(b, "# (Excluding large blocks.)\n")
- for _, t := range s.BySize {
- if t.Mallocs > 0 {
- fmt.Fprintf(b, "# %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
- }
+ // Pprof will ignore, but useful for people
+ if debug > 0 {
+ s := new(runtime.MemStats)
+ runtime.ReadMemStats(s)
+ fmt.Fprintf(w, "\n# runtime.MemStats\n")
+ fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
+ fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
+ fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
+ fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
+ fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
+
+ fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
+ fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
+ fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
+ fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
+
+ fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+ fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+ fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+ fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+ fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+ fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+ fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+ fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
+ fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
+ }
+
+ if tw != nil {
+ tw.Flush()
}
return b.Flush()
}
-// WriteThreadProfile writes a pprof-formatted thread creation profile to w.
-// If a write to w returns an error, WriteThreadProfile returns that error.
-// Otherwise, WriteThreadProfile returns nil.
-func WriteThreadProfile(w io.Writer) error {
- // Find out how many records there are (ThreadProfile(nil)),
+// countThreadCreate returns the size of the current ThreadCreateProfile.
+func countThreadCreate() int {
+ n, _ := runtime.ThreadCreateProfile(nil)
+ return n
+}
+
+// writeThreadCreate writes the current runtime ThreadCreateProfile to w.
+func writeThreadCreate(w io.Writer, debug int) error {
+ return writeRuntimeProfile(w, debug, "threadcreate", runtime.ThreadCreateProfile)
+}
+
+// countGoroutine returns the number of goroutines.
+func countGoroutine() int {
+ return runtime.NumGoroutine()
+}
+
+// writeGoroutine writes the current runtime GoroutineProfile to w.
+func writeGoroutine(w io.Writer, debug int) error {
+ if debug >= 2 {
+ return writeGoroutineStacks(w)
+ }
+ return writeRuntimeProfile(w, debug, "goroutine", runtime.GoroutineProfile)
+}
+
+func writeGoroutineStacks(w io.Writer) error {
+ // We don't know how big the buffer needs to be to collect
+ // all the goroutines. Start with 1 MB and try a few times, doubling each time.
+ // Give up and use a truncated trace if 64 MB is not enough.
+ buf := make([]byte, 1<<20)
+ for i := 0; ; i++ {
+ n := runtime.Stack(buf, true)
+ if n < len(buf) {
+ buf = buf[:n]
+ break
+ }
+ if len(buf) >= 64<<20 {
+ // Filled 64 MB - stop there.
+ break
+ }
+ buf = make([]byte, 2*len(buf))
+ }
+ _, err := w.Write(buf)
+ return err
+}
+
+func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord) (int, bool)) error {
+ // Find out how many records there are (fetch(nil)),
// allocate that many records, and get the data.
- // There's a race—more records (threads) might be added between
+ // There's a race—more records might be added between
// the two calls—so allocate a few extra records for safety
// and also try again if we're very unlucky.
// The loop should only execute one iteration in the common case.
- var p []runtime.ThreadProfileRecord
- n, ok := runtime.ThreadProfile(nil)
+ var p []runtime.StackRecord
+ n, ok := fetch(nil)
for {
// Allocate room for a slightly bigger profile,
// in case a few more entries have been added
// since the call to ThreadProfile.
- p = make([]runtime.ThreadProfileRecord, n+10)
- n, ok = runtime.ThreadProfile(p)
+ p = make([]runtime.StackRecord, n+10)
+ n, ok = fetch(p)
if ok {
p = p[0:n]
break
@@ -135,19 +522,14 @@ func WriteThreadProfile(w io.Writer) error {
// Profile grew; try again.
}
- b := bufio.NewWriter(w)
- fmt.Fprintf(b, "thread creation profile: %d threads\n", n)
- for i := range p {
- r := &p[i]
- fmt.Fprintf(b, "@")
- for _, pc := range r.Stack() {
- fmt.Fprintf(b, " %#x", pc)
- }
- fmt.Fprintf(b, "\n")
- }
- return b.Flush()
+ return printCountProfile(w, debug, name, runtimeProfile(p))
}
+type runtimeProfile []runtime.StackRecord
+
+func (p runtimeProfile) Len() int { return len(p) }
+func (p runtimeProfile) Stack(i int) []uintptr { return p[i].Stack() }
+
var cpu struct {
sync.Mutex
profiling bool
diff --git a/libgo/go/sort/example_interface_test.go b/libgo/go/sort/example_interface_test.go
new file mode 100644
index 00000000000..4c88821be7c
--- /dev/null
+++ b/libgo/go/sort/example_interface_test.go
@@ -0,0 +1,77 @@
+// Copyright 2011 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 sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+type Grams int
+
+func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }
+
+type Organ struct {
+ Name string
+ Weight Grams
+}
+
+type Organs []*Organ
+
+func (s Organs) Len() int { return len(s) }
+func (s Organs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// ByName implements sort.Interface by providing Less and using the Len and
+// Swap methods of the embedded Organs value.
+type ByName struct{ Organs }
+
+func (s ByName) Less(i, j int) bool { return s.Organs[i].Name < s.Organs[j].Name }
+
+// ByWeight implements sort.Interface by providing Less and using the Len and
+// Swap methods of the embedded Organs value.
+type ByWeight struct{ Organs }
+
+func (s ByWeight) Less(i, j int) bool { return s.Organs[i].Weight < s.Organs[j].Weight }
+
+func ExampleInterface() {
+ s := []*Organ{
+ {"brain", 1340},
+ {"heart", 290},
+ {"liver", 1494},
+ {"pancreas", 131},
+ {"prostate", 62},
+ {"spleen", 162},
+ }
+
+ sort.Sort(ByWeight{s})
+ fmt.Println("Organs by weight:")
+ printOrgans(s)
+
+ sort.Sort(ByName{s})
+ fmt.Println("Organs by name:")
+ printOrgans(s)
+
+ // Output:
+ // Organs by weight:
+ // prostate (62g)
+ // pancreas (131g)
+ // spleen (162g)
+ // heart (290g)
+ // brain (1340g)
+ // liver (1494g)
+ // Organs by name:
+ // brain (1340g)
+ // heart (290g)
+ // liver (1494g)
+ // pancreas (131g)
+ // prostate (62g)
+ // spleen (162g)
+}
+
+func printOrgans(s []*Organ) {
+ for _, o := range s {
+ fmt.Printf("%-8s (%v)\n", o.Name, o.Weight)
+ }
+}
diff --git a/libgo/go/sort/example_reverse_test.go b/libgo/go/sort/example_reverse_test.go
new file mode 100644
index 00000000000..7c7f05bf3a2
--- /dev/null
+++ b/libgo/go/sort/example_reverse_test.go
@@ -0,0 +1,30 @@
+// Copyright 2011 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 sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+// Reverse embeds a sort.Interface value and implements a reverse sort over
+// that value.
+type Reverse struct {
+ // This embedded Interface permits Reverse to use the methods of
+ // another Interface implementation.
+ sort.Interface
+}
+
+// Less returns the opposite of the embedded implementation's Less method.
+func (r Reverse) Less(i, j int) bool {
+ return r.Interface.Less(j, i)
+}
+
+func ExampleInterface_reverse() {
+ s := []int{5, 2, 6, 3, 1, 4} // unsorted
+ sort.Sort(Reverse{sort.IntSlice(s)})
+ fmt.Println(s)
+ // Output: [6 5 4 3 2 1]
+}
diff --git a/libgo/go/sort/example_test.go b/libgo/go/sort/example_test.go
index 2224db7e13c..f57d02546f7 100644
--- a/libgo/go/sort/example_test.go
+++ b/libgo/go/sort/example_test.go
@@ -9,9 +9,9 @@ import (
"sort"
)
-// [1 2 3 4 5 6]
func ExampleInts() {
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(s)
fmt.Println(s)
+ // Output: [1 2 3 4 5 6]
}
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index cd3031b0e61..d99117bed1d 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -13,6 +13,7 @@ package strconv
// 3) Multiply by 2^precision and round to get mantissa.
import "math"
+import "runtime"
var optimize = true // can change for testing
@@ -300,6 +301,11 @@ func (d *decimal) atof64() (f float64, ok bool) {
if d.nd > 15 {
return
}
+ // gccgo gets this wrong on 32-bit i386 when not using -msse.
+ // See TestRoundTrip in atof_test.go for a test case.
+ if runtime.GOARCH == "386" {
+ return
+ }
switch {
case d.dp == d.nd: // int
f := d.atof64int()
diff --git a/libgo/go/strconv/itoa_test.go b/libgo/go/strconv/itoa_test.go
index bac23e6ea67..63d2fa44e02 100644
--- a/libgo/go/strconv/itoa_test.go
+++ b/libgo/go/strconv/itoa_test.go
@@ -127,6 +127,7 @@ func TestUitoa(t *testing.T) {
}
func numAllocations(f func()) int {
+ runtime.GC()
memstats := new(runtime.MemStats)
runtime.ReadMemStats(memstats)
n0 := memstats.Mallocs
diff --git a/libgo/go/strings/example_test.go b/libgo/go/strings/example_test.go
index 5ef0b93d15e..0b583411331 100644
--- a/libgo/go/strings/example_test.go
+++ b/libgo/go/strings/example_test.go
@@ -9,134 +9,142 @@ import (
"strings"
)
-// Fields are: ["foo" "bar" "baz"]
func ExampleFields() {
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
+ // Output: Fields are: ["foo" "bar" "baz"]
}
-// true
-// false
-// true
-// true
func ExampleContains() {
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
fmt.Println(strings.Contains("seafood", ""))
fmt.Println(strings.Contains("", ""))
+ // Output:
+ // true
+ // false
+ // true
+ // true
}
-// false
-// true
-// false
-// false
func ExampleContainsAny() {
fmt.Println(strings.ContainsAny("team", "i"))
fmt.Println(strings.ContainsAny("failure", "u & i"))
fmt.Println(strings.ContainsAny("foo", ""))
fmt.Println(strings.ContainsAny("", ""))
-
+ // Output:
+ // false
+ // true
+ // false
+ // false
}
-// 3
-// 5
func ExampleCount() {
fmt.Println(strings.Count("cheese", "e"))
fmt.Println(strings.Count("five", "")) // before & after each rune
+ // Output:
+ // 3
+ // 5
}
-// true
func ExampleEqualFold() {
fmt.Println(strings.EqualFold("Go", "go"))
+ // Output: true
}
-// 4
-// -1
func ExampleIndex() {
fmt.Println(strings.Index("chicken", "ken"))
fmt.Println(strings.Index("chicken", "dmr"))
+ // Output:
+ // 4
+ // -1
}
-// 4
-// -1
func ExampleRune() {
fmt.Println(strings.IndexRune("chicken", 'k'))
fmt.Println(strings.IndexRune("chicken", 'd'))
+ // Output:
+ // 4
+ // -1
}
-// 0
-// 3
-// -1
func ExampleLastIndex() {
fmt.Println(strings.Index("go gopher", "go"))
fmt.Println(strings.LastIndex("go gopher", "go"))
fmt.Println(strings.LastIndex("go gopher", "rodent"))
+ // Output:
+ // 0
+ // 3
+ // -1
}
-// foo, bar, baz
func ExampleJoin() {
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))
+ // Output: foo, bar, baz
}
-// banana
func ExampleRepeat() {
fmt.Println("ba" + strings.Repeat("na", 2))
+ // Output: banana
}
-// oinky oinky oink
-// moo moo moo
func ExampleReplace() {
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
+ // Output:
+ // oinky oinky oink
+ // moo moo moo
}
-// ["a" "b" "c"]
-// ["" "man " "plan " "canal panama"]
-// [" " "x" "y" "z" " "]
-// [""]
func ExampleSplit() {
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
fmt.Printf("%q\n", strings.Split(" xyz ", ""))
fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
+ // Output:
+ // ["a" "b" "c"]
+ // ["" "man " "plan " "canal panama"]
+ // [" " "x" "y" "z" " "]
+ // [""]
}
-// ["a" "b,c"]
-// [] (nil = true)
func ExampleSplitN() {
fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
z := strings.SplitN("a,b,c", ",", 0)
fmt.Printf("%q (nil = %v)\n", z, z == nil)
+ // Output:
+ // ["a" "b,c"]
+ // [] (nil = true)
}
-// ["a," "b," "c"]
func ExampleSplitAfter() {
fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
+ // Output: ["a," "b," "c"]
}
-// ["a," "b,c"]
func ExampleSplitAfterN() {
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
+ // Output: ["a," "b,c"]
}
-// Her Royal Highness
func ExampleTitle() {
fmt.Println(strings.Title("her royal highness"))
+ // Output: Her Royal Highness
}
-// LOUD NOISES
-// ХЛЕБ
func ExampleToTitle() {
fmt.Println(strings.ToTitle("loud noises"))
fmt.Println(strings.ToTitle("хлеб"))
+ // Output:
+ // LOUD NOISES
+ // ХЛЕБ
}
-// [Achtung]
func ExampleTrim() {
- fmt.Printf("[%s]", strings.Trim(" !!! Achtung !!! ", "! "))
+ fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
+ // Output: ["Achtung"]
}
-// 'Gjnf oevyyvt naq gur fyvgul tbcure...
func ExampleMap() {
rot13 := func(r rune) rune {
switch {
@@ -148,25 +156,26 @@ func ExampleMap() {
return r
}
fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
+ // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
}
-// a lone gopher
func ExampleTrimSpace() {
fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
+ // Output: a lone gopher
}
-// This is &lt;b&gt;HTML&lt;/b&gt;!
func ExampleNewReplacer() {
r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
fmt.Println(r.Replace("This is <b>HTML</b>!"))
+ // Output: This is &lt;b&gt;HTML&lt;/b&gt;!
}
-// GOPHER
func ExampleToUpper() {
fmt.Println(strings.ToUpper("Gopher"))
+ // Output: GOPHER
}
-// gopher
func ExampleToLower() {
fmt.Println(strings.ToLower("Gopher"))
+ // Output: gopher
}
diff --git a/libgo/go/sync/cond.go b/libgo/go/sync/cond.go
index 75494b53536..1fc3deaf1e0 100644
--- a/libgo/go/sync/cond.go
+++ b/libgo/go/sync/cond.go
@@ -4,8 +4,6 @@
package sync
-import "runtime"
-
// Cond implements a condition variable, a rendezvous point
// for goroutines waiting for or announcing the occurrence
// of an event.
@@ -43,9 +41,10 @@ func NewCond(l Locker) *Cond {
// Wait atomically unlocks c.L and suspends execution
// of the calling goroutine. After later resuming execution,
-// Wait locks c.L before returning.
+// Wait locks c.L before returning. Unlike in other systems,
+// Wait cannot return unless awoken by Broadcast or Signal.
//
-// Because L is not locked when Wait first resumes, the caller
+// Because c.L is not locked when Wait first resumes, the caller
// typically cannot assume that the condition is true when
// Wait returns. Instead, the caller should Wait in a loop:
//
@@ -65,7 +64,7 @@ func (c *Cond) Wait() {
c.newWaiters++
c.m.Unlock()
c.L.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
c.L.Lock()
}
@@ -84,7 +83,7 @@ func (c *Cond) Signal() {
}
if c.oldWaiters > 0 {
c.oldWaiters--
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.m.Unlock()
}
@@ -98,13 +97,13 @@ func (c *Cond) Broadcast() {
// Wake both generations.
if c.oldWaiters > 0 {
for i := 0; i < c.oldWaiters; i++ {
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.oldWaiters = 0
}
if c.newWaiters > 0 {
for i := 0; i < c.newWaiters; i++ {
- runtime.Semrelease(c.newSema)
+ runtime_Semrelease(c.newSema)
}
c.newWaiters = 0
c.newSema = nil
diff --git a/libgo/go/sync/example_test.go b/libgo/go/sync/example_test.go
new file mode 100644
index 00000000000..1424b1e79e6
--- /dev/null
+++ b/libgo/go/sync/example_test.go
@@ -0,0 +1,34 @@
+// Copyright 2012 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 sync_test
+
+import (
+ "net/http"
+ "sync"
+)
+
+// This example fetches several URLs concurrently,
+// using a WaitGroup to block until all the fetches are complete.
+func ExampleWaitGroup() {
+ var wg sync.WaitGroup
+ var urls = []string{
+ "http://www.golang.org/",
+ "http://www.google.com/",
+ "http://www.somestupidname.com/",
+ }
+ for _, url := range urls {
+ // Increment the WaitGroup counter.
+ wg.Add(1)
+ // Launch a goroutine to fetch the URL.
+ go func(url string) {
+ // Fetch the URL.
+ http.Get(url)
+ // Decrement the counter.
+ wg.Done()
+ }(url)
+ }
+ // Wait for all HTTP fetches to complete.
+ wg.Wait()
+}
diff --git a/libgo/go/sync/export_test.go b/libgo/go/sync/export_test.go
new file mode 100644
index 00000000000..fa5983a2d1e
--- /dev/null
+++ b/libgo/go/sync/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2012 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 sync
+
+// Export for testing.
+var Runtime_Semacquire = runtime_Semacquire
+var Runtime_Semrelease = runtime_Semrelease
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
index 4fc02743c6e..9494cc3f826 100644
--- a/libgo/go/sync/mutex.go
+++ b/libgo/go/sync/mutex.go
@@ -10,10 +10,7 @@
// Values containing the types defined in this package should not be copied.
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
@@ -60,7 +57,7 @@ func (m *Mutex) Lock() {
if old&mutexLocked == 0 {
break
}
- runtime.Semacquire(&m.sema)
+ runtime_Semacquire(&m.sema)
awoke = true
}
}
@@ -89,7 +86,7 @@ func (m *Mutex) Unlock() {
// Grab the right to wake someone.
new = (old - 1<<mutexWaiterShift) | mutexWoken
if atomic.CompareAndSwapInt32(&m.state, old, new) {
- runtime.Semrelease(&m.sema)
+ runtime_Semrelease(&m.sema)
return
}
old = m.state
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
index a514b4ad4c0..bf78c6f609c 100644
--- a/libgo/go/sync/mutex_test.go
+++ b/libgo/go/sync/mutex_test.go
@@ -15,8 +15,8 @@ import (
func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
for i := 0; i < loops; i++ {
- runtime.Semacquire(s)
- runtime.Semrelease(s)
+ Runtime_Semacquire(s)
+ Runtime_Semrelease(s)
}
cdone <- true
}
diff --git a/libgo/go/sync/runtime.go b/libgo/go/sync/runtime.go
new file mode 100644
index 00000000000..e99599c11ae
--- /dev/null
+++ b/libgo/go/sync/runtime.go
@@ -0,0 +1,18 @@
+// Copyright 2012 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 sync
+
+// defined in package runtime
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semrelease(s *uint32)
diff --git a/libgo/go/runtime/sema_test.go b/libgo/go/sync/runtime_sema_test.go
index d95bb1ec58f..57a8dbee783 100644
--- a/libgo/go/runtime/sema_test.go
+++ b/libgo/go/sync/runtime_sema_test.go
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package runtime_test
+package sync_test
import (
"runtime"
+ . "sync"
"sync/atomic"
"testing"
)
@@ -25,8 +26,8 @@ func BenchmarkSemaUncontended(b *testing.B) {
for atomic.AddInt32(&N, -1) >= 0 {
runtime.Gosched()
for g := 0; g < CallsPerSched; g++ {
- runtime.Semrelease(&sem.sem)
- runtime.Semacquire(&sem.sem)
+ Runtime_Semrelease(&sem.sem)
+ Runtime_Semacquire(&sem.sem)
}
}
c <- true
@@ -48,7 +49,7 @@ func benchmarkSema(b *testing.B, block, work bool) {
if block {
for p := 0; p < procs/2; p++ {
go func() {
- runtime.Semacquire(&sem)
+ Runtime_Semacquire(&sem)
c2 <- true
}()
}
@@ -59,18 +60,18 @@ func benchmarkSema(b *testing.B, block, work bool) {
for atomic.AddInt32(&N, -1) >= 0 {
runtime.Gosched()
for g := 0; g < CallsPerSched; g++ {
- runtime.Semrelease(&sem)
+ Runtime_Semrelease(&sem)
if work {
for i := 0; i < LocalWork; i++ {
foo *= 2
foo /= 2
}
}
- runtime.Semacquire(&sem)
+ Runtime_Semacquire(&sem)
}
}
c <- foo == 42
- runtime.Semrelease(&sem)
+ Runtime_Semrelease(&sem)
}()
}
if block {
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
index cb1a47720b2..782a9c31968 100644
--- a/libgo/go/sync/rwmutex.go
+++ b/libgo/go/sync/rwmutex.go
@@ -4,10 +4,7 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// An RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers
@@ -29,7 +26,7 @@ const rwmutexMaxReaders = 1 << 30
func (rw *RWMutex) RLock() {
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
- runtime.Semacquire(&rw.readerSem)
+ runtime_Semacquire(&rw.readerSem)
}
}
@@ -42,7 +39,7 @@ func (rw *RWMutex) RUnlock() {
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
// The last reader unblocks the writer.
- runtime.Semrelease(&rw.writerSem)
+ runtime_Semrelease(&rw.writerSem)
}
}
}
@@ -60,7 +57,7 @@ func (rw *RWMutex) Lock() {
r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
- runtime.Semacquire(&rw.writerSem)
+ runtime_Semacquire(&rw.writerSem)
}
}
@@ -75,7 +72,7 @@ func (rw *RWMutex) Unlock() {
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
- runtime.Semrelease(&rw.readerSem)
+ runtime_Semrelease(&rw.readerSem)
}
// Allow other writers to proceed.
rw.w.Unlock()
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index a4c9b7e43cd..3e7d9d3c8f4 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -4,10 +4,7 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
@@ -60,7 +57,7 @@ func (wg *WaitGroup) Add(delta int) {
}
wg.m.Lock()
for i := int32(0); i < wg.waiters; i++ {
- runtime.Semrelease(wg.sema)
+ runtime_Semrelease(wg.sema)
}
wg.waiters = 0
wg.sema = nil
@@ -93,5 +90,5 @@ func (wg *WaitGroup) Wait() {
}
s := wg.sema
wg.m.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index d5d60eae4cd..adc8c09f217 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -38,16 +38,25 @@
// }
// }
//
-// The package also runs and verifies example code. Example functions
-// include an introductory comment that is compared with the standard output
-// of the function when the tests are run, as in this example of an example:
+// The package also runs and verifies example code. Example functions may
+// include a concluding comment that begins with "Output:" and is compared with
+// the standard output of the function when the tests are run, as in these
+// examples of an example:
//
-// // hello
// func ExampleHello() {
// fmt.Println("hello")
+// // Output: hello
// }
//
-// Example functions without comments are compiled but not executed.
+// func ExampleSalutations() {
+// fmt.Println("hello, and")
+// fmt.Println("goodbye")
+// // Output:
+// // hello, and
+// // goodbye
+// }
+//
+// Example functions without output comments are compiled but not executed.
//
// The naming convention to declare examples for a function F, a type T and
// method M on type T are:
diff --git a/libgo/go/text/tabwriter/example_test.go b/libgo/go/text/tabwriter/example_test.go
new file mode 100644
index 00000000000..20443cb1ffb
--- /dev/null
+++ b/libgo/go/text/tabwriter/example_test.go
@@ -0,0 +1,38 @@
+// Copyright 2012 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 tabwriter_test
+
+import (
+ "fmt"
+ "os"
+ "text/tabwriter"
+)
+
+func ExampleWriter_Init() {
+ w := new(tabwriter.Writer)
+
+ // Format in tab-separated columns with a tab stop of 8.
+ w.Init(os.Stdout, 0, 8, 0, '\t', 0)
+ fmt.Fprintln(w, "a\tb\tc\td\t.")
+ fmt.Fprintln(w, "123\t12345\t1234567\t123456789\t.")
+ fmt.Fprintln(w)
+ w.Flush()
+
+ // Format right-aligned in space-separated columns of minimal width 5
+ // and at least one blank of padding (so wider column entries do not
+ // touch each other).
+ w.Init(os.Stdout, 5, 0, 1, ' ', tabwriter.AlignRight)
+ fmt.Fprintln(w, "a\tb\tc\td\t.")
+ fmt.Fprintln(w, "123\t12345\t1234567\t123456789\t.")
+ fmt.Fprintln(w)
+ w.Flush()
+
+ // output:
+ // a b c d .
+ // 123 12345 1234567 123456789 .
+ //
+ // a b c d.
+ // 123 12345 1234567 123456789.
+}
diff --git a/libgo/go/text/tabwriter/tabwriter.go b/libgo/go/text/tabwriter/tabwriter.go
index ea7c4008111..ce84600d604 100644
--- a/libgo/go/text/tabwriter/tabwriter.go
+++ b/libgo/go/text/tabwriter/tabwriter.go
@@ -169,12 +169,6 @@ const (
// to the tab width in the viewer displaying the result)
// flags formatting control
//
-// To format in tab-separated columns with a tab stop of 8:
-// b.Init(w, 8, 1, 8, '\t', 0);
-//
-// To format in space-separated columns with at least 4 spaces between columns:
-// b.Init(w, 0, 4, 8, ' ', 0);
-//
func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
if minwidth < 0 || tabwidth < 0 || padding < 0 {
panic("negative minwidth, tabwidth, or padding")
diff --git a/libgo/go/text/tabwriter/tabwriter_test.go b/libgo/go/text/tabwriter/tabwriter_test.go
index 1ffb330d432..ace53564737 100644
--- a/libgo/go/text/tabwriter/tabwriter_test.go
+++ b/libgo/go/text/tabwriter/tabwriter_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package tabwriter
+package tabwriter_test
import (
"io"
"testing"
+ . "text/tabwriter"
)
type buffer struct {
diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go
index 35c4c681183..ae91f4a5419 100644
--- a/libgo/go/text/template/doc.go
+++ b/libgo/go/text/template/doc.go
@@ -22,6 +22,20 @@ Actions may not span newlines, although comments can.
Once constructed, a template may be executed safely in parallel.
+Here is a trivial example that prints "17 items are made of wool".
+
+ type Inventory struct {
+ Material string
+ Count uint
+ }
+ sweaters := Inventory{"wool", 17}
+ tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
+ if err != nil { panic(err) }
+ err = tmpl.Execute(os.Stdout, sweaters)
+ if err != nil { panic(err) }
+
+More intricate examples appear below.
+
Actions
Here is the list of actions. "Arguments" and "pipelines" are evaluations of
@@ -128,6 +142,11 @@ An argument is a simple value, denoted by one of the following.
.Field1.Key1.Method1.Field2.Key2.Method2
Methods can also be evaluated on variables, including chaining:
$x.Method1.Field
+ - The name of a niladic function-valued struct field of the data,
+ preceded by a period, such as
+ .Function
+ Function-valued fields behave like methods (of structs) but do not
+ pass a receiver.
- The name of a niladic function, such as
fun
The result is the value of invoking the function, fun(). The return
@@ -148,6 +167,9 @@ value (argument) or a function or method call, possibly with multiple arguments:
The result is the value of calling the method with the
arguments:
dot.Method(Argument1, etc.)
+ .Function [Argument...]
+ A function-valued field of a struct works like a method but does
+ not pass the receiver.
functionName [Argument...]
The result is the value of calling the function associated
with the name:
@@ -303,7 +325,7 @@ produce the text
By construction, a template may reside in only one association. If it's
necessary to have a template addressable from multiple associations, the
template definition must be parsed multiple times to create distinct *Template
-values.
+values, or must be copied with the Clone or AddParseTree method.
Parse may be called multiple times to assemble the various associated templates;
see the ParseFiles and ParseGlob functions and methods for simple ways to parse
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index 973189a8a62..af745286c0b 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -419,10 +419,14 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
tField, ok := receiver.Type().FieldByName(fieldName)
if ok {
field := receiver.FieldByIndex(tField.Index)
- if hasArgs {
- s.errorf("%s is not a method but has arguments", fieldName)
- }
if tField.PkgPath == "" { // field is exported
+ // If it's a function, we must call it.
+ if field.Type().Kind() == reflect.Func {
+ return s.evalCall(dot, field, fieldName, args, final)
+ }
+ if hasArgs {
+ s.errorf("%s is not a method or function but has arguments", fieldName)
+ }
return field
}
}
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index 9bb55e48aac..159cf5100d9 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -59,6 +59,8 @@ type T struct {
PI *int
PSI *[]int
NIL *int
+ // Function (not method)
+ Func func(...string) string
// Template to test evaluation of templates.
Tmpl *Template
}
@@ -118,6 +120,7 @@ var tVal = &T{
Err: errors.New("erroozle"),
PI: newInt(23),
PSI: newIntSlice(21, 22, 23),
+ Func: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
}
@@ -297,8 +300,13 @@ var execTests = []execTest{
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
"true", tVal, true},
+ // Function call
+ {".Func", "-{{.Func}}-", "-<>-", tVal, true},
+ {".Func2", "-{{.Func `he` `llo`}}-", "-<he+llo>-", tVal, true},
+
// Pipelines.
{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
+ {"pipeline func", "-{{.Func `llo` | .Func `he` }}-", "-<he+<llo>>-", tVal, true},
// If.
{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go
index 274f5ef1477..f205e6be1b4 100644
--- a/libgo/go/text/template/multi_test.go
+++ b/libgo/go/text/template/multi_test.go
@@ -193,7 +193,7 @@ func TestClone(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- clone := root.Clone()
+ clone := Must(root.Clone())
// Add variants to both.
_, err = root.Parse(cloneText3)
if err != nil {
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index 4da756657d5..35194f7dfdb 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package parse builds parse trees for templates. The grammar is defined
-// in the documents for the template package.
+// Package parse builds parse trees for templates as defined by text/template
+// and html/template. Clients should use those packages to construct templates
+// rather than this one, which provides shared internal data structures not
+// intended for general use.
package parse
import (
diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go
index 87e39d3af74..7494f9d8c45 100644
--- a/libgo/go/text/template/template.go
+++ b/libgo/go/text/template/template.go
@@ -69,9 +69,9 @@ func (t *Template) init() {
// templates. The actual representation is not copied, but the name space of
// associated templates is, so further calls to Parse in the copy will add
// templates to the copy but not to the original. Clone can be used to prepare
-// common templates and use them with variant definitions for other templates by
-// adding the variants after the clone is made.
-func (t *Template) Clone() *Template {
+// common templates and use them with variant definitions for other templates
+// by adding the variants after the clone is made.
+func (t *Template) Clone() (*Template, error) {
nt := t.copy(nil)
nt.init()
nt.tmpl[t.name] = nt
@@ -89,7 +89,7 @@ func (t *Template) Clone() *Template {
for k, v := range t.execFuncs {
nt.execFuncs[k] = v
}
- return nt
+ return nt, nil
}
// copy returns a shallow copy of t, with common set to the argument.
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
index b25e64cda3e..944cc789c31 100644
--- a/libgo/go/time/example_test.go
+++ b/libgo/go/time/example_test.go
@@ -51,8 +51,8 @@ func ExampleMonth() {
}
}
-// Go launched at 2009-11-10 15:00:00 -0800 PST
func ExampleDate() {
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go launched at %s\n", t.Local())
+ // Output: Go launched at 2009-11-10 15:00:00 -0800 PST
}
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
index c7cfa792a29..8484729448e 100644
--- a/libgo/go/time/sys_plan9.go
+++ b/libgo/go/time/sys_plan9.go
@@ -6,7 +6,10 @@
package time
-import "syscall"
+import (
+ "errors"
+ "syscall"
+)
// for testing: whatever interrupts a sleep
func interrupt() {
@@ -38,3 +41,36 @@ func readFile(name string) ([]byte, error) {
}
return ret, err
}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(int(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(int(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
+ }
+ return nil
+}
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 56a7414e0ce..7f69b492c9f 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -6,7 +6,10 @@
package time
-import "syscall"
+import (
+ "errors"
+ "syscall"
+)
// for testing: whatever interrupts a sleep
func interrupt() {
@@ -38,3 +41,36 @@ func readFile(name string) ([]byte, error) {
}
return ret, err
}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(int(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(int(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
+ }
+ return nil
+}
diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go
index 8c7242f4275..de63b4bf4bb 100644
--- a/libgo/go/time/sys_windows.go
+++ b/libgo/go/time/sys_windows.go
@@ -4,6 +4,70 @@
package time
+import (
+ "errors"
+ "syscall"
+)
+
// for testing: whatever interrupts a sleep
func interrupt() {
}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(syscall.Handle(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(syscall.Handle(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
+ }
+ return nil
+}
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
index 0c1c4d67ab0..914f02c861c 100644
--- a/libgo/go/time/tick_test.go
+++ b/libgo/go/time/tick_test.go
@@ -12,9 +12,6 @@ import (
func TestTicker(t *testing.T) {
const Count = 10
Delta := 100 * Millisecond
- if testing.Short() {
- Delta = 10 * Millisecond
- }
ticker := NewTicker(Delta)
t0 := Now()
for i := 0; i < Count; i++ {
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
index aca56e746af..3c57744043e 100644
--- a/libgo/go/time/zoneinfo.go
+++ b/libgo/go/time/zoneinfo.go
@@ -4,7 +4,10 @@
package time
-import "sync"
+import (
+ "sync"
+ "syscall"
+)
// A Location maps time instants to the zone in use at that time.
// Typically, the Location represents the collection of time offsets
@@ -168,10 +171,7 @@ func (l *Location) lookupOffset(offset int) (name string, isDST bool, ok bool) {
// NOTE(rsc): Eventually we will need to accept the POSIX TZ environment
// syntax too, but I don't feel like implementing it today.
-// NOTE(rsc): Using the IANA names below means ensuring we have access
-// to the database. Probably we will ship the files in $GOROOT/lib/zoneinfo/
-// and only look there if there are no system files available (such as on Windows).
-// The files total 200 kB.
+var zoneinfo, _ = syscall.Getenv("ZONEINFO")
// LoadLocation returns the Location with the given name.
//
@@ -180,6 +180,13 @@ func (l *Location) lookupOffset(offset int) (name string, isDST bool, ok bool) {
//
// Otherwise, the name is taken to be a location name corresponding to a file
// in the IANA Time Zone database, such as "America/New_York".
+//
+// The time zone database needed by LoadLocation may not be
+// present on all systems, especially non-Unix systems.
+// LoadLocation looks in the directory or uncompressed zip file
+// named by the ZONEINFO environment variable, if any, then looks in
+// known installation locations on Unix systems,
+// and finally looks in $GOROOT/lib/time/zoneinfo.zip.
func LoadLocation(name string) (*Location, error) {
if name == "" || name == "UTC" {
return UTC, nil
@@ -187,5 +194,11 @@ func LoadLocation(name string) (*Location, error) {
if name == "Local" {
return Local, nil
}
+ if zoneinfo != "" {
+ if z, err := loadZoneFile(zoneinfo, name); err == nil {
+ z.name = name
+ return z, nil
+ }
+ }
return loadLocation(name)
}
diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go
index 9c052d42cd3..6855238dc84 100644
--- a/libgo/go/time/zoneinfo_plan9.go
+++ b/libgo/go/time/zoneinfo_plan9.go
@@ -8,11 +8,10 @@ package time
import (
"errors"
+ "runtime"
"syscall"
)
-var badData = errors.New("malformed time zone information")
-
func isSpace(r rune) bool {
return r == ' ' || r == '\t' || r == '\n'
}
@@ -51,7 +50,7 @@ func fields(s string) []string {
return a
}
-func loadZoneData(s string) (l *Location, err error) {
+func loadZoneDataPlan9(s string) (l *Location, err error) {
f := fields(s)
if len(f) < 4 {
if len(f) == 2 && f[0] == "GMT" {
@@ -112,33 +111,32 @@ func loadZoneData(s string) (l *Location, err error) {
return l, nil
}
-func loadZoneFile(name string) (*Location, error) {
+func loadZoneFilePlan9(name string) (*Location, error) {
b, err := readFile(name)
if err != nil {
return nil, err
}
- return loadZoneData(string(b))
+ return loadZoneDataPlan9(string(b))
}
func initTestingZone() {
- if z, err := loadZoneFile("/adm/timezone/US_Pacific"); err == nil {
- localLoc = *z
- return
+ z, err := loadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
}
-
- // Fall back to UTC.
- localLoc.name = "UTC"
+ z.name = "Local"
+ localLoc = *z
}
func initLocal() {
t, ok := syscall.Getenv("timezone")
if ok {
- if z, err := loadZoneData(t); err == nil {
+ if z, err := loadZoneDataPlan9(t); err == nil {
localLoc = *z
return
}
} else {
- if z, err := loadZoneFile("/adm/timezone/local"); err == nil {
+ if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
localLoc = *z
localLoc.name = "Local"
return
@@ -150,7 +148,8 @@ func initLocal() {
}
func loadLocation(name string) (*Location, error) {
- if z, err := loadZoneFile("/adm/timezone/" + name); err == nil {
+ if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
+ z.name = name
return z, nil
}
return nil, errors.New("unknown time zone " + name)
diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go
new file mode 100644
index 00000000000..ebb4205a98f
--- /dev/null
+++ b/libgo/go/time/zoneinfo_read.go
@@ -0,0 +1,341 @@
+// 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.
+
+// Parse "zoneinfo" time zone file.
+// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
+// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
+// and ftp://munnari.oz.au/pub/oldtz/
+
+package time
+
+import "errors"
+
+const (
+ headerSize = 4 + 16 + 4*7
+)
+
+// Simple I/O interface to binary blob of data.
+type data struct {
+ p []byte
+ error bool
+}
+
+func (d *data) read(n int) []byte {
+ if len(d.p) < n {
+ d.p = nil
+ d.error = true
+ return nil
+ }
+ p := d.p[0:n]
+ d.p = d.p[n:]
+ return p
+}
+
+func (d *data) big4() (n uint32, ok bool) {
+ p := d.read(4)
+ if len(p) < 4 {
+ d.error = true
+ return 0, false
+ }
+ return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+}
+
+func (d *data) byte() (n byte, ok bool) {
+ p := d.read(1)
+ if len(p) < 1 {
+ d.error = true
+ return 0, false
+ }
+ return p[0], true
+}
+
+// Make a string by stopping at the first NUL
+func byteString(p []byte) string {
+ for i := 0; i < len(p); i++ {
+ if p[i] == 0 {
+ return string(p[0:i])
+ }
+ }
+ return string(p)
+}
+
+var badData = errors.New("malformed time zone information")
+
+func loadZoneData(bytes []byte) (l *Location, err error) {
+ d := data{bytes, false}
+
+ // 4-byte magic "TZif"
+ if magic := d.read(4); string(magic) != "TZif" {
+ return nil, badData
+ }
+
+ // 1-byte version, then 15 bytes of padding
+ var p []byte
+ if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+ return nil, badData
+ }
+
+ // six big-endian 32-bit integers:
+ // number of UTC/local indicators
+ // number of standard/wall indicators
+ // number of leap seconds
+ // number of transition times
+ // number of local time zones
+ // number of characters of time zone abbrev strings
+ const (
+ NUTCLocal = iota
+ NStdWall
+ NLeap
+ NTime
+ NZone
+ NChar
+ )
+ var n [6]int
+ for i := 0; i < 6; i++ {
+ nn, ok := d.big4()
+ if !ok {
+ return nil, badData
+ }
+ n[i] = int(nn)
+ }
+
+ // Transition times.
+ txtimes := data{d.read(n[NTime] * 4), false}
+
+ // Time zone indices for transition times.
+ txzones := d.read(n[NTime])
+
+ // Zone info structures
+ zonedata := data{d.read(n[NZone] * 6), false}
+
+ // Time zone abbreviations.
+ abbrev := d.read(n[NChar])
+
+ // Leap-second time pairs
+ d.read(n[NLeap] * 8)
+
+ // Whether tx times associated with local time types
+ // are specified as standard time or wall time.
+ isstd := d.read(n[NStdWall])
+
+ // Whether tx times associated with local time types
+ // are specified as UTC or local time.
+ isutc := d.read(n[NUTCLocal])
+
+ if d.error { // ran out of data
+ return nil, badData
+ }
+
+ // If version == 2, the entire file repeats, this time using
+ // 8-byte ints for txtimes and leap seconds.
+ // We won't need those until 2106.
+
+ // Now we can build up a useful data structure.
+ // First the zone information.
+ // utcoff[4] isdst[1] nameindex[1]
+ zone := make([]zone, n[NZone])
+ for i := range zone {
+ var ok bool
+ var n uint32
+ if n, ok = zonedata.big4(); !ok {
+ return nil, badData
+ }
+ zone[i].offset = int(n)
+ var b byte
+ if b, ok = zonedata.byte(); !ok {
+ return nil, badData
+ }
+ zone[i].isDST = b != 0
+ if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
+ return nil, badData
+ }
+ zone[i].name = byteString(abbrev[b:])
+ }
+
+ // Now the transition time info.
+ tx := make([]zoneTrans, n[NTime])
+ for i := range tx {
+ var ok bool
+ var n uint32
+ if n, ok = txtimes.big4(); !ok {
+ return nil, badData
+ }
+ tx[i].when = int64(int32(n))
+ if int(txzones[i]) >= len(zone) {
+ return nil, badData
+ }
+ tx[i].index = txzones[i]
+ if i < len(isstd) {
+ tx[i].isstd = isstd[i] != 0
+ }
+ if i < len(isutc) {
+ tx[i].isutc = isutc[i] != 0
+ }
+ }
+
+ // Commited to succeed.
+ l = &Location{zone: zone, tx: tx}
+
+ // Fill in the cache with information about right now,
+ // since that will be the most common lookup.
+ sec, _ := now()
+ for i := range tx {
+ if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
+ l.cacheStart = tx[i].when
+ l.cacheEnd = 1<<63 - 1
+ if i+1 < len(tx) {
+ l.cacheEnd = tx[i+1].when
+ }
+ l.cacheZone = &l.zone[tx[i].index]
+ }
+ }
+
+ return l, nil
+}
+
+func loadZoneFile(dir, name string) (l *Location, err error) {
+ if len(dir) > 4 && dir[len(dir)-4:] == ".zip" {
+ return loadZoneZip(dir, name)
+ }
+ if dir != "" {
+ name = dir + "/" + name
+ }
+ buf, err := readFile(name)
+ if err != nil {
+ return
+ }
+ return loadZoneData(buf)
+}
+
+// There are 500+ zoneinfo files. Rather than distribute them all
+// individually, we ship them in an uncompressed zip file.
+// Used this way, the zip file format serves as a commonly readable
+// container for the individual small files. We choose zip over tar
+// because zip files have a contiguous table of contents, making
+// individual file lookups faster, and because the per-file overhead
+// in a zip file is considerably less than tar's 512 bytes.
+
+// get4 returns the little-endian 32-bit value in b.
+func get4(b []byte) int {
+ if len(b) < 4 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func get2(b []byte) int {
+ if len(b) < 2 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8
+}
+
+func loadZoneZip(zipfile, name string) (l *Location, err error) {
+ fd, err := open(zipfile)
+ if err != nil {
+ return nil, errors.New("open " + zipfile + ": " + err.Error())
+ }
+ defer closefd(fd)
+
+ const (
+ zecheader = 0x06054b50
+ zcheader = 0x02014b50
+ ztailsize = 22
+
+ zheadersize = 30
+ zheader = 0x04034b50
+ )
+
+ buf := make([]byte, ztailsize)
+ if err := preadn(fd, buf, -ztailsize); err != nil || get4(buf) != zecheader {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+ n := get2(buf[10:])
+ size := get4(buf[12:])
+ off := get4(buf[16:])
+
+ buf = make([]byte, size)
+ if err := preadn(fd, buf, off); err != nil {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+
+ for i := 0; i < n; i++ {
+ // zip entry layout:
+ // 0 magic[4]
+ // 4 madevers[1]
+ // 5 madeos[1]
+ // 6 extvers[1]
+ // 7 extos[1]
+ // 8 flags[2]
+ // 10 meth[2]
+ // 12 modtime[2]
+ // 14 moddate[2]
+ // 16 crc[4]
+ // 20 csize[4]
+ // 24 uncsize[4]
+ // 28 namelen[2]
+ // 30 xlen[2]
+ // 32 fclen[2]
+ // 34 disknum[2]
+ // 36 iattr[2]
+ // 38 eattr[4]
+ // 42 off[4]
+ // 46 name[namelen]
+ // 46+namelen+xlen+fclen - next header
+ //
+ if get4(buf) != zcheader {
+ break
+ }
+ meth := get2(buf[10:])
+ size := get4(buf[24:])
+ namelen := get2(buf[28:])
+ xlen := get2(buf[30:])
+ fclen := get2(buf[32:])
+ off := get4(buf[42:])
+ zname := buf[46 : 46+namelen]
+ buf = buf[46+namelen+xlen+fclen:]
+ if string(zname) != name {
+ continue
+ }
+ if meth != 0 {
+ return nil, errors.New("unsupported compression for " + name + " in " + zipfile)
+ }
+
+ // zip per-file header layout:
+ // 0 magic[4]
+ // 4 extvers[1]
+ // 5 extos[1]
+ // 6 flags[2]
+ // 8 meth[2]
+ // 10 modtime[2]
+ // 12 moddate[2]
+ // 14 crc[4]
+ // 18 csize[4]
+ // 22 uncsize[4]
+ // 26 namelen[2]
+ // 28 xlen[2]
+ // 30 name[namelen]
+ // 30+namelen+xlen - file data
+ //
+ buf = make([]byte, zheadersize+namelen)
+ if err := preadn(fd, buf, off); err != nil ||
+ get4(buf) != zheader ||
+ get2(buf[8:]) != meth ||
+ get2(buf[26:]) != namelen ||
+ string(buf[30:30+namelen]) != name {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+ xlen = get2(buf[28:])
+
+ buf = make([]byte, size)
+ if err := preadn(fd, buf, off+30+namelen+xlen); err != nil {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+
+ return loadZoneData(buf)
+ }
+
+ return nil, errors.New("cannot find " + name + " in zip file " + zipfile)
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 540b653c57d..1bf1f11e24f 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -13,200 +13,10 @@ package time
import (
"errors"
+ "runtime"
"syscall"
)
-const (
- headerSize = 4 + 16 + 4*7
-)
-
-// Simple I/O interface to binary blob of data.
-type data struct {
- p []byte
- error bool
-}
-
-func (d *data) read(n int) []byte {
- if len(d.p) < n {
- d.p = nil
- d.error = true
- return nil
- }
- p := d.p[0:n]
- d.p = d.p[n:]
- return p
-}
-
-func (d *data) big4() (n uint32, ok bool) {
- p := d.read(4)
- if len(p) < 4 {
- d.error = true
- return 0, false
- }
- return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
-}
-
-func (d *data) byte() (n byte, ok bool) {
- p := d.read(1)
- if len(p) < 1 {
- d.error = true
- return 0, false
- }
- return p[0], true
-}
-
-// Make a string by stopping at the first NUL
-func byteString(p []byte) string {
- for i := 0; i < len(p); i++ {
- if p[i] == 0 {
- return string(p[0:i])
- }
- }
- return string(p)
-}
-
-var badData = errors.New("malformed time zone information")
-
-func loadZoneData(bytes []byte) (l *Location, err error) {
- d := data{bytes, false}
-
- // 4-byte magic "TZif"
- if magic := d.read(4); string(magic) != "TZif" {
- return nil, badData
- }
-
- // 1-byte version, then 15 bytes of padding
- var p []byte
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
- return nil, badData
- }
-
- // six big-endian 32-bit integers:
- // number of UTC/local indicators
- // number of standard/wall indicators
- // number of leap seconds
- // number of transition times
- // number of local time zones
- // number of characters of time zone abbrev strings
- const (
- NUTCLocal = iota
- NStdWall
- NLeap
- NTime
- NZone
- NChar
- )
- var n [6]int
- for i := 0; i < 6; i++ {
- nn, ok := d.big4()
- if !ok {
- return nil, badData
- }
- n[i] = int(nn)
- }
-
- // Transition times.
- txtimes := data{d.read(n[NTime] * 4), false}
-
- // Time zone indices for transition times.
- txzones := d.read(n[NTime])
-
- // Zone info structures
- zonedata := data{d.read(n[NZone] * 6), false}
-
- // Time zone abbreviations.
- abbrev := d.read(n[NChar])
-
- // Leap-second time pairs
- d.read(n[NLeap] * 8)
-
- // Whether tx times associated with local time types
- // are specified as standard time or wall time.
- isstd := d.read(n[NStdWall])
-
- // Whether tx times associated with local time types
- // are specified as UTC or local time.
- isutc := d.read(n[NUTCLocal])
-
- if d.error { // ran out of data
- return nil, badData
- }
-
- // If version == 2, the entire file repeats, this time using
- // 8-byte ints for txtimes and leap seconds.
- // We won't need those until 2106.
-
- // Now we can build up a useful data structure.
- // First the zone information.
- // utcoff[4] isdst[1] nameindex[1]
- zone := make([]zone, n[NZone])
- for i := range zone {
- var ok bool
- var n uint32
- if n, ok = zonedata.big4(); !ok {
- return nil, badData
- }
- zone[i].offset = int(n)
- var b byte
- if b, ok = zonedata.byte(); !ok {
- return nil, badData
- }
- zone[i].isDST = b != 0
- if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
- return nil, badData
- }
- zone[i].name = byteString(abbrev[b:])
- }
-
- // Now the transition time info.
- tx := make([]zoneTrans, n[NTime])
- for i := range tx {
- var ok bool
- var n uint32
- if n, ok = txtimes.big4(); !ok {
- return nil, badData
- }
- tx[i].when = int64(int32(n))
- if int(txzones[i]) >= len(zone) {
- return nil, badData
- }
- tx[i].index = txzones[i]
- if i < len(isstd) {
- tx[i].isstd = isstd[i] != 0
- }
- if i < len(isutc) {
- tx[i].isutc = isutc[i] != 0
- }
- }
-
- // Commited to succeed.
- l = &Location{zone: zone, tx: tx}
-
- // Fill in the cache with information about right now,
- // since that will be the most common lookup.
- sec, _ := now()
- for i := range tx {
- if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
- l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
- if i+1 < len(tx) {
- l.cacheEnd = tx[i+1].when
- }
- l.cacheZone = &l.zone[tx[i].index]
- }
- }
-
- return l, nil
-}
-
-func loadZoneFile(name string) (l *Location, err error) {
- buf, err := readFile(name)
- if err != nil {
- return
- }
- return loadZoneData(buf)
-}
-
func initTestingZone() {
syscall.Setenv("TZ", "America/Los_Angeles")
initLocal()
@@ -218,6 +28,7 @@ var zoneDirs = []string{
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
+ runtime.GOROOT() + "/lib/time/zoneinfo/",
}
func initLocal() {
@@ -229,7 +40,7 @@ func initLocal() {
tz, ok := syscall.Getenv("TZ")
switch {
case !ok:
- z, err := loadZoneFile("/etc/localtime")
+ z, err := loadZoneFile("", "/etc/localtime")
if err == nil {
localLoc = *z
localLoc.name = "Local"
@@ -248,7 +59,7 @@ func initLocal() {
func loadLocation(name string) (*Location, error) {
for _, zoneDir := range zoneDirs {
- if z, err := loadZoneFile(zoneDir + name); err == nil {
+ if z, err := loadZoneFile(zoneDir, name); err == nil {
z.name = name
return z, nil
}
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index beef4de92b0..754e392deca 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -6,6 +6,7 @@ package time
import (
"errors"
+ "runtime"
"syscall"
)
@@ -151,7 +152,10 @@ func initLocal() {
initLocalFromTZI(&i)
}
-// TODO(rsc): Implement.
func loadLocation(name string) (*Location, error) {
+ if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
+ z.name = name
+ return z, nil
+ }
return nil, errors.New("unknown time zone " + name)
}
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 8b48c866346..23641e8298f 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -19,6 +19,7 @@ package runtime
#include "go-type.h"
MHeap runtime_mheap;
+
extern MStats mstats; // defined in extern.go
extern volatile int32 runtime_MemProfileRate
@@ -429,18 +430,6 @@ func new(typ *Type) (ret *uint8) {
ret = runtime_mallocgc(typ->__size, flag, 1, 1);
}
-func Alloc(n uintptr) (p *byte) {
- p = runtime_malloc(n);
-}
-
-func Free(p *byte) {
- runtime_free(p);
-}
-
-func Lookup(p *byte) (base *byte, size uintptr) {
- runtime_mlookup(p, &base, &size, nil);
-}
-
func GC() {
runtime_gc(1);
}
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
index c1cf02c6deb..4cb07477f15 100644
--- a/libgo/runtime/malloc.h
+++ b/libgo/runtime/malloc.h
@@ -205,6 +205,7 @@ struct MStats
uint64 heap_sys; // bytes obtained from system
uint64 heap_idle; // bytes in idle spans
uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_released; // bytes released to the OS
uint64 heap_objects; // total number of allocated objects
// Statistics about allocation of low-level fixed-size structures.
@@ -220,6 +221,7 @@ struct MStats
// Statistics about garbage collector.
// Protected by stopping the world during GC.
uint64 next_gc; // next GC (in heap_alloc time)
+ uint64 last_gc; // last GC (in absolute time)
uint64 pause_total_ns;
uint64 pause_ns[256];
uint32 numgc;
@@ -304,14 +306,16 @@ struct MSpan
{
MSpan *next; // in a span linked list
MSpan *prev; // in a span linked list
- MSpan *allnext; // in the list of all spans
+ MSpan *allnext; // in the list of all spans
PageID start; // starting page number
uintptr npages; // number of pages in span
MLink *freelist; // list of free objects
uint32 ref; // number of allocated objects in this span
uint32 sizeclass; // size class
uint32 state; // MSpanInUse etc
- byte *limit; // end of data in span
+ int64 unusedsince; // First time spotted by GC in MSpanFree state
+ uintptr npreleased; // number of pages released to the OS
+ byte *limit; // end of data in span
};
void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
@@ -381,6 +385,7 @@ MSpan* runtime_MHeap_LookupMaybe(MHeap *h, void *v);
void runtime_MGetSizeClassInfo(int32 sizeclass, uintptr *size, int32 *npages, int32 *nobj);
void* runtime_MHeap_SysAlloc(MHeap *h, uintptr n);
void runtime_MHeap_MapBits(MHeap *h);
+void runtime_MHeap_Scavenger(void*);
void* runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
int32 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s);
@@ -406,19 +411,11 @@ enum
void runtime_MProf_Malloc(void*, uintptr);
void runtime_MProf_Free(void*, uintptr);
+void runtime_MProf_GC(void);
void runtime_MProf_Mark(void (*scan)(byte *, int64));
int32 runtime_helpgc(bool*);
void runtime_gchelper(void);
-// Malloc profiling settings.
-// Must match definition in extern.go.
-enum {
- MProf_None = 0,
- MProf_Sample = 1,
- MProf_All = 2,
-};
-extern int32 runtime_malloc_profile;
-
struct __go_func_type;
bool runtime_getfinalizer(void *p, bool del, void (**fn)(void*), const struct __go_func_type **ft);
void runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 73c399df239..d852946cdbb 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -61,6 +61,21 @@ enum {
#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+// Holding worldsema grants an M the right to try to stop the world.
+// The procedure is:
+//
+// runtime_semacquire(&runtime_worldsema);
+// m->gcing = 1;
+// runtime_stoptheworld();
+//
+// ... do stuff ...
+//
+// m->gcing = 0;
+// runtime_semrelease(&runtime_worldsema);
+// runtime_starttheworld();
+//
+uint32 runtime_worldsema = 1;
+
// TODO: Make these per-M.
static uint64 nhandoff;
@@ -92,7 +107,6 @@ struct FinBlock
Finalizer fin[1];
};
-
static G *fing;
static FinBlock *finq; // list of finalizers that are to be executed
static FinBlock *finc; // cache of free blocks
@@ -778,9 +792,11 @@ sweep(void)
byte *p;
MCache *c;
byte *arena_start;
+ int64 now;
m = runtime_m();
arena_start = runtime_mheap.arena_start;
+ now = runtime_nanotime();
for(;;) {
s = work.spans;
@@ -789,6 +805,11 @@ sweep(void)
if(!runtime_casp(&work.spans, s, s->allnext))
continue;
+ // Stamp newly unused spans. The scavenger will use that
+ // info to potentially give back some pages to the OS.
+ if(s->state == MSpanFree && s->unusedsince == 0)
+ s->unusedsince = now;
+
if(s->state != MSpanInUse)
continue;
@@ -875,11 +896,6 @@ runtime_gchelper(void)
runtime_notewakeup(&work.alldone);
}
-// Semaphore, not Lock, so that the goroutine
-// reschedules when there is contention rather
-// than spinning.
-static uint32 gcsema = 1;
-
// Initialized from $GOGC. GOGC=off means no gc.
//
// Next gc is after we've allocated an extra amount of
@@ -968,9 +984,9 @@ runtime_gc(int32 force)
if(gcpercent < 0)
return;
- runtime_semacquire(&gcsema);
+ runtime_semacquire(&runtime_worldsema);
if(!force && mstats.heap_alloc < mstats.next_gc) {
- runtime_semrelease(&gcsema);
+ runtime_semrelease(&runtime_worldsema);
return;
}
@@ -1032,6 +1048,7 @@ runtime_gc(int32 force)
obj1 = mstats.nmalloc - mstats.nfree;
t3 = runtime_nanotime();
+ mstats.last_gc = t3;
mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t3 - t0;
mstats.pause_total_ns += t3 - t0;
mstats.numgc++;
@@ -1045,8 +1062,9 @@ runtime_gc(int32 force)
(unsigned long long) mstats.nmalloc, (unsigned long long)mstats.nfree,
(unsigned long long) nhandoff);
}
-
- runtime_semrelease(&gcsema);
+
+ runtime_MProf_GC();
+ runtime_semrelease(&runtime_worldsema);
// If we could have used another helper proc, start one now,
// in the hope that it will be available next time.
@@ -1073,18 +1091,18 @@ runtime_ReadMemStats(MStats *stats)
{
M *m;
- // Have to acquire gcsema to stop the world,
+ // Have to acquire worldsema to stop the world,
// because stoptheworld can only be used by
// one goroutine at a time, and there might be
// a pending garbage collection already calling it.
- runtime_semacquire(&gcsema);
+ runtime_semacquire(&runtime_worldsema);
m = runtime_m();
m->gcing = 1;
runtime_stoptheworld();
cachestats();
*stats = mstats;
m->gcing = 0;
- runtime_semrelease(&gcsema);
+ runtime_semrelease(&runtime_worldsema);
runtime_starttheworld(false);
}
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
index 5a5a1e71a12..79359d9dfca 100644
--- a/libgo/runtime/mheap.c
+++ b/libgo/runtime/mheap.c
@@ -103,6 +103,8 @@ HaveSpan:
runtime_MSpanList_Remove(s);
s->state = MSpanInUse;
mstats.heap_idle -= s->npages<<PageShift;
+ mstats.heap_released -= s->npreleased<<PageShift;
+ s->npreleased = 0;
if(s->npages > npage) {
// Trim extra and put it back in the heap.
@@ -280,6 +282,8 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
}
mstats.heap_idle += s->npages<<PageShift;
s->state = MSpanFree;
+ s->unusedsince = 0;
+ s->npreleased = 0;
runtime_MSpanList_Remove(s);
sp = (uintptr*)(s->start<<PageShift);
@@ -292,6 +296,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
*tp |= *sp; // propagate "needs zeroing" mark
s->start = t->start;
s->npages += t->npages;
+ s->npreleased = t->npreleased; // absorb released pages
p -= t->npages;
h->map[p] = s;
runtime_MSpanList_Remove(t);
@@ -304,6 +309,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
tp = (uintptr*)(t->start<<PageShift);
*sp |= *tp; // propagate "needs zeroing" mark
s->npages += t->npages;
+ s->npreleased += t->npreleased;
h->map[p + s->npages - 1] = s;
runtime_MSpanList_Remove(t);
t->state = MSpanDead;
@@ -317,8 +323,86 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
runtime_MSpanList_Insert(&h->free[s->npages], s);
else
runtime_MSpanList_Insert(&h->large, s);
+}
- // TODO(rsc): IncrementalScavenge() to return memory to OS.
+// Release (part of) unused memory to OS.
+// Goroutine created in runtime_schedinit.
+// Loop forever.
+void
+runtime_MHeap_Scavenger(void* dummy)
+{
+ MHeap *h;
+ MSpan *s, *list;
+ uint64 tick, now, forcegc, limit;
+ uint32 k, i;
+ uintptr released, sumreleased;
+ const byte *env;
+ bool trace;
+ Note note;
+
+ USED(dummy);
+
+ // If we go two minutes without a garbage collection, force one to run.
+ forcegc = 2*60*1e9;
+ // If a span goes unused for 5 minutes after a garbage collection,
+ // we hand it back to the operating system.
+ limit = 5*60*1e9;
+ // Make wake-up period small enough for the sampling to be correct.
+ if(forcegc < limit)
+ tick = forcegc/2;
+ else
+ tick = limit/2;
+
+ trace = false;
+ env = runtime_getenv("GOGCTRACE");
+ if(env != nil)
+ trace = runtime_atoi(env) > 0;
+
+ h = &runtime_mheap;
+ for(k=0;; k++) {
+ runtime_noteclear(&note);
+ runtime_entersyscall();
+ runtime_notetsleep(&note, tick);
+ runtime_exitsyscall();
+
+ runtime_lock(h);
+ now = runtime_nanotime();
+ if(now - mstats.last_gc > forcegc) {
+ runtime_unlock(h);
+ runtime_gc(1);
+ runtime_lock(h);
+ now = runtime_nanotime();
+ if (trace)
+ runtime_printf("scvg%d: GC forced\n", k);
+ }
+ sumreleased = 0;
+ for(i=0; i < nelem(h->free)+1; i++) {
+ if(i < nelem(h->free))
+ list = &h->free[i];
+ else
+ list = &h->large;
+ if(runtime_MSpanList_IsEmpty(list))
+ continue;
+ for(s=list->next; s != list; s=s->next) {
+ if(s->unusedsince != 0 && (now - s->unusedsince) > limit) {
+ released = (s->npages - s->npreleased) << PageShift;
+ mstats.heap_released += released;
+ sumreleased += released;
+ s->npreleased = s->npages;
+ runtime_SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
+ }
+ }
+ }
+ runtime_unlock(h);
+
+ if(trace) {
+ if(sumreleased > 0)
+ runtime_printf("scvg%d: %p MB released\n", k, (void*)(sumreleased>>20));
+ runtime_printf("scvg%d: inuse: %lld, idle: %lld, sys: %lld, released: %lld, consumed: %lld (MB)\n",
+ k, (long long)(mstats.heap_inuse>>20), (long long)(mstats.heap_idle>>20), (long long)(mstats.heap_sys>>20),
+ (long long)(mstats.heap_released>>20), (long long)((mstats.heap_sys - mstats.heap_released)>>20));
+ }
+ }
}
// Initialize a new span with the given start and npages.
@@ -333,6 +417,8 @@ runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
span->ref = 0;
span->sizeclass = 0;
span->state = 0;
+ span->unusedsince = 0;
+ span->npreleased = 0;
}
// Initialize an empty doubly-linked list.
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
index 95e05fabeb3..e40dd61f784 100644
--- a/libgo/runtime/mprof.goc
+++ b/libgo/runtime/mprof.goc
@@ -26,6 +26,10 @@ struct Bucket
uintptr frees;
uintptr alloc_bytes;
uintptr free_bytes;
+ uintptr recent_allocs; // since last gc
+ uintptr recent_frees;
+ uintptr recent_alloc_bytes;
+ uintptr recent_free_bytes;
uintptr hash;
uintptr nstk;
uintptr stk[1];
@@ -39,7 +43,7 @@ static uintptr bucketmem;
// Return the bucket for stk[0:nstk], allocating new bucket if needed.
static Bucket*
-stkbucket(uintptr *stk, int32 nstk)
+stkbucket(uintptr *stk, int32 nstk, bool alloc)
{
int32 i;
uintptr h;
@@ -66,6 +70,9 @@ stkbucket(uintptr *stk, int32 nstk)
runtime_mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
+ if(!alloc)
+ return nil;
+
b = runtime_mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
bucketmem += sizeof *b + nstk*sizeof stk[0];
runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
@@ -78,6 +85,26 @@ stkbucket(uintptr *stk, int32 nstk)
return b;
}
+// Record that a gc just happened: all the 'recent' statistics are now real.
+void
+runtime_MProf_GC(void)
+{
+ Bucket *b;
+
+ runtime_lock(&proflock);
+ for(b=buckets; b; b=b->allnext) {
+ b->allocs += b->recent_allocs;
+ b->frees += b->recent_frees;
+ b->alloc_bytes += b->recent_alloc_bytes;
+ b->free_bytes += b->recent_free_bytes;
+ b->recent_allocs = 0;
+ b->recent_frees = 0;
+ b->recent_alloc_bytes = 0;
+ b->recent_free_bytes = 0;
+ }
+ runtime_unlock(&proflock);
+}
+
// Map from pointer to Bucket* that allocated it.
// Three levels:
// Linked-list hash table for top N-20 bits.
@@ -204,9 +231,9 @@ runtime_MProf_Malloc(void *p, uintptr size)
nstk = 0;
#endif
runtime_lock(&proflock);
- b = stkbucket(stk, nstk);
- b->allocs++;
- b->alloc_bytes += size;
+ b = stkbucket(stk, nstk, true);
+ b->recent_allocs++;
+ b->recent_alloc_bytes += size;
setaddrbucket((uintptr)p, b);
runtime_unlock(&proflock);
m = runtime_m();
@@ -228,8 +255,8 @@ runtime_MProf_Free(void *p, uintptr size)
runtime_lock(&proflock);
b = getaddrbucket((uintptr)p);
if(b != nil) {
- b->frees++;
- b->free_bytes += size;
+ b->recent_frees++;
+ b->recent_free_bytes += size;
}
runtime_unlock(&proflock);
m = runtime_m();
@@ -293,13 +320,13 @@ runtime_MProf_Mark(void (*scan)(byte *, int64))
scan((byte*)&addrfree, sizeof addrfree);
}
-// Must match ThreadProfileRecord in debug.go.
+// Must match StackRecord in debug.go.
typedef struct TRecord TRecord;
struct TRecord {
uintptr stk[32];
};
-func ThreadProfile(p Slice) (n int32, ok bool) {
+func ThreadCreateProfile(p Slice) (n int32, ok bool) {
TRecord *r;
M *first, *m;
@@ -317,3 +344,89 @@ func ThreadProfile(p Slice) (n int32, ok bool) {
}
}
}
+
+func Stack(b Slice, all bool) (n int32) {
+ byte *pc, *sp;
+
+ sp = runtime_getcallersp(&b);
+ pc = runtime_getcallerpc(&b);
+
+ if(all) {
+ runtime_semacquire(&runtime_worldsema);
+ runtime_m()->gcing = 1;
+ runtime_stoptheworld();
+ }
+
+ if(b.__count == 0)
+ n = 0;
+ else{
+ G* g = runtime_g();
+ g->writebuf = (byte*)b.__values;
+ g->writenbuf = b.__count;
+ USED(pc);
+ USED(sp);
+ // runtime_goroutineheader(g);
+ // runtime_traceback(pc, sp, 0, g);
+ // if(all)
+ // runtime_tracebackothers(g);
+ n = b.__count - g->writenbuf;
+ g->writebuf = nil;
+ g->writenbuf = 0;
+ }
+
+ if(all) {
+ runtime_m()->gcing = 0;
+ runtime_semrelease(&runtime_worldsema);
+ runtime_starttheworld(false);
+ }
+}
+
+static void
+saveg(byte *pc, byte *sp, G *g, TRecord *r)
+{
+ int32 n;
+
+ USED(pc);
+ USED(sp);
+ USED(g);
+ // n = runtime_gentraceback(pc, sp, 0, g, 0, r->stk, nelem(r->stk));
+ n = 0;
+ if((size_t)n < nelem(r->stk))
+ r->stk[n] = 0;
+}
+
+func GoroutineProfile(b Slice) (n int32, ok bool) {
+ byte *pc, *sp;
+ TRecord *r;
+ G *gp;
+
+ sp = runtime_getcallersp(&b);
+ pc = runtime_getcallerpc(&b);
+
+ ok = false;
+ n = runtime_gcount();
+ if(n <= b.__count) {
+ runtime_semacquire(&runtime_worldsema);
+ runtime_m()->gcing = 1;
+ runtime_stoptheworld();
+
+ n = runtime_gcount();
+ if(n <= b.__count) {
+ G* g = runtime_g();
+ ok = true;
+ r = (TRecord*)b.__values;
+ saveg(pc, sp, g, r++);
+ for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
+ if(gp == g || gp->status == Gdead)
+ continue;
+ //saveg(gp->sched.pc, gp->sched.sp, gp, r++);
+ r++;
+ }
+ }
+
+ runtime_m()->gcing = 0;
+ runtime_semrelease(&runtime_worldsema);
+ runtime_starttheworld(false);
+ }
+}
+
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index a4e4588299e..d0ae09c45a0 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -362,6 +362,9 @@ runtime_mcall(void (*pfn)(G*))
}
}
+// Keep trace of scavenger's goroutine for deadlock detection.
+static G *scvg;
+
// The bootstrap sequence is:
//
// call osinit
@@ -413,6 +416,8 @@ runtime_schedinit(void)
// Can not enable GC until all roots are registered.
// mstats.enablegc = 1;
m->nomemprof--;
+
+ scvg = __go_go(runtime_MHeap_Scavenger, nil);
}
extern void main_init(void) __asm__ ("__go_init_main");
@@ -547,7 +552,7 @@ mcommoninit(M *m)
// Add to runtime_allm so garbage collector doesn't free m
// when it is just in a register or thread-local storage.
m->alllink = runtime_allm;
- // runtime_Cgocalls() iterates over allm w/o schedlock,
+ // runtime_NumCgoCall() iterates over allm w/o schedlock,
// so we need to publish it safely.
runtime_atomicstorep(&runtime_allm, m);
}
@@ -786,9 +791,12 @@ top:
mput(m);
}
- v = runtime_atomicload(&runtime_sched.atomic);
- if(runtime_sched.grunning == 0)
- runtime_throw("all goroutines are asleep - deadlock!");
+ // Look for deadlock situation: one single active g which happens to be scvg.
+ if(runtime_sched.grunning == 1 && runtime_sched.gwait == 0) {
+ if(scvg->status == Grunning || scvg->status == Gsyscall)
+ runtime_throw("all goroutines are asleep - deadlock!");
+ }
+
m->nextg = nil;
m->waitnextg = 1;
runtime_noteclear(&m->havenextg);
@@ -797,6 +805,7 @@ top:
// Entersyscall might have decremented mcpu too, but if so
// it will see the waitstop and take the slow path.
// Exitsyscall never increments mcpu beyond mcpumax.
+ v = runtime_atomicload(&runtime_sched.atomic);
if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
// set waitstop = 0 (known to be 1)
runtime_xadd(&runtime_sched.atomic, -1<<waitstopShift);
@@ -1472,11 +1481,17 @@ runtime_mid()
return m->id;
}
-int32 runtime_Goroutines (void)
- __asm__ ("libgo_runtime.runtime.Goroutines");
+int32 runtime_NumGoroutine (void)
+ __asm__ ("libgo_runtime.runtime.NumGoroutine");
+
+int32
+runtime_NumGoroutine()
+{
+ return runtime_sched.gcount;
+}
int32
-runtime_Goroutines()
+runtime_gcount(void)
{
return runtime_sched.gcount;
}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 713af174491..113bb7163c5 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -143,6 +143,8 @@ struct G
M* lockedm;
M* idlem;
// int32 sig;
+ int32 writenbuf;
+ byte* writebuf;
// uintptr sigcode0;
// uintptr sigcode1;
// uintptr sigpc;
@@ -189,9 +191,9 @@ struct SigTab
enum
{
SigNotify = 1<<0, // let signal.Notify have signal, even if from kernel
- SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly
- SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
- SigPanic = 1<<3, // if the signal is from the kernel, panic
+ SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly
+ SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
+ SigPanic = 1<<3, // if the signal is from the kernel, panic
SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
};
@@ -277,6 +279,7 @@ void runtime_panicstring(const char*) __attribute__ ((noreturn));
void* runtime_mal(uintptr);
void runtime_schedinit(void);
void runtime_initsig(void);
+void runtime_sigenable(uint32 sig);
String runtime_gostringnocopy(const byte*);
void* runtime_mstart(void*);
G* runtime_malg(int32, byte**, size_t*);
@@ -296,6 +299,7 @@ int64 runtime_cputicks(void);
void runtime_stoptheworld(void);
void runtime_starttheworld(bool);
+extern uint32 runtime_worldsema;
G* __go_go(void (*pfn)(void*), void*);
/*
@@ -348,6 +352,7 @@ void runtime_futexwakeup(uint32*, uint32);
#define runtime_munmap munmap
#define runtime_madvise madvise
#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
+#define runtime_getcallerpc(p) __builtin_return_address(0)
#ifdef __rtems__
void __wrap_rtems_task_variable_add(void **);
@@ -373,8 +378,6 @@ void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
#define runtime_exit(s) exit(s)
MCache* runtime_allocmcache(void);
void free(void *v);
-struct __go_func_type;
-bool runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
#define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
#define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
#define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
@@ -384,6 +387,11 @@ bool runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *
#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+struct __go_func_type;
+bool runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
+#define runtime_getcallersp(p) __builtin_frame_address(1)
+int32 runtime_mcount(void);
+int32 runtime_gcount(void);
void runtime_dopanic(int32) __attribute__ ((noreturn));
void runtime_startpanic(void);
void runtime_ready(G*);
diff --git a/libgo/runtime/sema.goc b/libgo/runtime/sema.goc
index dd58cf38fb8..ff9c4f2e19e 100644
--- a/libgo/runtime/sema.goc
+++ b/libgo/runtime/sema.goc
@@ -17,7 +17,7 @@
// See Mullender and Cox, ``Semaphores in Plan 9,''
// http://swtch.com/semaphore.pdf
-package runtime
+package sync
#include "runtime.h"
#include "arch.h"
@@ -172,10 +172,10 @@ runtime_semrelease(uint32 volatile *addr)
runtime_ready(s->g);
}
-func Semacquire(addr *uint32) {
+func runtime_Semacquire(addr *uint32) {
runtime_semacquire(addr);
}
-func Semrelease(addr *uint32) {
+func runtime_Semrelease(addr *uint32) {
runtime_semrelease(addr);
}
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
index c550a4ebe9b..be7c5920cbc 100644
--- a/libgo/runtime/sigqueue.goc
+++ b/libgo/runtime/sigqueue.goc
@@ -142,10 +142,12 @@ func signal_enable(s uint32) {
// Special case: want everything.
for(i=0; (size_t)i<nelem(sig.wanted); i++)
sig.wanted[i] = ~(uint32)0;
+ runtime_sigenable(s);
return;
}
if(s >= nelem(sig.wanted)*32)
return;
sig.wanted[s/32] |= 1U<<(s&31);
+ runtime_sigenable(s);
}