aboutsummaryrefslogtreecommitdiff
path: root/libgo/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-01-13 05:11:45 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-01-13 05:11:45 +0000
commitdf4aa89a5e7acb315655f193e7f549e8d32367e2 (patch)
treeeb5eccc07097c5fcf940967f33ab84a7d47c96fe /libgo/go
parentf83fa0bf8f411697ec908cfa86ee6faf4cd9c476 (diff)
downloadgcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.zip
gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.gz
gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.bz2
libgo: Update to weekly.2011-12-22.
From-SVN: r183150
Diffstat (limited to 'libgo/go')
-rw-r--r--libgo/go/archive/zip/reader_test.go4
-rw-r--r--libgo/go/archive/zip/struct.go16
-rw-r--r--libgo/go/archive/zip/zip_test.go11
-rw-r--r--libgo/go/bytes/buffer_test.go1
-rw-r--r--libgo/go/bytes/bytes_test.go17
-rw-r--r--libgo/go/bytes/example_test.go24
-rw-r--r--libgo/go/crypto/aes/aes_test.go2
-rw-r--r--libgo/go/crypto/crypto.go3
-rw-r--r--libgo/go/crypto/openpgp/keys.go1
-rw-r--r--libgo/go/crypto/rand/rand_unix.go2
-rw-r--r--libgo/go/crypto/tls/common.go4
-rw-r--r--libgo/go/crypto/tls/handshake_client.go2
-rw-r--r--libgo/go/crypto/tls/key_agreement.go4
-rw-r--r--libgo/go/crypto/tls/root_darwin.go2
-rw-r--r--libgo/go/crypto/tls/root_stub.go2
-rw-r--r--libgo/go/crypto/x509/cert_pool.go3
-rw-r--r--libgo/go/crypto/x509/verify_test.go12
-rw-r--r--libgo/go/crypto/x509/x509.go1
-rw-r--r--libgo/go/debug/gosym/pclntab_test.go3
-rw-r--r--libgo/go/encoding/binary/binary_test.go58
-rw-r--r--libgo/go/encoding/binary/varint_test.go2
-rw-r--r--libgo/go/encoding/gob/codec_test.go3
-rw-r--r--libgo/go/encoding/gob/encode.go16
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go48
-rw-r--r--libgo/go/encoding/gob/timing_test.go2
-rw-r--r--libgo/go/encoding/gob/type.go1
-rw-r--r--libgo/go/encoding/json/bench_test.go10
-rw-r--r--libgo/go/encoding/json/decode.go71
-rw-r--r--libgo/go/encoding/json/decode_test.go39
-rw-r--r--libgo/go/encoding/json/encode.go25
-rw-r--r--libgo/go/encoding/xml/marshal_test.go2
-rw-r--r--libgo/go/exp/inotify/inotify_linux_test.go5
-rw-r--r--libgo/go/exp/sql/sql.go41
-rw-r--r--libgo/go/exp/sql/sql_test.go25
-rw-r--r--libgo/go/exp/ssh/client_auth.go4
-rw-r--r--libgo/go/exp/ssh/client_auth_test.go10
-rw-r--r--libgo/go/exp/ssh/client_func_test.go2
-rw-r--r--libgo/go/exp/ssh/server.go12
-rw-r--r--libgo/go/exp/ssh/session.go59
-rw-r--r--libgo/go/exp/ssh/session_test.go2
-rw-r--r--libgo/go/exp/ssh/tcpip.go1
-rw-r--r--libgo/go/exp/terminal/terminal.go206
-rw-r--r--libgo/go/exp/terminal/terminal_test.go2
-rw-r--r--libgo/go/exp/terminal/util.go17
-rw-r--r--libgo/go/exp/winfsnotify/winfsnotify.go2
-rw-r--r--libgo/go/exp/winfsnotify/winfsnotify_test.go2
-rw-r--r--libgo/go/exp/wingui/gui.go2
-rw-r--r--libgo/go/exp/wingui/winapi.go2
-rw-r--r--libgo/go/exp/wingui/zwinapi.go1
-rw-r--r--libgo/go/fmt/fmt_test.go98
-rw-r--r--libgo/go/fmt/format.go93
-rw-r--r--libgo/go/fmt/print.go8
-rw-r--r--libgo/go/go/ast/scope.go8
-rw-r--r--libgo/go/go/build/build_test.go14
-rw-r--r--libgo/go/go/build/dir.go77
-rw-r--r--libgo/go/go/build/path.go10
-rw-r--r--libgo/go/go/doc/doc.go391
-rw-r--r--libgo/go/go/doc/exports.go167
-rw-r--r--libgo/go/go/doc/filter.go105
-rw-r--r--libgo/go/go/parser/parser.go62
-rw-r--r--libgo/go/go/printer/nodes.go23
-rw-r--r--libgo/go/go/printer/printer.go145
-rw-r--r--libgo/go/go/printer/testdata/comments.golden5
-rw-r--r--libgo/go/go/printer/testdata/comments.input6
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden21
-rw-r--r--libgo/go/go/printer/testdata/declarations.input26
-rw-r--r--libgo/go/go/printer/testdata/statements.golden2
-rw-r--r--libgo/go/go/scanner/scanner.go27
-rw-r--r--libgo/go/go/scanner/scanner_test.go14
-rw-r--r--libgo/go/html/const.go12
-rw-r--r--libgo/go/html/parse.go87
-rw-r--r--libgo/go/html/parse_test.go3
-rw-r--r--libgo/go/html/template/error.go6
-rw-r--r--libgo/go/html/template/escape.go10
-rw-r--r--libgo/go/html/template/escape_test.go12
-rw-r--r--libgo/go/image/color/ycbcr.go99
-rw-r--r--libgo/go/image/color/ycbcr_test.go (renamed from libgo/go/image/ycbcr/ycbcr_test.go)2
-rw-r--r--libgo/go/image/draw/bench_test.go15
-rw-r--r--libgo/go/image/draw/draw.go19
-rw-r--r--libgo/go/image/draw/draw_test.go5
-rw-r--r--libgo/go/image/jpeg/reader.go15
-rw-r--r--libgo/go/image/jpeg/writer.go6
-rw-r--r--libgo/go/image/jpeg/writer_test.go2
-rw-r--r--libgo/go/image/png/writer_test.go4
-rw-r--r--libgo/go/image/tiff/reader_test.go2
-rw-r--r--libgo/go/image/ycbcr.go87
-rw-r--r--libgo/go/image/ycbcr/ycbcr.go184
-rw-r--r--libgo/go/io/ioutil/ioutil_test.go31
-rw-r--r--libgo/go/log/syslog/syslog.go4
-rw-r--r--libgo/go/math/all_test.go4
-rw-r--r--libgo/go/math/big/int_test.go7
-rw-r--r--libgo/go/math/big/nat.go6
-rw-r--r--libgo/go/math/big/nat_test.go3
-rw-r--r--libgo/go/math/sin.go1
-rw-r--r--libgo/go/mime/type_unix.go2
-rw-r--r--libgo/go/net/cgo_stub.go2
-rw-r--r--libgo/go/net/dial.go66
-rw-r--r--libgo/go/net/dial_test.go88
-rw-r--r--libgo/go/net/dnsclient_unix.go2
-rw-r--r--libgo/go/net/dnsconfig.go2
-rw-r--r--libgo/go/net/fd.go10
-rw-r--r--libgo/go/net/fd_linux.go16
-rw-r--r--libgo/go/net/fd_netbsd.go116
-rw-r--r--libgo/go/net/fd_openbsd.go1
-rw-r--r--libgo/go/net/file.go2
-rw-r--r--libgo/go/net/http/client.go17
-rw-r--r--libgo/go/net/http/jar.go30
-rw-r--r--libgo/go/net/http/readrequest_test.go2
-rw-r--r--libgo/go/net/http/request_test.go18
-rw-r--r--libgo/go/net/http/serve_test.go6
-rw-r--r--libgo/go/net/interface_bsd.go97
-rw-r--r--libgo/go/net/interface_linux.go73
-rw-r--r--libgo/go/net/interface_netbsd.go14
-rw-r--r--libgo/go/net/interface_test.go57
-rw-r--r--libgo/go/net/ip.go3
-rw-r--r--libgo/go/net/ipraw_test.go1
-rw-r--r--libgo/go/net/iprawsock_posix.go2
-rw-r--r--libgo/go/net/ipsock_posix.go2
-rw-r--r--libgo/go/net/lookup_unix.go2
-rw-r--r--libgo/go/net/net.go8
-rw-r--r--libgo/go/net/newpollserver.go2
-rw-r--r--libgo/go/net/port.go2
-rw-r--r--libgo/go/net/rpc/server_test.go20
-rw-r--r--libgo/go/net/sendfile_stub.go2
-rw-r--r--libgo/go/net/sock.go2
-rw-r--r--libgo/go/net/sock_bsd.go2
-rw-r--r--libgo/go/net/tcpsock_posix.go2
-rw-r--r--libgo/go/net/textproto/reader_test.go2
-rw-r--r--libgo/go/net/udpsock_posix.go2
-rw-r--r--libgo/go/net/unixsock_posix.go2
-rw-r--r--libgo/go/old/regexp/all_test.go12
-rw-r--r--libgo/go/old/template/template_test.go18
-rw-r--r--libgo/go/os/dir_unix.go2
-rw-r--r--libgo/go/os/error_posix.go2
-rw-r--r--libgo/go/os/exec/exec.go3
-rw-r--r--libgo/go/os/exec/exec_test.go50
-rw-r--r--libgo/go/os/exec/lp_unix.go2
-rw-r--r--libgo/go/os/exec_posix.go6
-rw-r--r--libgo/go/os/exec_unix.go2
-rw-r--r--libgo/go/os/file_posix.go35
-rw-r--r--libgo/go/os/file_unix.go41
-rw-r--r--libgo/go/os/os_test.go2
-rw-r--r--libgo/go/os/os_unix_test.go2
-rw-r--r--libgo/go/os/path_unix.go2
-rw-r--r--libgo/go/os/signal/signal.go4
-rw-r--r--libgo/go/os/signal/signal_test.go2
-rw-r--r--libgo/go/os/sys_bsd.go2
-rw-r--r--libgo/go/os/user/lookup_stubs.go2
-rw-r--r--libgo/go/os/user/lookup_unix.go1
-rw-r--r--libgo/go/path/filepath/path.go27
-rw-r--r--libgo/go/path/filepath/path_test.go67
-rw-r--r--libgo/go/path/filepath/path_unix.go2
-rw-r--r--libgo/go/path/path.go18
-rw-r--r--libgo/go/path/path_test.go39
-rw-r--r--libgo/go/regexp/all_test.go12
-rw-r--r--libgo/go/regexp/exec_test.go2
-rw-r--r--libgo/go/sort/sort.go4
-rw-r--r--libgo/go/strconv/atof.go23
-rw-r--r--libgo/go/strconv/atof_test.go67
-rw-r--r--libgo/go/strconv/decimal.go6
-rw-r--r--libgo/go/strconv/extfloat.go311
-rw-r--r--libgo/go/strconv/ftoa.go6
-rw-r--r--libgo/go/strings/strings_test.go7
-rw-r--r--libgo/go/syscall/bpf_bsd.go2
-rw-r--r--libgo/go/syscall/env_unix.go2
-rw-r--r--libgo/go/syscall/exec_unix.go2
-rw-r--r--libgo/go/syscall/route_bsd.go25
-rw-r--r--libgo/go/syscall/route_netbsd.go35
-rw-r--r--libgo/go/syscall/sockcmsg_unix.go2
-rw-r--r--libgo/go/syscall/socket_linux.go3
-rw-r--r--libgo/go/syscall/syscall_unix.go2
-rw-r--r--libgo/go/testing/benchmark.go71
-rw-r--r--libgo/go/testing/example.go9
-rw-r--r--libgo/go/testing/testing.go122
-rw-r--r--libgo/go/testing/wrapper.go105
-rw-r--r--libgo/go/text/template/exec.go10
-rw-r--r--libgo/go/text/template/exec_test.go7
-rw-r--r--libgo/go/time/sys_unix.go2
-rw-r--r--libgo/go/time/time.go72
-rw-r--r--libgo/go/time/time_test.go92
-rw-r--r--libgo/go/time/zoneinfo_unix.go2
-rw-r--r--libgo/go/websocket/server.go2
182 files changed, 3533 insertions, 1206 deletions
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index 9594fe8..0e40268 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -163,10 +163,10 @@ func readTestZip(t *testing.T, zt ZipTest) {
done := make(chan bool)
for i := 0; i < 5; i++ {
for j, ft := range zt.File {
- go func() {
+ go func(j int, ft ZipTestFile) {
readTestFile(t, ft, z.File[j])
done <- true
- }()
+ }(j, ft)
n++
}
}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index c53a83c..34a87fa 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -96,12 +96,28 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
)
}
+// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
+func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
+ t = t.In(time.UTC)
+ fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
+ fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
+ return
+}
+
// ModTime returns the modification time.
// The resolution is 2s.
func (h *FileHeader) ModTime() time.Time {
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
}
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// The resolution is 2s.
+func (h *FileHeader) SetModTime(t time.Time) {
+ h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
+}
+
// traditional names for Unix constants
const (
s_IFMT = 0xf000
diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go
index 2075715..8aab2b6 100644
--- a/libgo/go/archive/zip/zip_test.go
+++ b/libgo/go/archive/zip/zip_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"testing"
+ "time"
)
type stringReaderAt string
@@ -55,3 +56,13 @@ func TestOver65kFiles(t *testing.T) {
}
}
}
+
+func TestModTime(t *testing.T) {
+ var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC)
+ fh := new(FileHeader)
+ fh.SetModTime(testTime)
+ outTime := fh.ModTime()
+ if !outTime.Equal(testTime) {
+ t.Errorf("times don't match: got %s, want %s", outTime, testTime)
+ }
+}
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
index 5235970..adb9330 100644
--- a/libgo/go/bytes/buffer_test.go
+++ b/libgo/go/bytes/buffer_test.go
@@ -16,7 +16,6 @@ const N = 10000 // make this bigger for a larger (and slower) test
var data string // test data for write tests
var bytes []byte // test data; same as data but as a slice.
-
func init() {
bytes = make([]byte, N)
for i := 0; i < N; i++ {
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index a2a08c2..2a1d41b 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -289,8 +289,7 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
for i := 0; i < b.N; i++ {
j := index(buf, 'x')
if j != n-1 {
- println("bad index", j)
- panic("bad index")
+ b.Fatal("bad index", j)
}
}
buf[n-1] = '\x00'
@@ -317,7 +316,7 @@ func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
for i := 0; i < b.N; i++ {
eq := equal(buf1, buf2)
if !eq {
- panic("bad equal")
+ b.Fatal("bad equal")
}
}
buf1[n-1] = '\x00'
@@ -339,8 +338,7 @@ func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ {
j := index(buf, buf[n-7:])
if j != n-7 {
- println("bad index", j)
- panic("bad index")
+ b.Fatal("bad index", j)
}
}
buf[n-1] = '\x00'
@@ -362,8 +360,7 @@ func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ {
j := index(buf, buf[n-7:])
if j != n-7 {
- println("bad index", j)
- panic("bad index")
+ b.Fatal("bad index", j)
}
}
buf[n-1] = '\x00'
@@ -385,8 +382,7 @@ func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ {
j := count(buf, buf[n-7:])
if j != 1 {
- println("bad count", j)
- panic("bad count")
+ b.Fatal("bad count", j)
}
}
buf[n-1] = '\x00'
@@ -408,8 +404,7 @@ func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ {
j := count(buf, buf[n-7:])
if j != 1 {
- println("bad count", j)
- panic("bad count")
+ b.Fatal("bad count", j)
}
}
buf[n-1] = '\x00'
diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go
new file mode 100644
index 0000000..02da1ac
--- /dev/null
+++ b/libgo/go/bytes/example_test.go
@@ -0,0 +1,24 @@
+package bytes_test
+
+import (
+ . "bytes"
+ "encoding/base64"
+ "io"
+ "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)
+}
+
+// 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)
+}
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go
index aa1d0df..e500c66 100644
--- a/libgo/go/crypto/aes/aes_test.go
+++ b/libgo/go/crypto/aes/aes_test.go
@@ -356,7 +356,7 @@ func BenchmarkEncrypt(b *testing.B) {
tt := encryptTests[0]
c, err := NewCipher(tt.key)
if err != nil {
- panic("NewCipher")
+ b.Fatal("NewCipher:", err)
}
out := make([]byte, len(tt.in))
b.StartTimer()
diff --git a/libgo/go/crypto/crypto.go b/libgo/go/crypto/crypto.go
index 53672a4..c913494 100644
--- a/libgo/go/crypto/crypto.go
+++ b/libgo/go/crypto/crypto.go
@@ -71,3 +71,6 @@ func RegisterHash(h Hash, f func() hash.Hash) {
}
hashes[h] = f
}
+
+// PrivateKey represents a private key using an unspecified algorithm.
+type PrivateKey interface{}
diff --git a/libgo/go/crypto/openpgp/keys.go b/libgo/go/crypto/openpgp/keys.go
index df39970..74e7d23 100644
--- a/libgo/go/crypto/openpgp/keys.go
+++ b/libgo/go/crypto/openpgp/keys.go
@@ -16,6 +16,7 @@ import (
// PublicKeyType is the armor type for a PGP public key.
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
+
// PrivateKeyType is the armor type for a PGP private key.
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go
index d9cddf6..5d4fc81 100644
--- a/libgo/go/crypto/rand/rand_unix.go
+++ b/libgo/go/crypto/rand/rand_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Unix cryptographically secure pseudorandom number
// generator.
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index f57d932..a461ad9 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -5,8 +5,8 @@
package tls
import (
+ "crypto"
"crypto/rand"
- "crypto/rsa"
"crypto/x509"
"io"
"strings"
@@ -255,7 +255,7 @@ func (c *Config) BuildNameToCertificate() {
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
- PrivateKey *rsa.PrivateKey
+ PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index e39e59c..7364800 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -234,7 +234,7 @@ func (c *Conn) clientHandshake() error {
digest := make([]byte, 0, 36)
digest = finishedHash.serverMD5.Sum(digest)
digest = finishedHash.serverSHA1.Sum(digest)
- signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest)
+ signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, digest)
if err != nil {
return c.sendAlert(alertInternalError)
}
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
index b531717..c3c1664 100644
--- a/libgo/go/crypto/tls/key_agreement.go
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -44,7 +44,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
ciphertext = ckx.ciphertext[2:]
}
- err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
+ err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
if err != nil {
return nil, err
}
@@ -147,7 +147,7 @@ Curve:
copy(serverECDHParams[4:], ecdhePublic)
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
- sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
+ sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
if err != nil {
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
}
diff --git a/libgo/go/crypto/tls/root_darwin.go b/libgo/go/crypto/tls/root_darwin.go
index 1512241..db1b18b 100644
--- a/libgo/go/crypto/tls/root_darwin.go
+++ b/libgo/go/crypto/tls/root_darwin.go
@@ -8,7 +8,7 @@ package tls
// Note: We disable -Werror here because the code in this file uses a deprecated API to stay
// compatible with both Mac OS X 10.6 and 10.7. Using a deprecated function on Darwin generates
// a warning.
-#cgo CFLAGS: -Wno-error
+#cgo CFLAGS: -Wno-error -Wno-deprecated-declarations
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
diff --git a/libgo/go/crypto/tls/root_stub.go b/libgo/go/crypto/tls/root_stub.go
index 18dcb02..d00493a 100644
--- a/libgo/go/crypto/tls/root_stub.go
+++ b/libgo/go/crypto/tls/root_stub.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.
-// +build plan9
+// +build plan9 darwin/nocgo
package tls
diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go
index adc7f9b..5a0a876 100644
--- a/libgo/go/crypto/x509/cert_pool.go
+++ b/libgo/go/crypto/x509/cert_pool.go
@@ -28,6 +28,9 @@ func NewCertPool() *CertPool {
// given certificate. If no such certificate can be found or the signature
// doesn't match, it returns nil.
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int) {
+ if s == nil {
+ return
+ }
var candidates []int
if len(cert.AuthorityKeyId) > 0 {
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index df54430..2016858 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -19,6 +19,7 @@ type verifyTest struct {
roots []string
currentTime int64
dnsName string
+ nilRoots bool
errorCallback func(*testing.T, int, error) bool
expectedChains [][]string
@@ -48,6 +49,14 @@ var verifyTests = []verifyTest{
{
leaf: googleLeaf,
intermediates: []string{thawteIntermediate},
+ nilRoots: true, // verifies that we don't crash
+ currentTime: 1302726541,
+ dnsName: "www.google.com",
+ errorCallback: expectAuthorityUnknown,
+ },
+ {
+ leaf: googleLeaf,
+ intermediates: []string{thawteIntermediate},
roots: []string{verisignRoot},
currentTime: 1,
dnsName: "www.example.com",
@@ -136,6 +145,9 @@ func TestVerify(t *testing.T) {
DNSName: test.dnsName,
CurrentTime: time.Unix(test.currentTime, 0),
}
+ if test.nilRoots {
+ opts.Roots = nil
+ }
for j, root := range test.roots {
ok := opts.Roots.AppendCertsFromPEM([]byte(root))
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index 65ca315..28c7880 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -981,6 +981,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
// CRL.
var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+
// pemType is the type of a PEM encoded CRL.
var pemType = "X509 CRL"
diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go
index 562e7a0..e5c2988 100644
--- a/libgo/go/debug/gosym/pclntab_test.go
+++ b/libgo/go/debug/gosym/pclntab_test.go
@@ -13,7 +13,8 @@ import (
func dotest() bool {
// For now, only works on ELF platforms.
- return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+ // TODO: convert to work with new go tool
+ return false && syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
}
func getTable(t *testing.T) *Table {
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index fd4fdb0..3e7057e 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -171,11 +171,42 @@ func (br *byteSliceReader) Read(p []byte) (int, error) {
return n, nil
}
-func BenchmarkRead(b *testing.B) {
+func BenchmarkReadSlice1000Int32s(b *testing.B) {
+ bsr := &byteSliceReader{}
+ slice := make([]int32, 1000)
+ buf := make([]byte, len(slice)*4)
+ b.SetBytes(int64(len(buf)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bsr.remain = buf
+ Read(bsr, BigEndian, slice)
+ }
+}
+
+func BenchmarkReadStruct(b *testing.B) {
+ bsr := &byteSliceReader{}
+ var buf bytes.Buffer
+ Write(&buf, BigEndian, &s)
+ n := TotalSize(reflect.ValueOf(s))
+ b.SetBytes(int64(n))
+ t := s
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bsr.remain = buf.Bytes()
+ Read(bsr, BigEndian, &t)
+ }
+ b.StopTimer()
+ if !reflect.DeepEqual(s, t) {
+ b.Fatal("no match")
+ }
+}
+
+func BenchmarkReadInts(b *testing.B) {
var ls Struct
bsr := &byteSliceReader{}
var r io.Reader = bsr
-
+ b.SetBytes(2 * (1 + 2 + 4 + 8))
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
bsr.remain = big
Read(r, BigEndian, &ls.Int8)
@@ -196,25 +227,19 @@ func BenchmarkRead(b *testing.B) {
for i := range want.Array {
want.Array[i] = 0
}
+ b.StopTimer()
if !reflect.DeepEqual(ls, want) {
panic("no match")
}
}
-func BenchmarkWrite(b *testing.B) {
+func BenchmarkWriteInts(b *testing.B) {
buf := new(bytes.Buffer)
var w io.Writer = buf
-
+ b.SetBytes(2 * (1 + 2 + 4 + 8))
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
buf.Reset()
- Write(w, BigEndian, &s.Int8)
- Write(w, BigEndian, &s.Int16)
- Write(w, BigEndian, &s.Int32)
- Write(w, BigEndian, &s.Int64)
- Write(w, BigEndian, &s.Uint8)
- Write(w, BigEndian, &s.Uint16)
- Write(w, BigEndian, &s.Uint32)
- Write(w, BigEndian, &s.Uint64)
Write(w, BigEndian, s.Int8)
Write(w, BigEndian, s.Int16)
Write(w, BigEndian, s.Int32)
@@ -224,11 +249,8 @@ func BenchmarkWrite(b *testing.B) {
Write(w, BigEndian, s.Uint32)
Write(w, BigEndian, s.Uint64)
}
-
- if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
- panic("first half doesn't match")
- }
- if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
- panic("second half doesn't match")
+ b.StopTimer()
+ if !bytes.Equal(buf.Bytes(), big[:30]) {
+ b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
}
}
diff --git a/libgo/go/encoding/binary/varint_test.go b/libgo/go/encoding/binary/varint_test.go
index b553d6d..dc550f2 100644
--- a/libgo/go/encoding/binary/varint_test.go
+++ b/libgo/go/encoding/binary/varint_test.go
@@ -165,6 +165,7 @@ func TestNonCanonicalZero(t *testing.T) {
func BenchmarkPutUvarint32(b *testing.B) {
buf := make([]byte, MaxVarintLen32)
+ b.SetBytes(4)
for i := 0; i < b.N; i++ {
for j := uint(0); j < MaxVarintLen32; j++ {
PutUvarint(buf, 1<<(j*7))
@@ -174,6 +175,7 @@ func BenchmarkPutUvarint32(b *testing.B) {
func BenchmarkPutUvarint64(b *testing.B) {
buf := make([]byte, MaxVarintLen64)
+ b.SetBytes(8)
for i := 0; i < b.N; i++ {
for j := uint(0); j < MaxVarintLen64; j++ {
PutUvarint(buf, 1<<(j*7))
diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go
index dc0e007..73844b9 100644
--- a/libgo/go/encoding/gob/codec_test.go
+++ b/libgo/go/encoding/gob/codec_test.go
@@ -102,12 +102,15 @@ func TestIntCodec(t *testing.T) {
// The result of encoding a true boolean with field number 7
var boolResult = []byte{0x07, 0x01}
+
// The result of encoding a number 17 with field number 7
var signedResult = []byte{0x07, 2 * 17}
var unsignedResult = []byte{0x07, 17}
var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+
// The result of encoding a number 17+19i with field number 7
var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+
// The result of encoding "hello" with field number 7
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go
index c7e4823..f05b17c 100644
--- a/libgo/go/encoding/gob/encode.go
+++ b/libgo/go/encoding/gob/encode.go
@@ -469,7 +469,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
// isZero returns whether the value is the zero of its type.
func isZero(val reflect.Value) bool {
switch val.Kind() {
- case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ case reflect.Array:
+ for i := 0; i < val.Len(); i++ {
+ if !isZero(val.Index(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Map, reflect.Slice, reflect.String:
return val.Len() == 0
case reflect.Bool:
return !val.Bool()
@@ -483,6 +490,13 @@ func isZero(val reflect.Value) bool {
return val.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return val.Uint() == 0
+ case reflect.Struct:
+ for i := 0; i < val.NumField(); i++ {
+ if !isZero(val.Field(i)) {
+ return false
+ }
+ }
+ return true
}
panic("unknown type in isZero " + val.Type().String())
}
diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go
index eacfd84..b8dfeeb 100644
--- a/libgo/go/encoding/gob/gobencdec_test.go
+++ b/libgo/go/encoding/gob/gobencdec_test.go
@@ -13,6 +13,7 @@ import (
"io"
"strings"
"testing"
+ "time"
)
// Types that implement the GobEncoder/Decoder interfaces.
@@ -526,3 +527,50 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
t.Errorf("got = %q, want %q", got, gdb)
}
}
+
+// Another bug: this caused a crash with the new Go1 Time type.
+// We throw in a gob-encoding array, to test another case of isZero
+
+type isZeroBug struct {
+ T time.Time
+ S string
+ I int
+ A isZeroBugArray
+}
+
+type isZeroBugArray [2]uint8
+
+// Receiver is value, not pointer, to test isZero of array.
+func (a isZeroBugArray) GobEncode() (b []byte, e error) {
+ b = append(b, a[:]...)
+ return b, nil
+}
+
+func (a *isZeroBugArray) GobDecode(data []byte) error {
+ println("DECODE")
+ if len(data) != len(a) {
+ return io.EOF
+ }
+ a[0] = data[0]
+ a[1] = data[1]
+ return nil
+}
+
+func TestGobEncodeIsZero(t *testing.T) {
+ x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(x)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ var y isZeroBug
+ dec := NewDecoder(b)
+ err = dec.Decode(&y)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if x != y {
+ t.Fatalf("%v != %v", x, y)
+ }
+}
diff --git a/libgo/go/encoding/gob/timing_test.go b/libgo/go/encoding/gob/timing_test.go
index 47437a6..1017eb7 100644
--- a/libgo/go/encoding/gob/timing_test.go
+++ b/libgo/go/encoding/gob/timing_test.go
@@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
func BenchmarkEndToEndPipe(b *testing.B) {
r, w, err := os.Pipe()
if err != nil {
- panic("can't get pipe:" + err.Error())
+ b.Fatal("can't get pipe:", err)
}
benchmarkEndToEnd(r, w, b)
}
diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go
index 1b20843..71a28be 100644
--- a/libgo/go/encoding/gob/type.go
+++ b/libgo/go/encoding/gob/type.go
@@ -130,6 +130,7 @@ func userType(rt reflect.Type) *userTypeInfo {
}
return ut
}
+
// A typeId represents a gob Type as an integer that can be passed on the wire.
// Internally, typeIds are used as keys to a map to recover the underlying type info.
type typeId int32
diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go
index f0c5201..333c1c0 100644
--- a/libgo/go/encoding/json/bench_test.go
+++ b/libgo/go/encoding/json/bench_test.go
@@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) {
enc := NewEncoder(ioutil.Discard)
for i := 0; i < b.N; i++ {
if err := enc.Encode(&codeStruct); err != nil {
- panic(err)
+ b.Fatal("Encode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
@@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) {
}
for i := 0; i < b.N; i++ {
if _, err := Marshal(&codeStruct); err != nil {
- panic(err)
+ b.Fatal("Marshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
@@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) {
buf.WriteByte('\n')
buf.WriteByte('\n')
if err := dec.Decode(&r); err != nil {
- panic(err)
+ b.Fatal("Decode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
@@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
var r codeResponse
if err := Unmarshal(codeJSON, &r); err != nil {
- panic(err)
+ b.Fatal("Unmmarshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
@@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
var r codeResponse
for i := 0; i < b.N; i++ {
if err := Unmarshal(codeJSON, &r); err != nil {
- panic(err)
+ b.Fatal("Unmmarshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 0a70092..8287b33 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) {
// Feed in an empty string - the shortest, simplest value -
// so that it knows we got to the end of the value.
if d.scan.redo {
- panic("redo")
+ // rewind.
+ d.scan.redo = false
+ d.scan.step = stateBeginValue
}
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
@@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) {
}
v = pv
- // Decoding into nil interface? Switch to non-reflect code.
- iv := v
- ok := iv.Kind() == reflect.Interface
- if ok {
- iv.Set(reflect.ValueOf(d.arrayInterface()))
- return
- }
-
// Check type of target.
- av := v
- if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
+ switch v.Kind() {
+ default:
d.saveError(&UnmarshalTypeError{"array", v.Type()})
d.off--
d.next()
return
+ case reflect.Interface:
+ // Decoding into nil interface? Switch to non-reflect code.
+ v.Set(reflect.ValueOf(d.arrayInterface()))
+ return
+ case reflect.Array:
+ case reflect.Slice:
+ break
}
- sv := v
-
i := 0
for {
// Look ahead for ] - can only happen on first iteration.
@@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) {
d.scan.undo(op)
// Get element of array, growing if necessary.
- if i >= av.Cap() && sv.IsValid() {
- newcap := sv.Cap() + sv.Cap()/2
- if newcap < 4 {
- newcap = 4
+ if v.Kind() == reflect.Slice {
+ // Grow slice if necessary
+ if i >= v.Cap() {
+ newcap := v.Cap() + v.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
+ reflect.Copy(newv, v)
+ v.Set(newv)
+ }
+ if i >= v.Len() {
+ v.SetLen(i + 1)
}
- newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
- reflect.Copy(newv, sv)
- sv.Set(newv)
- }
- if i >= av.Len() && sv.IsValid() {
- // Must be slice; gave up on array during i >= av.Cap().
- sv.SetLen(i + 1)
}
- // Decode into element.
- if i < av.Len() {
- d.value(av.Index(i))
+ if i < v.Len() {
+ // Decode into element.
+ d.value(v.Index(i))
} else {
// Ran out of fixed array: skip.
d.value(reflect.Value{})
@@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) {
}
}
- if i < av.Len() {
- if !sv.IsValid() {
+ if i < v.Len() {
+ if v.Kind() == reflect.Array {
// Array. Zero the rest.
- z := reflect.Zero(av.Type().Elem())
- for ; i < av.Len(); i++ {
- av.Index(i).Set(z)
+ z := reflect.Zero(v.Type().Elem())
+ for ; i < v.Len(); i++ {
+ v.Index(i).Set(z)
}
} else {
- sv.SetLen(i)
+ v.SetLen(i)
}
}
- if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() {
- sv.Set(reflect.MakeSlice(sv.Type(), 0, 0))
+ if i == 0 && v.Kind() == reflect.Slice {
+ v.Set(reflect.MakeSlice(v.Type(), 0, 0))
}
}
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index bf3953e..05c8a06 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -6,6 +6,7 @@ package json
import (
"bytes"
+ "fmt"
"reflect"
"strings"
"testing"
@@ -73,6 +74,12 @@ var unmarshalTests = []unmarshalTest{
// syntax errors
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
+ {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
+
+ // array tests
+ {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
+ {`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
+ {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
// composite tests
{allValueIndent, new(All), allValue, nil},
@@ -242,6 +249,38 @@ func TestHTMLEscape(t *testing.T) {
}
}
+// WrongString is a struct that's misusing the ,string modifier.
+type WrongString struct {
+ Message string `json:"result,string"`
+}
+
+type wrongStringTest struct {
+ in, err string
+}
+
+// TODO(bradfitz): as part of Issue 2331, fix these tests' expected
+// error values to be helpful, rather than the confusing messages they
+// are now.
+var wrongStringTests = []wrongStringTest{
+ {`{"result":"x"}`, "JSON decoder out of sync - data changing underfoot?"},
+ {`{"result":"foo"}`, "json: cannot unmarshal bool into Go value of type string"},
+ {`{"result":"123"}`, "json: cannot unmarshal number into Go value of type string"},
+}
+
+// If people misuse the ,string modifier, the error message should be
+// helpful, telling the user that they're doing it wrong.
+func TestErrorMessageFromMisusedString(t *testing.T) {
+ for n, tt := range wrongStringTests {
+ r := strings.NewReader(tt.in)
+ var s WrongString
+ err := NewDecoder(r).Decode(&s)
+ got := fmt.Sprintf("%v", err)
+ if got != tt.err {
+ t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
+ }
+ }
+}
+
func noSpace(c rune) rune {
if isSpace(c) {
return -1
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index ff8e80c..3d2f4fc 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -197,6 +197,7 @@ var hex = "0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
type encodeState struct {
bytes.Buffer // accumulated output
+ scratch [64]byte
}
func (e *encodeState) marshal(v interface{}) (err error) {
@@ -275,14 +276,26 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- writeString(e, strconv.FormatInt(v.Int(), 10))
-
+ b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- writeString(e, strconv.FormatUint(v.Uint(), 10))
-
+ b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.Float32, reflect.Float64:
- writeString(e, strconv.FormatFloat(v.Float(), 'g', -1, v.Type().Bits()))
-
+ b := strconv.AppendFloat(e.scratch[:0], v.Float(), 'g', -1, v.Type().Bits())
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.String:
if quoted {
sb, err := Marshal(v.String())
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index 8040765..6a24169 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -394,7 +394,7 @@ func TestUnmarshal(t *testing.T) {
if err != nil {
t.Errorf("#%d: unexpected error: %#v", i, err)
} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
- t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
+ t.Errorf("#%d: unmarshal(%q) = %#v, want %#v", i, test.ExpectXML, got, want)
}
}
}
diff --git a/libgo/go/exp/inotify/inotify_linux_test.go b/libgo/go/exp/inotify/inotify_linux_test.go
index 92384b6..d035ec1 100644
--- a/libgo/go/exp/inotify/inotify_linux_test.go
+++ b/libgo/go/exp/inotify/inotify_linux_test.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 linux
+
package inotify
import (
@@ -17,6 +19,9 @@ func TestInotifyEvents(t *testing.T) {
t.Fatalf("NewWatcher() failed: %s", err)
}
+ t.Logf("NEEDS TO BE CONVERTED TO NEW GO TOOL") // TODO
+ return
+
// Add a watch for "_test"
err = watcher.Watch("_test")
if err != nil {
diff --git a/libgo/go/exp/sql/sql.go b/libgo/go/exp/sql/sql.go
index 948b911..937982c 100644
--- a/libgo/go/exp/sql/sql.go
+++ b/libgo/go/exp/sql/sql.go
@@ -22,10 +22,10 @@ var drivers = make(map[string]driver.Driver)
// it panics.
func Register(name string, driver driver.Driver) {
if driver == nil {
- panic("db: Register driver is nil")
+ panic("sql: Register driver is nil")
}
if _, dup := drivers[name]; dup {
- panic("db: Register called twice for driver " + name)
+ panic("sql: Register called twice for driver " + name)
}
drivers[name] = driver
}
@@ -80,7 +80,7 @@ type ScannerInto interface {
// ErrNoRows is returned by Scan when QueryRow doesn't return a
// row. In such a case, QueryRow returns a placeholder *Row value that
// defers this error until a Scan.
-var ErrNoRows = errors.New("db: no rows in result set")
+var ErrNoRows = errors.New("sql: no rows in result set")
// DB is a database handle. It's safe for concurrent use by multiple
// goroutines.
@@ -102,7 +102,7 @@ type DB struct {
func Open(driverName, dataSourceName string) (*DB, error) {
driver, ok := drivers[driverName]
if !ok {
- return nil, fmt.Errorf("db: unknown driver %q (forgotten import?)", driverName)
+ return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
return &DB{driver: driver, dsn: dataSourceName}, nil
}
@@ -514,7 +514,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
// placeholders, so we won't sanity check input here and instead let the
// driver deal with errors.
if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("db: expected %d arguments, got %d", want, len(args))
+ return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
// Convert args to subset types.
@@ -522,10 +522,10 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
for n, arg := range args {
args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
if err != nil {
- return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
}
if !driver.IsParameterSubsetType(args[n]) {
- return nil, fmt.Errorf("db: driver ColumnConverter error converted %T to unsupported type %T",
+ return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
arg, args[n])
}
}
@@ -533,7 +533,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
for n, arg := range args {
args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
if err != nil {
- return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
}
}
}
@@ -555,7 +555,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
s.mu.Lock()
if s.closed {
s.mu.Unlock()
- err = errors.New("db: statement is closed")
+ err = errors.New("sql: statement is closed")
return
}
@@ -617,7 +617,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
// placeholders, so we won't sanity check input here and instead let the
// driver deal with errors.
if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("db: statement expects %d inputs; got %d", si.NumInput(), len(args))
+ return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
}
sargs, err := subsetTypeArgs(args)
if err != nil {
@@ -737,27 +737,40 @@ func (rs *Rows) Err() error {
return rs.lasterr
}
+// Columns returns the column names.
+// Columns returns an error if the rows are closed, or if the rows
+// are from QueryRow and there was a deferred error.
+func (rs *Rows) Columns() ([]string, error) {
+ if rs.closed {
+ return nil, errors.New("sql: Rows are closed")
+ }
+ if rs.rowsi == nil {
+ return nil, errors.New("sql: no Rows available")
+ }
+ return rs.rowsi.Columns(), nil
+}
+
// Scan copies the columns in the current row into the values pointed
// at by dest. If dest contains pointers to []byte, the slices should
// not be modified and should only be considered valid until the next
// call to Next or Scan.
func (rs *Rows) Scan(dest ...interface{}) error {
if rs.closed {
- return errors.New("db: Rows closed")
+ return errors.New("sql: Rows closed")
}
if rs.lasterr != nil {
return rs.lasterr
}
if rs.lastcols == nil {
- return errors.New("db: Scan called without calling Next")
+ return errors.New("sql: Scan called without calling Next")
}
if len(dest) != len(rs.lastcols) {
- return fmt.Errorf("db: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
+ return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
}
for i, sv := range rs.lastcols {
err := convertAssign(dest[i], sv)
if err != nil {
- return fmt.Errorf("db: Scan error on column index %d: %v", i, err)
+ return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
}
}
return nil
diff --git a/libgo/go/exp/sql/sql_test.go b/libgo/go/exp/sql/sql_test.go
index f8ccf76..5307a23 100644
--- a/libgo/go/exp/sql/sql_test.go
+++ b/libgo/go/exp/sql/sql_test.go
@@ -75,6 +75,23 @@ func TestQuery(t *testing.T) {
}
}
+func TestRowsColumns(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ cols, err := rows.Columns()
+ if err != nil {
+ t.Fatalf("Columns: %v", err)
+ }
+ want := []string{"age", "name"}
+ if !reflect.DeepEqual(cols, want) {
+ t.Errorf("got %#v; want %#v", cols, want)
+ }
+}
+
func TestQueryRow(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -187,12 +204,12 @@ func TestExec(t *testing.T) {
{[]interface{}{7, 9}, ""},
// Invalid conversions:
- {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "db: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
- {[]interface{}{"Brad", "strconv fail"}, "db: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+ {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
+ {[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
// Wrong number of args:
- {[]interface{}{}, "db: expected 2 arguments, got 0"},
- {[]interface{}{1, 2, 3}, "db: expected 2 arguments, got 3"},
+ {[]interface{}{}, "sql: expected 2 arguments, got 0"},
+ {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
}
for n, et := range execTests {
_, err := stmt.Exec(et.args...)
diff --git a/libgo/go/exp/ssh/client_auth.go b/libgo/go/exp/ssh/client_auth.go
index 1a38235..3a7e9fb 100644
--- a/libgo/go/exp/ssh/client_auth.go
+++ b/libgo/go/exp/ssh/client_auth.go
@@ -283,8 +283,8 @@ func (p *publickeyAuth) method() string {
return "publickey"
}
-// ClientAuthPublickey returns a ClientAuth using public key authentication.
-func ClientAuthPublickey(impl ClientKeyring) ClientAuth {
+// ClientAuthKeyring returns a ClientAuth using public key authentication.
+func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
return &publickeyAuth{impl}
}
diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go
index 2b89e97..c41a93b 100644
--- a/libgo/go/exp/ssh/client_auth_test.go
+++ b/libgo/go/exp/ssh/client_auth_test.go
@@ -122,7 +122,7 @@ var (
PasswordCallback: func(user, pass string) bool {
return user == "testuser" && pass == string(clientPassword)
},
- PubKeyCallback: func(user, algo string, pubkey []byte) bool {
+ PublicKeyCallback: func(user, algo string, pubkey []byte) bool {
key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey
expected := []byte(serializePublickey(key))
algoname := algoName(key)
@@ -179,7 +179,7 @@ func TestClientAuthPublickey(t *testing.T) {
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
- ClientAuthPublickey(clientKeychain),
+ ClientAuthKeyring(clientKeychain),
},
}
c, err := Dial("tcp", newMockAuthServer(t), config)
@@ -210,7 +210,7 @@ func TestClientAuthWrongPassword(t *testing.T) {
User: "testuser",
Auth: []ClientAuth{
ClientAuthPassword(wrongPw),
- ClientAuthPublickey(clientKeychain),
+ ClientAuthKeyring(clientKeychain),
},
}
@@ -228,7 +228,7 @@ func TestClientAuthInvalidPublickey(t *testing.T) {
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
- ClientAuthPublickey(kc),
+ ClientAuthKeyring(kc),
},
}
@@ -246,7 +246,7 @@ func TestClientAuthRSAandDSA(t *testing.T) {
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
- ClientAuthPublickey(kc),
+ ClientAuthKeyring(kc),
},
}
c, err := Dial("tcp", newMockAuthServer(t), config)
diff --git a/libgo/go/exp/ssh/client_func_test.go b/libgo/go/exp/ssh/client_func_test.go
index 24e3a63..b4bdba9 100644
--- a/libgo/go/exp/ssh/client_func_test.go
+++ b/libgo/go/exp/ssh/client_func_test.go
@@ -50,7 +50,7 @@ func TestFuncPublickeyAuth(t *testing.T) {
config := &ClientConfig{
User: *sshuser,
Auth: []ClientAuth{
- ClientAuthPublickey(kc),
+ ClientAuthKeyring(kc),
},
}
conn, err := Dial("tcp", "localhost:22", config)
diff --git a/libgo/go/exp/ssh/server.go b/libgo/go/exp/ssh/server.go
index 1eee9a4..31011c6 100644
--- a/libgo/go/exp/ssh/server.go
+++ b/libgo/go/exp/ssh/server.go
@@ -36,10 +36,10 @@ type ServerConfig struct {
// several goroutines.
PasswordCallback func(user, password string) bool
- // PubKeyCallback, if non-nil, is called when a client attempts public
+ // PublicKeyCallback, if non-nil, is called when a client attempts public
// key authentication. It must return true iff the given public key is
// valid for the given user.
- PubKeyCallback func(user, algo string, pubkey []byte) bool
+ PublicKeyCallback func(user, algo string, pubkey []byte) bool
// Cryptographic-related configuration.
Crypto CryptoConfig
@@ -359,7 +359,7 @@ func isAcceptableAlgo(algo string) bool {
// testPubKey returns true if the given public key is acceptable for the user.
func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
- if s.config.PubKeyCallback == nil || !isAcceptableAlgo(algo) {
+ if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
return false
}
@@ -369,7 +369,7 @@ func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
}
}
- result := s.config.PubKeyCallback(user, algo, pubKey)
+ result := s.config.PublicKeyCallback(user, algo, pubKey)
if len(s.cachedPubKeys) < maxCachedPubKeys {
c := cachedPubKey{
user: user,
@@ -425,7 +425,7 @@ userAuthLoop:
break userAuthLoop
}
case "publickey":
- if s.config.PubKeyCallback == nil {
+ if s.config.PublicKeyCallback == nil {
break
}
payload := userAuthReq.Payload
@@ -499,7 +499,7 @@ userAuthLoop:
if s.config.PasswordCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "password")
}
- if s.config.PubKeyCallback != nil {
+ if s.config.PublicKeyCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "publickey")
}
diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go
index bf9a88e..807dd87 100644
--- a/libgo/go/exp/ssh/session.go
+++ b/libgo/go/exp/ssh/session.go
@@ -68,10 +68,12 @@ type Session struct {
*clientChan // the channel backing this session
- started bool // true once Start, Run or Shell is invoked.
- closeAfterWait []io.Closer
- copyFuncs []func() error
- errch chan error // one send per copyFunc
+ started bool // true once Start, Run or Shell is invoked.
+ copyFuncs []func() error
+ errch chan error // one send per copyFunc
+
+ // true if pipe method is active
+ stdinpipe, stdoutpipe, stderrpipe bool
}
// RFC 4254 Section 6.4.
@@ -237,11 +239,9 @@ func (s *Session) waitForResponse() error {
func (s *Session) start() error {
s.started = true
- type F func(*Session) error
+ type F func(*Session)
for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
- if err := setupFd(s); err != nil {
- return err
- }
+ setupFd(s)
}
s.errch = make(chan error, len(s.copyFuncs))
@@ -274,9 +274,6 @@ func (s *Session) Wait() error {
copyError = err
}
}
- for _, fd := range s.closeAfterWait {
- fd.Close()
- }
if waitErr != nil {
return waitErr
}
@@ -341,7 +338,10 @@ func (s *Session) wait() error {
return &ExitError{wm}
}
-func (s *Session) stdin() error {
+func (s *Session) stdin() {
+ if s.stdinpipe {
+ return
+ }
if s.Stdin == nil {
s.Stdin = new(bytes.Buffer)
}
@@ -352,10 +352,12 @@ func (s *Session) stdin() error {
}
return err
})
- return nil
}
-func (s *Session) stdout() error {
+func (s *Session) stdout() {
+ if s.stdoutpipe {
+ return
+ }
if s.Stdout == nil {
s.Stdout = ioutil.Discard
}
@@ -363,10 +365,12 @@ func (s *Session) stdout() error {
_, err := io.Copy(s.Stdout, s.clientChan.stdout)
return err
})
- return nil
}
-func (s *Session) stderr() error {
+func (s *Session) stderr() {
+ if s.stderrpipe {
+ return
+ }
if s.Stderr == nil {
s.Stderr = ioutil.Discard
}
@@ -374,7 +378,6 @@ func (s *Session) stderr() error {
_, err := io.Copy(s.Stderr, s.clientChan.stderr)
return err
})
- return nil
}
// StdinPipe returns a pipe that will be connected to the
@@ -386,10 +389,8 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
if s.started {
return nil, errors.New("ssh: StdinPipe after process started")
}
- pr, pw := io.Pipe()
- s.Stdin = pr
- s.closeAfterWait = append(s.closeAfterWait, pr)
- return pw, nil
+ s.stdinpipe = true
+ return s.clientChan.stdin, nil
}
// StdoutPipe returns a pipe that will be connected to the
@@ -398,17 +399,15 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
// stdout and stderr streams. If the StdoutPipe reader is
// not serviced fast enought it may eventually cause the
// remote command to block.
-func (s *Session) StdoutPipe() (io.ReadCloser, error) {
+func (s *Session) StdoutPipe() (io.Reader, error) {
if s.Stdout != nil {
return nil, errors.New("ssh: Stdout already set")
}
if s.started {
return nil, errors.New("ssh: StdoutPipe after process started")
}
- pr, pw := io.Pipe()
- s.Stdout = pw
- s.closeAfterWait = append(s.closeAfterWait, pw)
- return pr, nil
+ s.stdoutpipe = true
+ return s.clientChan.stdout, nil
}
// StderrPipe returns a pipe that will be connected to the
@@ -417,17 +416,15 @@ func (s *Session) StdoutPipe() (io.ReadCloser, error) {
// stdout and stderr streams. If the StderrPipe reader is
// not serviced fast enought it may eventually cause the
// remote command to block.
-func (s *Session) StderrPipe() (io.ReadCloser, error) {
+func (s *Session) StderrPipe() (io.Reader, error) {
if s.Stderr != nil {
return nil, errors.New("ssh: Stderr already set")
}
if s.started {
return nil, errors.New("ssh: StderrPipe after process started")
}
- pr, pw := io.Pipe()
- s.Stderr = pw
- s.closeAfterWait = append(s.closeAfterWait, pw)
- return pr, nil
+ s.stderrpipe = true
+ return s.clientChan.stderr, nil
}
// TODO(dfc) add Output and CombinedOutput helpers
diff --git a/libgo/go/exp/ssh/session_test.go b/libgo/go/exp/ssh/session_test.go
index a28ead0..2882620 100644
--- a/libgo/go/exp/ssh/session_test.go
+++ b/libgo/go/exp/ssh/session_test.go
@@ -20,7 +20,7 @@ func dial(handler serverType, t *testing.T) *ClientConn {
serverConfig.PasswordCallback = func(user, pass string) bool {
return user == "testuser" && pass == string(pw)
}
- serverConfig.PubKeyCallback = nil
+ serverConfig.PublicKeyCallback = nil
l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
if err != nil {
diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go
index a85044a..bee41ee 100644
--- a/libgo/go/exp/ssh/tcpip.go
+++ b/libgo/go/exp/ssh/tcpip.go
@@ -10,6 +10,7 @@ import (
"io"
"net"
)
+
// Dial initiates a connection to the addr from the remote host.
// addr is resolved using net.ResolveTCPAddr before connection.
// This could allow an observer to observe the DNS name of the
diff --git a/libgo/go/exp/terminal/terminal.go b/libgo/go/exp/terminal/terminal.go
index 18d76cd..809e88c 100644
--- a/libgo/go/exp/terminal/terminal.go
+++ b/libgo/go/exp/terminal/terminal.go
@@ -2,13 +2,56 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux
+
package terminal
-import "io"
+import (
+ "io"
+ "sync"
+)
+
+// EscapeCodes contains escape sequences that can be written to the terminal in
+// order to achieve different styles of text.
+type EscapeCodes struct {
+ // Foreground colors
+ Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
+
+ // Reset all attributes
+ Reset []byte
+}
+
+var vt100EscapeCodes = EscapeCodes{
+ Black: []byte{keyEscape, '[', '3', '0', 'm'},
+ Red: []byte{keyEscape, '[', '3', '1', 'm'},
+ Green: []byte{keyEscape, '[', '3', '2', 'm'},
+ Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
+ Blue: []byte{keyEscape, '[', '3', '4', 'm'},
+ Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
+ Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
+ White: []byte{keyEscape, '[', '3', '7', 'm'},
+
+ Reset: []byte{keyEscape, '[', '0', 'm'},
+}
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal struct {
+ // AutoCompleteCallback, if non-null, is called for each keypress
+ // with the full input line and the current position of the cursor.
+ // If it returns a nil newLine, the key press is processed normally.
+ // Otherwise it returns a replacement line and the new cursor position.
+ AutoCompleteCallback func(line []byte, pos, key int) (newLine []byte, newPos int)
+
+ // Escape contains a pointer to the escape codes for this terminal.
+ // It's always a valid pointer, although the escape codes themselves
+ // may be empty if the terminal doesn't support them.
+ Escape *EscapeCodes
+
+ // lock protects the terminal and the state in this object from
+ // concurrent processing of a key press and a Write() call.
+ lock sync.Mutex
+
c io.ReadWriter
prompt string
@@ -16,6 +59,8 @@ type Terminal struct {
line []byte
// pos is the logical position of the cursor in line
pos int
+ // echo is true if local echo is enabled
+ echo bool
// cursorX contains the current X value of the cursor where the left
// edge is 0. cursorY contains the row number where the first row of
@@ -40,10 +85,12 @@ type Terminal struct {
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return &Terminal{
+ Escape: &vt100EscapeCodes,
c: c,
prompt: prompt,
termWidth: 80,
termHeight: 24,
+ echo: true,
}
}
@@ -109,18 +156,11 @@ func bytesToKey(b []byte) (int, []byte) {
// queue appends data to the end of t.outBuf
func (t *Terminal) queue(data []byte) {
- if len(t.outBuf)+len(data) > cap(t.outBuf) {
- newOutBuf := make([]byte, len(t.outBuf), 2*(len(t.outBuf)+len(data)))
- copy(newOutBuf, t.outBuf)
- t.outBuf = newOutBuf
- }
-
- oldLen := len(t.outBuf)
- t.outBuf = t.outBuf[:len(t.outBuf)+len(data)]
- copy(t.outBuf[oldLen:], data)
+ t.outBuf = append(t.outBuf, data...)
}
var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
+var space = []byte{' '}
func isPrintable(key int) bool {
return key >= 32 && key < 127
@@ -129,6 +169,10 @@ func isPrintable(key int) bool {
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
// given, logical position in the text.
func (t *Terminal) moveCursorToPos(pos int) {
+ if !t.echo {
+ return
+ }
+
x := len(t.prompt) + pos
y := x / t.termWidth
x = x % t.termWidth
@@ -153,6 +197,12 @@ func (t *Terminal) moveCursorToPos(pos int) {
right = x - t.cursorX
}
+ t.cursorX = x
+ t.cursorY = y
+ t.move(up, down, left, right)
+}
+
+func (t *Terminal) move(up, down, left, right int) {
movement := make([]byte, 3*(up+down+left+right))
m := movement
for i := 0; i < up; i++ {
@@ -180,11 +230,14 @@ func (t *Terminal) moveCursorToPos(pos int) {
m = m[3:]
}
- t.cursorX = x
- t.cursorY = y
t.queue(movement)
}
+func (t *Terminal) clearLineToRight() {
+ op := []byte{keyEscape, '[', 'K'}
+ t.queue(op)
+}
+
const maxLineLength = 4096
// handleKey processes the given key and, optionally, returns a line of text
@@ -196,12 +249,15 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
return
}
t.pos--
+ t.moveCursorToPos(t.pos)
copy(t.line[t.pos:], t.line[1+t.pos:])
t.line = t.line[:len(t.line)-1]
- t.writeLine(t.line[t.pos:])
- t.moveCursorToPos(t.pos)
+ if t.echo {
+ t.writeLine(t.line[t.pos:])
+ }
t.queue(eraseUnderCursor)
+ t.moveCursorToPos(t.pos)
case keyAltLeft:
// move left by a word.
if t.pos == 0 {
@@ -260,6 +316,25 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
t.cursorY = 0
t.maxLine = 0
default:
+ if t.AutoCompleteCallback != nil {
+ t.lock.Unlock()
+ newLine, newPos := t.AutoCompleteCallback(t.line, t.pos, key)
+ t.lock.Lock()
+
+ if newLine != nil {
+ if t.echo {
+ t.moveCursorToPos(0)
+ t.writeLine(newLine)
+ for i := len(newLine); i < len(t.line); i++ {
+ t.writeLine(space)
+ }
+ t.moveCursorToPos(newPos)
+ }
+ t.line = newLine
+ t.pos = newPos
+ return
+ }
+ }
if !isPrintable(key) {
return
}
@@ -274,7 +349,9 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
t.line = t.line[:len(t.line)+1]
copy(t.line[t.pos+1:], t.line[t.pos:])
t.line[t.pos] = byte(key)
- t.writeLine(t.line[t.pos:])
+ if t.echo {
+ t.writeLine(t.line[t.pos:])
+ }
t.pos++
t.moveCursorToPos(t.pos)
}
@@ -283,15 +360,6 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
func (t *Terminal) writeLine(line []byte) {
for len(line) != 0 {
- if t.cursorX == t.termWidth {
- t.queue([]byte("\r\n"))
- t.cursorX = 0
- t.cursorY++
- if t.cursorY > t.maxLine {
- t.maxLine = t.cursorY
- }
- }
-
remainingOnLine := t.termWidth - t.cursorX
todo := len(line)
if todo > remainingOnLine {
@@ -300,16 +368,95 @@ func (t *Terminal) writeLine(line []byte) {
t.queue(line[:todo])
t.cursorX += todo
line = line[todo:]
+
+ if t.cursorX == t.termWidth {
+ t.cursorX = 0
+ t.cursorY++
+ if t.cursorY > t.maxLine {
+ t.maxLine = t.cursorY
+ }
+ }
}
}
func (t *Terminal) Write(buf []byte) (n int, err error) {
- return t.c.Write(buf)
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ if t.cursorX == 0 && t.cursorY == 0 {
+ // This is the easy case: there's nothing on the screen that we
+ // have to move out of the way.
+ return t.c.Write(buf)
+ }
+
+ // 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.cursorX = 0
+ t.clearLineToRight()
+
+ for t.cursorY > 0 {
+ t.move(1, /* up */ 0, 0, 0)
+ t.cursorY--
+ t.clearLineToRight()
+ }
+
+ if _, err = t.c.Write(t.outBuf); err != nil {
+ return
+ }
+ t.outBuf = t.outBuf[:0]
+
+ if n, err = t.c.Write(buf); err != nil {
+ return
+ }
+
+ t.queue([]byte(t.prompt))
+ chars := len(t.prompt)
+ if t.echo {
+ t.queue(t.line)
+ chars += len(t.line)
+ }
+ t.cursorX = chars % t.termWidth
+ t.cursorY = chars / t.termWidth
+ t.moveCursorToPos(t.pos)
+
+ if _, err = t.c.Write(t.outBuf); err != nil {
+ return
+ }
+ t.outBuf = t.outBuf[:0]
+ return
+}
+
+// ReadPassword temporarily changes the prompt and reads a password, without
+// echo, from the terminal.
+func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ oldPrompt := t.prompt
+ t.prompt = prompt
+ t.echo = false
+
+ line, err = t.readLine()
+
+ t.prompt = oldPrompt
+ t.echo = true
+
+ return
}
// ReadLine returns a line of input from the terminal.
func (t *Terminal) ReadLine() (line string, err error) {
- if t.cursorX == 0 {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ return t.readLine()
+}
+
+func (t *Terminal) readLine() (line string, err error) {
+ // t.lock must be held at this point
+
+ if t.cursorX == 0 && t.cursorY == 0 {
t.writeLine([]byte(t.prompt))
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
@@ -320,7 +467,11 @@ func (t *Terminal) ReadLine() (line string, err error) {
// containing a partial key sequence
readBuf := t.inBuf[len(t.remainder):]
var n int
+
+ t.lock.Unlock()
n, err = t.c.Read(readBuf)
+ t.lock.Lock()
+
if err != nil {
return
}
@@ -358,5 +509,8 @@ func (t *Terminal) ReadLine() (line string, err error) {
}
func (t *Terminal) SetSize(width, height int) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
t.termWidth, t.termHeight = width, height
}
diff --git a/libgo/go/exp/terminal/terminal_test.go b/libgo/go/exp/terminal/terminal_test.go
index a219721..75628f6 100644
--- a/libgo/go/exp/terminal/terminal_test.go
+++ b/libgo/go/exp/terminal/terminal_test.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 linux
+
package terminal
import (
diff --git a/libgo/go/exp/terminal/util.go b/libgo/go/exp/terminal/util.go
index 0303567..a5bbfca 100644
--- a/libgo/go/exp/terminal/util.go
+++ b/libgo/go/exp/terminal/util.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 linux
+
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
@@ -9,7 +11,7 @@
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
-// panic(err.String())
+// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal
@@ -17,6 +19,7 @@ package terminal
import (
"io"
"syscall"
+ "unsafe"
)
// State contains the state of a terminal.
@@ -57,6 +60,18 @@ func Restore(fd int, state *State) error {
return err
}
+func ioctl(int, int, unsafe.Pointer) int __asm__("ioctl")
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ var dimensions [4]uint16
+
+ if ioctl(fd, syscall.TIOCGWINSZ, unsafe.Pointer(&dimensions)) < 0 {
+ return -1, -1, syscall.GetErrno()
+ }
+ return int(dimensions[1]), int(dimensions[0]), nil
+}
+
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
diff --git a/libgo/go/exp/winfsnotify/winfsnotify.go b/libgo/go/exp/winfsnotify/winfsnotify.go
index d47ffd1..a6e3a6a 100644
--- a/libgo/go/exp/winfsnotify/winfsnotify.go
+++ b/libgo/go/exp/winfsnotify/winfsnotify.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
+
// Package winfsnotify allows the user to receive
// file system event notifications on Windows.
package winfsnotify
diff --git a/libgo/go/exp/winfsnotify/winfsnotify_test.go b/libgo/go/exp/winfsnotify/winfsnotify_test.go
index b9c43d9..59ac162 100644
--- a/libgo/go/exp/winfsnotify/winfsnotify_test.go
+++ b/libgo/go/exp/winfsnotify/winfsnotify_test.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
+
package winfsnotify
import (
diff --git a/libgo/go/exp/wingui/gui.go b/libgo/go/exp/wingui/gui.go
index d58421b..3b79873 100644
--- a/libgo/go/exp/wingui/gui.go
+++ b/libgo/go/exp/wingui/gui.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
+
package main
import (
diff --git a/libgo/go/exp/wingui/winapi.go b/libgo/go/exp/wingui/winapi.go
index 24f3dd4..f876088 100644
--- a/libgo/go/exp/wingui/winapi.go
+++ b/libgo/go/exp/wingui/winapi.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
+
package main
import (
diff --git a/libgo/go/exp/wingui/zwinapi.go b/libgo/go/exp/wingui/zwinapi.go
index b062ca3..5666c6d 100644
--- a/libgo/go/exp/wingui/zwinapi.go
+++ b/libgo/go/exp/wingui/zwinapi.go
@@ -1,3 +1,4 @@
+// +build windows
// mksyscall_windows.pl winapi.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index d7fe296..d34a4f8 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -506,78 +506,42 @@ func BenchmarkSprintfFloat(b *testing.B) {
}
}
+var mallocBuf bytes.Buffer
+
+var mallocTest = []struct {
+ count int
+ desc string
+ fn func()
+}{
+ {0, `Sprintf("")`, func() { Sprintf("") }},
+ {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
+ {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
+ {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
+ {1, `Sprintf("%x %x")`, func() { Sprintf("%x", 7, 112) }},
+ {1, `Sprintf("%g")`, func() { Sprintf("%g", 3.14159) }},
+ {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+ {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+}
+
+var _ bytes.Buffer
+
func TestCountMallocs(t *testing.T) {
if testing.Short() {
return
}
- const N = 100
- runtime.UpdateMemStats()
- mallocs := 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("xxx")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("%x", i)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("%s", "hello")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%s\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("%x %x", i, i)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- Sprintf("%g", 3.14159)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%g\"): %d\n", mallocs/N)
- buf := new(bytes.Buffer)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- buf.Reset()
- Fprintf(buf, "%x %x %x", i, i, i)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Fprintf(buf, \"%%x %%x %%x\"): %d\n", mallocs/N)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < N; i++ {
- buf.Reset()
- Fprintf(buf, "%s", "hello")
+ for _, mt := range mallocTest {
+ const N = 100
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ for i := 0; i < N; i++ {
+ mt.fn()
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ if mallocs/N != uint64(mt.count) {
+ t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
+ }
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Fprintf(buf, \"%%s\"): %d\n", mallocs/N)
}
type flagPrinter struct{}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index 5f62c06..78d9e99 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
return i - 1
}
+var (
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+)
+
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
- f.padString("true")
+ f.pad(trueBytes)
} else {
- f.padString("false")
+ f.pad(falseBytes)
}
}
@@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) {
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s string) {
- t := ""
+func (f *fmt) fmt_sx(s, digits string) {
+ // TODO: Avoid buffer by pre-padding.
+ var b bytes.Buffer
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
- t += " "
+ b.WriteByte(' ')
}
v := s[i]
- t += string(ldigits[v>>4])
- t += string(ldigits[v&0xF])
+ b.WriteByte(digits[v>>4])
+ b.WriteByte(digits[v&0xF])
}
- f.padString(t)
-}
-
-// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sX(s string) {
- t := ""
- for i := 0; i < len(s); i++ {
- if i > 0 && f.space {
- t += " "
- }
- v := s[i]
- t += string(udigits[v>>4])
- t += string(udigits[v&0xF])
- }
- f.padString(t)
+ f.pad(b.Bytes())
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
@@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) {
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmt_qc(c int64) {
- var quoted string
+ var quoted []byte
if f.plus {
- quoted = strconv.QuoteRuneToASCII(rune(c))
+ quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
} else {
- quoted = strconv.QuoteRune(rune(c))
+ quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
}
- f.padString(quoted)
+ f.pad(quoted)
}
// floating-point
@@ -347,57 +339,70 @@ func doPrec(f *fmt, def int) int {
return def
}
-// Add a plus sign or space to the floating-point string representation if missing and required.
-func (f *fmt) plusSpace(s string) {
- if s[0] != '-' {
+// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
+func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
+ // We leave one byte at the beginning of f.intbuf for a sign if needed,
+ // and make it a space, which we might be able to use.
+ f.intbuf[0] = ' '
+ slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ // Add a plus sign or space to the floating-point string representation if missing and required.
+ // The formatted number starts at slice[1].
+ switch slice[1] {
+ case '-', '+':
+ // We're set; drop the leading space.
+ slice = slice[1:]
+ default:
+ // There's no sign, but we might need one.
if f.plus {
- s = "+" + s
+ slice[0] = '+'
} else if f.space {
- s = " " + s
+ // space is already there
+ } else {
+ slice = slice[1:]
}
}
- f.padString(s)
+ f.pad(slice)
}
// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'e', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'E', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'f', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'g', doPrec(f, -1), 64)) }
+func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'G', doPrec(f, -1), 64)) }
+func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'b', 0, 64)) }
+func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'e', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'E', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'f', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'g', doPrec(f, -1), 32)) }
+func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'G', doPrec(f, -1), 32)) }
+func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.FormatFloat(float64(v), 'b', 0, 32)) }
+func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
func (f *fmt) fmt_c64(v complex64, verb rune) {
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 9f157da..3b7d346 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -503,9 +503,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
case 's':
p.fmt.fmt_s(v)
case 'x':
- p.fmt.fmt_sx(v)
+ p.fmt.fmt_sx(v, ldigits)
case 'X':
- p.fmt.fmt_sX(v)
+ p.fmt.fmt_sx(v, udigits)
case 'q':
p.fmt.fmt_q(v)
default:
@@ -542,9 +542,9 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
case 's':
p.fmt.fmt_s(s)
case 'x':
- p.fmt.fmt_sx(s)
+ p.fmt.fmt_sx(s, ldigits)
case 'X':
- p.fmt.fmt_sX(s)
+ p.fmt.fmt_sx(s, udigits)
case 'q':
p.fmt.fmt_q(s)
default:
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
index 92e3669..fbe4779 100644
--- a/libgo/go/go/ast/scope.go
+++ b/libgo/go/go/ast/scope.go
@@ -80,7 +80,7 @@ func (s *Scope) String() string {
type Object struct {
Kind ObjKind
Name string // declared name
- Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
}
@@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos {
if d.Label.Name == name {
return d.Label.Pos()
}
+ case *AssignStmt:
+ for _, x := range d.Lhs {
+ if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
+ return ident.Pos()
+ }
+ }
}
return token.NoPos
}
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
index e22a49a..fd40306 100644
--- a/libgo/go/go/build/build_test.go
+++ b/libgo/go/go/build/build_test.go
@@ -46,8 +46,9 @@ var buildPkgs = []struct {
{
"go/build/cgotest",
&DirInfo{
- CgoFiles: []string{"cgotest.go"},
+ CgoFiles: ifCgo([]string{"cgotest.go"}),
CFiles: []string{"cgotest.c"},
+ HFiles: []string{"cgotest.h"},
Imports: []string{"C", "unsafe"},
TestImports: []string{},
Package: "cgotest",
@@ -55,6 +56,13 @@ var buildPkgs = []struct {
},
}
+func ifCgo(x []string) []string {
+ if DefaultContext.CgoEnabled {
+ return x
+ }
+ return nil
+}
+
const cmdtestOutput = "3"
func TestBuild(t *testing.T) {
@@ -71,6 +79,10 @@ func TestBuild(t *testing.T) {
continue
}
+ if tt.dir == "go/build/cgotest" && len(info.CgoFiles) == 0 {
+ continue
+ }
+
s, err := Build(tree, tt.dir, info)
if err != nil {
t.Errorf("Build(%#q): %v", tt.dir, err)
diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go
index 2c89224..265261f 100644
--- a/libgo/go/go/build/dir.go
+++ b/libgo/go/go/build/dir.go
@@ -26,9 +26,9 @@ import (
// A Context specifies the supporting context for a build.
type Context struct {
- GOARCH string // target architecture
- GOOS string // target operating system
- // TODO(rsc,adg): GOPATH
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ CgoEnabled bool // whether cgo can be used
// By default, ScanDir uses the operating system's
// file system calls to read directories and files.
@@ -75,9 +75,36 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
// The DefaultContext is the default Context for builds.
// It uses the GOARCH and GOOS environment variables
// if set, or else the compiled code's GOARCH and GOOS.
-var DefaultContext = Context{
- GOARCH: envOr("GOARCH", runtime.GOARCH),
- GOOS: envOr("GOOS", runtime.GOOS),
+var DefaultContext = defaultContext()
+
+var cgoEnabled = map[string]bool{
+ "darwin/386": true,
+ "darwin/amd64": true,
+ "linux/386": true,
+ "linux/amd64": true,
+ "freebsd/386": true,
+ "freebsd/amd64": true,
+ "windows/386": true,
+ "windows/amd64": true,
+}
+
+func defaultContext() Context {
+ var c Context
+
+ c.GOARCH = envOr("GOARCH", runtime.GOARCH)
+ c.GOOS = envOr("GOOS", runtime.GOOS)
+
+ s := os.Getenv("CGO_ENABLED")
+ switch s {
+ case "1":
+ c.CgoEnabled = true
+ case "0":
+ c.CgoEnabled = false
+ default:
+ c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+ }
+
+ return c
}
func envOr(name, def string) string {
@@ -96,8 +123,9 @@ type DirInfo struct {
// Source files
GoFiles []string // .go files in dir (excluding CgoFiles)
+ HFiles []string // .h files in dir
CFiles []string // .c files in dir
- SFiles []string // .s files in dir
+ SFiles []string // .s (and, when using cgo, .S files in dir)
CgoFiles []string // .go files that import "C"
// Cgo directives
@@ -135,6 +163,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
return nil, err
}
+ var Sfiles []string // files with ".S" (capital S)
var di DirInfo
imported := make(map[string]bool)
testImported := make(map[string]bool)
@@ -154,7 +183,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
ext := path.Ext(name)
switch ext {
- case ".go", ".c", ".s":
+ case ".go", ".c", ".s", ".h", ".S":
// tentatively okay
default:
// skip
@@ -175,9 +204,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
case ".c":
di.CFiles = append(di.CFiles, name)
continue
+ case ".h":
+ di.HFiles = append(di.HFiles, name)
+ continue
case ".s":
di.SFiles = append(di.SFiles, name)
continue
+ case ".S":
+ Sfiles = append(Sfiles, name)
+ continue
}
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
@@ -256,7 +291,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
}
}
if isCgo {
- di.CgoFiles = append(di.CgoFiles, name)
+ if ctxt.CgoEnabled {
+ di.CgoFiles = append(di.CgoFiles, name)
+ }
} else if isTest {
if pkg == string(pf.Name.Name) {
di.TestGoFiles = append(di.TestGoFiles, name)
@@ -282,6 +319,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
di.TestImports[i] = p
i++
}
+
+ // add the .S files only if we are using cgo
+ // (which means gcc will compile them).
+ // The standard assemblers expect .s files.
+ if len(di.CgoFiles) > 0 {
+ di.SFiles = append(di.SFiles, Sfiles...)
+ sort.Strings(di.SFiles)
+ }
+
// File name lists are sorted because ReadDir sorts.
sort.Strings(di.Imports)
sort.Strings(di.TestImports)
@@ -289,7 +335,6 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
}
var slashslash = []byte("//")
-var plusBuild = []byte("+build")
// shouldBuild reports whether it is okay to use this file,
// The rule is that in the file's leading run of // comments
@@ -510,14 +555,22 @@ func splitQuoted(s string) (r []string, err error) {
//
// $GOOS
// $GOARCH
-// $GOOS/$GOARCH
+// cgo (if cgo is enabled)
+// nocgo (if cgo is disabled)
+// a slash-separated list of any of these
//
func (ctxt *Context) matchOSArch(name string) bool {
+ if ctxt.CgoEnabled && name == "cgo" {
+ return true
+ }
+ if !ctxt.CgoEnabled && name == "nocgo" {
+ return true
+ }
if name == ctxt.GOOS || name == ctxt.GOARCH {
return true
}
i := strings.Index(name, "/")
- return i >= 0 && name[:i] == ctxt.GOOS && name[i+1:] == ctxt.GOARCH
+ return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
}
// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go
index 91d6c43..7a28180 100644
--- a/libgo/go/go/build/path.go
+++ b/libgo/go/go/build/path.go
@@ -57,7 +57,7 @@ func (t *Tree) PkgDir() string {
func (t *Tree) BinDir() string {
if t.Goroot {
if gobin := os.Getenv("GOBIN"); gobin != "" {
- return gobin
+ return filepath.Clean(gobin)
}
}
return filepath.Join(t.Path, "bin")
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
}
var (
- ErrNotFound = errors.New("go/build: package could not be found locally")
- ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
+ ErrNotFound = errors.New("package could not be found locally")
+ ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)
// FindTree takes an import or filesystem path and returns the
@@ -151,7 +151,7 @@ func init() {
root := runtime.GOROOT()
t, err := newTree(root)
if err != nil {
- log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+ log.Printf("invalid GOROOT %q: %v", root, err)
} else {
t.Goroot = true
Path = []*Tree{t}
@@ -163,7 +163,7 @@ func init() {
}
t, err := newTree(p)
if err != nil {
- log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+ log.Printf("invalid GOPATH %q: %v", p, err)
continue
}
Path = append(Path, t)
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
index 9174864..1bb2241 100644
--- a/libgo/go/go/doc/doc.go
+++ b/libgo/go/go/doc/doc.go
@@ -13,17 +13,32 @@ import (
)
// ----------------------------------------------------------------------------
+// Collection of documentation info
-type typeDoc struct {
+// embeddedType describes the type of an anonymous field.
+//
+type embeddedType struct {
+ typ *typeInfo // the corresponding base type
+ ptr bool // if set, the anonymous field type is a pointer
+}
+
+type typeInfo struct {
// len(decl.Specs) == 1, and the element type is *ast.TypeSpec
// if the type declaration hasn't been seen yet, decl is nil
- decl *ast.GenDecl
- // values, factory functions, and methods associated with the type
+ decl *ast.GenDecl
+ embedded []embeddedType
+ forward *TypeDoc // forward link to processed type documentation
+
+ // declarations associated with the type
values []*ast.GenDecl // consts and vars
factories map[string]*ast.FuncDecl
methods map[string]*ast.FuncDecl
}
+func (info *typeInfo) addEmbeddedType(embedded *typeInfo, isPtr bool) {
+ info.embedded = append(info.embedded, embeddedType{embedded, isPtr})
+}
+
// docReader accumulates documentation for a single package.
// It modifies the AST: Comments (declaration documentation)
// that have been collected by the DocReader are set to nil
@@ -32,17 +47,19 @@ type typeDoc struct {
// printing the corresponding AST node).
//
type docReader struct {
- doc *ast.CommentGroup // package documentation, if any
- pkgName string
- values []*ast.GenDecl // consts and vars
- types map[string]*typeDoc
- funcs map[string]*ast.FuncDecl
- bugs []*ast.CommentGroup
+ doc *ast.CommentGroup // package documentation, if any
+ pkgName string
+ values []*ast.GenDecl // consts and vars
+ types map[string]*typeInfo
+ embedded map[string]*typeInfo // embedded types, possibly not exported
+ funcs map[string]*ast.FuncDecl
+ bugs []*ast.CommentGroup
}
func (doc *docReader) init(pkgName string) {
doc.pkgName = pkgName
- doc.types = make(map[string]*typeDoc)
+ doc.types = make(map[string]*typeInfo)
+ doc.embedded = make(map[string]*typeInfo)
doc.funcs = make(map[string]*ast.FuncDecl)
}
@@ -52,56 +69,40 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
doc.doc = comments
return
}
-
// More than one package comment: Usually there will be only
// one file with a package comment, but it's better to collect
// all comments than drop them on the floor.
- // (This code isn't particularly clever - no amortized doubling is
- // used - but this situation occurs rarely and is not time-critical.)
- n1 := len(doc.doc.List)
- n2 := len(comments.List)
- list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
- copy(list, doc.doc.List)
- list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
- copy(list[n1+1:], comments.List)
- doc.doc = &ast.CommentGroup{list}
-}
-
-func (doc *docReader) addType(decl *ast.GenDecl) {
- spec := decl.Specs[0].(*ast.TypeSpec)
- typ := doc.lookupTypeDoc(spec.Name.Name)
- // typ should always be != nil since declared types
- // are always named - be conservative and check
- if typ != nil {
- // a type should be added at most once, so typ.decl
- // should be nil - if it isn't, simply overwrite it
- typ.decl = decl
- }
+ blankComment := &ast.Comment{token.NoPos, "//"}
+ list := append(doc.doc.List, blankComment)
+ doc.doc.List = append(list, comments.List...)
}
-func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
- if name == "" {
+func (doc *docReader) lookupTypeInfo(name string) *typeInfo {
+ if name == "" || name == "_" {
return nil // no type docs for anonymous types
}
- if tdoc, found := doc.types[name]; found {
- return tdoc
+ if info, found := doc.types[name]; found {
+ return info
}
// type wasn't found - add one without declaration
- tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
- doc.types[name] = tdoc
- return tdoc
+ info := &typeInfo{
+ factories: make(map[string]*ast.FuncDecl),
+ methods: make(map[string]*ast.FuncDecl),
+ }
+ doc.types[name] = info
+ return info
}
-func baseTypeName(typ ast.Expr) string {
+func baseTypeName(typ ast.Expr, allTypes bool) string {
switch t := typ.(type) {
case *ast.Ident:
// if the type is not exported, the effect to
// a client is as if there were no type name
- if t.IsExported() {
+ if t.IsExported() || allTypes {
return t.Name
}
case *ast.StarExpr:
- return baseTypeName(t.X)
+ return baseTypeName(t.X, allTypes)
}
return ""
}
@@ -120,7 +121,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
switch {
case v.Type != nil:
// a type is present; determine its name
- name = baseTypeName(v.Type)
+ name = baseTypeName(v.Type, false)
case decl.Tok == token.CONST:
// no type is present but we have a constant declaration;
// use the previous type name (w/o more type information
@@ -148,7 +149,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
values := &doc.values
if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
// typed entries are sufficiently frequent
- typ := doc.lookupTypeDoc(domName)
+ typ := doc.lookupTypeInfo(domName)
if typ != nil {
values = &typ.values // associate with that type
}
@@ -175,10 +176,13 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
}
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
+ // strip function body
+ fun.Body = nil
+
// determine if it should be associated with a type
if fun.Recv != nil {
// method
- typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
+ typ := doc.lookupTypeInfo(baseTypeName(fun.Recv.List[0].Type, false))
if typ != nil {
// exported receiver type
setFunc(typ.methods, fun)
@@ -199,8 +203,8 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
// exactly one (named or anonymous) result associated
// with the first type in result signature (there may
// be more than one result)
- tname := baseTypeName(res.Type)
- typ := doc.lookupTypeDoc(tname)
+ tname := baseTypeName(res.Type, false)
+ typ := doc.lookupTypeInfo(tname)
if typ != nil {
// named and exported result type
setFunc(typ.factories, fun)
@@ -224,10 +228,17 @@ func (doc *docReader) addDecl(decl ast.Decl) {
case token.TYPE:
// types are handled individually
for _, spec := range d.Specs {
- // make a (fake) GenDecl node for this TypeSpec
+ tspec := spec.(*ast.TypeSpec)
+ // add the type to the documentation
+ info := doc.lookupTypeInfo(tspec.Name.Name)
+ if info == nil {
+ continue // no name - ignore the type
+ }
+ // Make a (fake) GenDecl node for this TypeSpec
// (we need to do this here - as opposed to just
// for printing - so we don't lose the GenDecl
- // documentation)
+ // documentation). Since a new GenDecl node is
+ // created, there's no need to nil out d.Doc.
//
// TODO(gri): Consider just collecting the TypeSpec
// node (and copy in the GenDecl.doc if there is no
@@ -235,8 +246,32 @@ func (doc *docReader) addDecl(decl ast.Decl) {
// makeTypeDocs below). Simpler data structures, but
// would lose GenDecl documentation if the TypeSpec
// has documentation as well.
- doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
- // A new GenDecl node is created, no need to nil out d.Doc.
+ fake := &ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos,
+ []ast.Spec{tspec}, token.NoPos}
+ // A type should be added at most once, so info.decl
+ // should be nil - if it isn't, simply overwrite it.
+ info.decl = fake
+ // Look for anonymous fields that might contribute methods.
+ var fields *ast.FieldList
+ switch typ := spec.(*ast.TypeSpec).Type.(type) {
+ case *ast.StructType:
+ fields = typ.Fields
+ case *ast.InterfaceType:
+ fields = typ.Methods
+ }
+ if fields != nil {
+ for _, field := range fields.List {
+ if len(field.Names) == 0 {
+ // anonymous field - add corresponding type
+ // to the info and collect it in doc
+ name := baseTypeName(field.Type, true)
+ if embedded := doc.lookupTypeInfo(name); embedded != nil {
+ _, ptr := field.Type.(*ast.StarExpr)
+ info.addEmbeddedType(embedded, ptr)
+ }
+ }
+ }
+ }
}
}
}
@@ -285,19 +320,15 @@ func (doc *docReader) addFile(src *ast.File) {
src.Comments = nil // consumed unassociated comments - remove from ast.File node
}
-func NewFileDoc(file *ast.File) *PackageDoc {
- var r docReader
- r.init(file.Name.Name)
- r.addFile(file)
- return r.newDoc("", nil)
-}
-
-func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
+func NewPackageDoc(pkg *ast.Package, importpath string, exportsOnly bool) *PackageDoc {
var r docReader
r.init(pkg.Name)
filenames := make([]string, len(pkg.Files))
i := 0
for filename, f := range pkg.Files {
+ if exportsOnly {
+ r.fileExports(f)
+ }
r.addFile(f)
filenames[i] = filename
i++
@@ -397,6 +428,25 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
return d
}
+type methodSet map[string]*FuncDoc
+
+func (mset methodSet) add(m *FuncDoc) {
+ if mset[m.Name] == nil {
+ mset[m.Name] = m
+ }
+}
+
+func (mset methodSet) sortedList() []*FuncDoc {
+ list := make([]*FuncDoc, len(mset))
+ i := 0
+ for _, m := range mset {
+ list[i] = m
+ i++
+ }
+ sort.Sort(sortFuncDoc(list))
+ return list
+}
+
// TypeDoc is the documentation for a declared type.
// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
// Factories is a sorted list of factory functions that return that type.
@@ -407,7 +457,9 @@ type TypeDoc struct {
Consts []*ValueDoc
Vars []*ValueDoc
Factories []*FuncDoc
- Methods []*FuncDoc
+ methods []*FuncDoc // top-level methods only
+ embedded methodSet // embedded methods only
+ Methods []*FuncDoc // all methods including embedded ones
Decl *ast.GenDecl
order int
}
@@ -429,11 +481,17 @@ func (p sortTypeDoc) Less(i, j int) bool {
// NOTE(rsc): This would appear not to be correct for type ( )
// blocks, but the doc extractor above has split them into
// individual declarations.
-func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
- d := make([]*TypeDoc, len(m))
+func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {
+ // TODO(gri) Consider computing the embedded method information
+ // before calling makeTypeDocs. Then this function can
+ // be single-phased again. Also, it might simplify some
+ // of the logic.
+ //
+ // phase 1: associate collected declarations with TypeDocs
+ list := make([]*TypeDoc, len(m))
i := 0
for _, old := range m {
- // all typeDocs should have a declaration associated with
+ // all typeInfos should have a declaration associated with
// them after processing an entire package - be conservative
// and check
if decl := old.decl; decl != nil {
@@ -451,10 +509,16 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
t.Consts = makeValueDocs(old.values, token.CONST)
t.Vars = makeValueDocs(old.values, token.VAR)
t.Factories = makeFuncDocs(old.factories)
- t.Methods = makeFuncDocs(old.methods)
+ t.methods = makeFuncDocs(old.methods)
+ // The list of embedded types' methods is computed from the list
+ // of embedded types, some of which may not have been processed
+ // yet (i.e., their forward link is nil) - do this in a 2nd phase.
+ // The final list of methods can only be computed after that -
+ // do this in a 3rd phase.
t.Decl = old.decl
t.order = i
- d[i] = t
+ old.forward = t // old has been processed
+ list[i] = t
i++
} else {
// no corresponding type declaration found - move any associated
@@ -477,9 +541,99 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
}
}
}
- d = d[0:i] // some types may have been ignored
- sort.Sort(sortTypeDoc(d))
- return d
+ list = list[0:i] // some types may have been ignored
+
+ // phase 2: collect embedded methods for each processed typeInfo
+ for _, old := range m {
+ if t := old.forward; t != nil {
+ // old has been processed into t; collect embedded
+ // methods for t from the list of processed embedded
+ // types in old (and thus for which the methods are known)
+ typ := t.Type
+ if _, ok := typ.Type.(*ast.StructType); ok {
+ // struct
+ t.embedded = make(methodSet)
+ collectEmbeddedMethods(t.embedded, old, typ.Name.Name)
+ } else {
+ // interface
+ // TODO(gri) fix this
+ }
+ }
+ }
+
+ // phase 3: compute final method set for each TypeDoc
+ for _, d := range list {
+ if len(d.embedded) > 0 {
+ // there are embedded methods - exclude
+ // the ones with names conflicting with
+ // non-embedded methods
+ mset := make(methodSet)
+ // top-level methods have priority
+ for _, m := range d.methods {
+ mset.add(m)
+ }
+ // add non-conflicting embedded methods
+ for _, m := range d.embedded {
+ mset.add(m)
+ }
+ d.Methods = mset.sortedList()
+ } else {
+ // no embedded methods
+ d.Methods = d.methods
+ }
+ }
+
+ sort.Sort(sortTypeDoc(list))
+ return list
+}
+
+// collectEmbeddedMethods collects the embedded methods from all
+// processed embedded types found in info in mset. It considers
+// embedded types at the most shallow level first so that more
+// deeply nested embedded methods with conflicting names are
+// excluded.
+//
+func collectEmbeddedMethods(mset methodSet, info *typeInfo, recvTypeName string) {
+ for _, e := range info.embedded {
+ if e.typ.forward != nil { // == e was processed
+ for _, m := range e.typ.forward.methods {
+ mset.add(customizeRecv(m, e.ptr, recvTypeName))
+ }
+ collectEmbeddedMethods(mset, e.typ, recvTypeName)
+ }
+ }
+}
+
+func customizeRecv(m *FuncDoc, embeddedIsPtr bool, recvTypeName string) *FuncDoc {
+ if m == nil || m.Decl == nil || m.Decl.Recv == nil || len(m.Decl.Recv.List) != 1 {
+ return m // shouldn't happen, but be safe
+ }
+
+ // copy existing receiver field and set new type
+ // TODO(gri) is receiver type computation correct?
+ // what about deeply nested embeddings?
+ newField := *m.Decl.Recv.List[0]
+ _, origRecvIsPtr := newField.Type.(*ast.StarExpr)
+ var typ ast.Expr = ast.NewIdent(recvTypeName)
+ if embeddedIsPtr || origRecvIsPtr {
+ typ = &ast.StarExpr{token.NoPos, typ}
+ }
+ newField.Type = typ
+
+ // copy existing receiver field list and set new receiver field
+ newFieldList := *m.Decl.Recv
+ newFieldList.List = []*ast.Field{&newField}
+
+ // copy existing function declaration and set new receiver field list
+ newFuncDecl := *m.Decl
+ newFuncDecl.Recv = &newFieldList
+
+ // copy existing function documentation and set new declaration
+ newM := *m
+ newM.Decl = &newFuncDecl
+ newM.Recv = typ
+
+ return &newM
}
func makeBugDocs(list []*ast.CommentGroup) []string {
@@ -523,104 +677,3 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
p.Bugs = makeBugDocs(doc.bugs)
return p
}
-
-// ----------------------------------------------------------------------------
-// Filtering by name
-
-type Filter func(string) bool
-
-func matchFields(fields *ast.FieldList, f Filter) bool {
- if fields != nil {
- for _, field := range fields.List {
- for _, name := range field.Names {
- if f(name.Name) {
- return true
- }
- }
- }
- }
- return false
-}
-
-func matchDecl(d *ast.GenDecl, f Filter) bool {
- for _, d := range d.Specs {
- switch v := d.(type) {
- case *ast.ValueSpec:
- for _, name := range v.Names {
- if f(name.Name) {
- return true
- }
- }
- case *ast.TypeSpec:
- if f(v.Name.Name) {
- return true
- }
- switch t := v.Type.(type) {
- case *ast.StructType:
- if matchFields(t.Fields, f) {
- return true
- }
- case *ast.InterfaceType:
- if matchFields(t.Methods, f) {
- return true
- }
- }
- }
- }
- return false
-}
-
-func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
- w := 0
- for _, vd := range a {
- if matchDecl(vd.Decl, f) {
- a[w] = vd
- w++
- }
- }
- return a[0:w]
-}
-
-func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
- w := 0
- for _, fd := range a {
- if f(fd.Name) {
- a[w] = fd
- w++
- }
- }
- return a[0:w]
-}
-
-func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
- w := 0
- for _, td := range a {
- n := 0 // number of matches
- if matchDecl(td.Decl, f) {
- n = 1
- } else {
- // type name doesn't match, but we may have matching consts, vars, factories or methods
- td.Consts = filterValueDocs(td.Consts, f)
- td.Vars = filterValueDocs(td.Vars, f)
- td.Factories = filterFuncDocs(td.Factories, f)
- td.Methods = filterFuncDocs(td.Methods, f)
- n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
- }
- if n > 0 {
- a[w] = td
- w++
- }
- }
- return a[0:w]
-}
-
-// Filter eliminates documentation for names that don't pass through the filter f.
-// TODO: Recognize "Type.Method" as a name.
-//
-func (p *PackageDoc) Filter(f Filter) {
- p.Consts = filterValueDocs(p.Consts, f)
- p.Vars = filterValueDocs(p.Vars, f)
- p.Types = filterTypeDocs(p.Types, f)
- p.Funcs = filterFuncDocs(p.Funcs, f)
- p.Doc = "" // don't show top-level package doc
-}
diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go
new file mode 100644
index 0000000..9cd186a
--- /dev/null
+++ b/libgo/go/go/doc/exports.go
@@ -0,0 +1,167 @@
+// 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.
+
+// This file implements export filtering of an AST.
+
+package doc
+
+import "go/ast"
+
+func filterIdentList(list []*ast.Ident) []*ast.Ident {
+ j := 0
+ for _, x := range list {
+ if ast.IsExported(x.Name) {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+func baseName(x ast.Expr) *ast.Ident {
+ switch t := x.(type) {
+ case *ast.Ident:
+ return t
+ case *ast.SelectorExpr:
+ if _, ok := t.X.(*ast.Ident); ok {
+ return t.Sel
+ }
+ case *ast.StarExpr:
+ return baseName(t.X)
+ }
+ return nil
+}
+
+func (doc *docReader) filterFieldList(fields *ast.FieldList) (removedFields bool) {
+ if fields == nil {
+ return false
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ keepField := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ name := baseName(f.Type)
+ keepField = name != nil && name.IsExported()
+ } else {
+ n := len(f.Names)
+ f.Names = filterIdentList(f.Names)
+ if len(f.Names) < n {
+ removedFields = true
+ }
+ keepField = len(f.Names) > 0
+ }
+ if keepField {
+ doc.filterType(f.Type)
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
+
+func (doc *docReader) filterParamList(fields *ast.FieldList) bool {
+ if fields == nil {
+ return false
+ }
+ var b bool
+ for _, f := range fields.List {
+ if doc.filterType(f.Type) {
+ b = true
+ }
+ }
+ return b
+}
+
+func (doc *docReader) filterType(typ ast.Expr) bool {
+ switch t := typ.(type) {
+ case *ast.Ident:
+ return ast.IsExported(t.Name)
+ case *ast.ParenExpr:
+ return doc.filterType(t.X)
+ case *ast.ArrayType:
+ return doc.filterType(t.Elt)
+ case *ast.StructType:
+ if doc.filterFieldList(t.Fields) {
+ t.Incomplete = true
+ }
+ return len(t.Fields.List) > 0
+ case *ast.FuncType:
+ b1 := doc.filterParamList(t.Params)
+ b2 := doc.filterParamList(t.Results)
+ return b1 || b2
+ case *ast.InterfaceType:
+ if doc.filterFieldList(t.Methods) {
+ t.Incomplete = true
+ }
+ return len(t.Methods.List) > 0
+ case *ast.MapType:
+ b1 := doc.filterType(t.Key)
+ b2 := doc.filterType(t.Value)
+ return b1 || b2
+ case *ast.ChanType:
+ return doc.filterType(t.Value)
+ }
+ return false
+}
+
+func (doc *docReader) filterSpec(spec ast.Spec) bool {
+ switch s := spec.(type) {
+ case *ast.ValueSpec:
+ s.Names = filterIdentList(s.Names)
+ if len(s.Names) > 0 {
+ doc.filterType(s.Type)
+ return true
+ }
+ case *ast.TypeSpec:
+ if ast.IsExported(s.Name.Name) {
+ doc.filterType(s.Type)
+ return true
+ }
+ }
+ return false
+}
+
+func (doc *docReader) filterSpecList(list []ast.Spec) []ast.Spec {
+ j := 0
+ for _, s := range list {
+ if doc.filterSpec(s) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+func (doc *docReader) filterDecl(decl ast.Decl) bool {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ d.Specs = doc.filterSpecList(d.Specs)
+ return len(d.Specs) > 0
+ case *ast.FuncDecl:
+ return ast.IsExported(d.Name.Name)
+ }
+ return false
+}
+
+// fileExports trims the AST for a Go file in place such that
+// only exported nodes remain. fileExports returns true if
+// there are exported declarations; otherwise it returns false.
+//
+func (doc *docReader) fileExports(src *ast.File) bool {
+ j := 0
+ for _, d := range src.Decls {
+ if doc.filterDecl(d) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+ return j > 0
+}
diff --git a/libgo/go/go/doc/filter.go b/libgo/go/go/doc/filter.go
new file mode 100644
index 0000000..71c2ebb
--- /dev/null
+++ b/libgo/go/go/doc/filter.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import "go/ast"
+
+type Filter func(string) bool
+
+func matchFields(fields *ast.FieldList, f Filter) bool {
+ if fields != nil {
+ for _, field := range fields.List {
+ for _, name := range field.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func matchDecl(d *ast.GenDecl, f Filter) bool {
+ for _, d := range d.Specs {
+ switch v := d.(type) {
+ case *ast.ValueSpec:
+ for _, name := range v.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ case *ast.TypeSpec:
+ if f(v.Name.Name) {
+ return true
+ }
+ switch t := v.Type.(type) {
+ case *ast.StructType:
+ if matchFields(t.Fields, f) {
+ return true
+ }
+ case *ast.InterfaceType:
+ if matchFields(t.Methods, f) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+ w := 0
+ for _, vd := range a {
+ if matchDecl(vd.Decl, f) {
+ a[w] = vd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+ w := 0
+ for _, fd := range a {
+ if f(fd.Name) {
+ a[w] = fd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+ w := 0
+ for _, td := range a {
+ n := 0 // number of matches
+ if matchDecl(td.Decl, f) {
+ n = 1
+ } else {
+ // type name doesn't match, but we may have matching consts, vars, factories or methods
+ td.Consts = filterValueDocs(td.Consts, f)
+ td.Vars = filterValueDocs(td.Vars, f)
+ td.Factories = filterFuncDocs(td.Factories, f)
+ td.Methods = filterFuncDocs(td.Methods, f)
+ n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
+ }
+ if n > 0 {
+ a[w] = td
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *PackageDoc) Filter(f Filter) {
+ p.Consts = filterValueDocs(p.Consts, f)
+ p.Vars = filterValueDocs(p.Vars, f)
+ p.Types = filterTypeDocs(p.Types, f)
+ p.Funcs = filterFuncDocs(p.Funcs, f)
+ p.Doc = "" // don't show top-level package doc
+}
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index f0a8055..9fbed2d 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -144,28 +144,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
}
}
-func (p *parser) shortVarDecl(idents []*ast.Ident) {
+func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
// the same type, and at least one of the non-blank variables is new.
n := 0 // number of new variables
- for _, ident := range idents {
- assert(ident.Obj == nil, "identifier already declared or resolved")
- obj := ast.NewObj(ast.Var, ident.Name)
- // short var declarations cannot have redeclaration errors
- // and are not global => no need to remember the respective
- // declaration
- ident.Obj = obj
- if ident.Name != "_" {
- if alt := p.topScope.Insert(obj); alt != nil {
- ident.Obj = alt // redeclaration
- } else {
- n++ // new declaration
+ for _, x := range list {
+ if ident, isIdent := x.(*ast.Ident); isIdent {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // remember corresponding assignment for other tools
+ obj.Decl = decl
+ ident.Obj = obj
+ if ident.Name != "_" {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
+ n++ // new declaration
+ }
}
+ } else {
+ p.errorExpected(x.Pos(), "identifier")
}
}
if n == 0 && p.mode&DeclarationErrors != 0 {
- p.error(idents[0].Pos(), "no new variables on left side of :=")
+ p.error(list[0].Pos(), "no new variables on left side of :=")
}
}
@@ -522,7 +525,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
for i, x := range list {
ident, isIdent := x.(*ast.Ident)
if !isIdent {
- pos := x.(ast.Expr).Pos()
+ pos := x.Pos()
p.errorExpected(pos, "identifier")
ident = &ast.Ident{pos, "_", nil}
}
@@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
} else {
y = p.parseRhsList()
}
+ as := &ast.AssignStmt{x, pos, tok, y}
if tok == token.DEFINE {
- p.shortVarDecl(p.makeIdentList(x))
+ p.shortVarDecl(as, x)
}
- return &ast.AssignStmt{x, pos, tok, y}, isRange
+ return as, isRange
}
if len(x) > 1 {
@@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause {
comm = &ast.SendStmt{lhs[0], arrow, rhs}
} else {
// RecvStmt
- pos := p.pos
- tok := p.tok
- var rhs ast.Expr
- if tok == token.ASSIGN || tok == token.DEFINE {
+ if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
// RecvStmt with assignment
if len(lhs) > 2 {
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
// continue with first two expressions
lhs = lhs[0:2]
}
+ pos := p.pos
p.next()
- rhs = p.parseRhs()
- if tok == token.DEFINE && lhs != nil {
- p.shortVarDecl(p.makeIdentList(lhs))
+ rhs := p.parseRhs()
+ as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+ if tok == token.DEFINE {
+ p.shortVarDecl(as, lhs)
}
+ comm = as
} else {
- // rhs must be single receive operation
+ // lhs must be single receive operation
if len(lhs) > 1 {
p.errorExpected(lhs[0].Pos(), "1 expression")
// continue with first expression
}
- rhs = lhs[0]
- lhs = nil // there is no lhs
- }
- if lhs != nil {
- comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
- } else {
- comm = &ast.ExprStmt{rhs}
+ comm = &ast.ExprStmt{lhs[0]}
}
}
} else {
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index b2a48c2..6817cc4 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -39,7 +39,10 @@ import (
// future (not yet interspersed) comments in this function.
//
func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
- n := p.nlines(line-p.pos.Line, min)
+ n := nlimit(line - p.pos.Line)
+ if n < min {
+ n = min
+ }
if n > 0 {
p.print(ws)
if newSection {
@@ -361,9 +364,10 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
+ hasComments := isIncomplete || p.commentBefore(p.fset.Position(rbrace))
srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
- if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
+ if !hasComments && srcIsOneLine {
// possibly a one-line struct/interface
if len(list) == 0 {
// no blank between keyword and {} in this case
@@ -388,9 +392,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
return
}
}
+ // hasComments || !srcIsOneLine
+
+ p.print(blank, lbrace, token.LBRACE, indent)
+ if hasComments || len(list) > 0 {
+ p.print(formfeed)
+ }
- // at least one entry or incomplete
- p.print(blank, lbrace, token.LBRACE, indent, formfeed)
if isStruct {
sep := vtab
@@ -1509,9 +1517,14 @@ func (p *printer) file(src *ast.File) {
prev := tok
tok = declToken(d)
// if the declaration token changed (e.g., from CONST to TYPE)
+ // or the next declaration has documentation associated with it,
// print an empty line between top-level declarations
+ // (because p.linebreak is called with the position of d, which
+ // is past any documentation, the minimum requirement is satisfied
+ // even w/o the extra getDoc(d) nil-check - leave it in case the
+ // linebreak logic improves - there's already a TODO).
min := 1
- if prev != tok {
+ if prev != tok || getDoc(d) != nil {
min = 2
}
p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index 8538236..a78cfc6 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -18,8 +18,11 @@ import (
"text/tabwriter"
)
-const debug = false // enable for debugging
-const infinity = 1 << 30
+const (
+ maxNewlines = 2 // max. number of newlines between source text
+ debug = false // enable for debugging
+ infinity = 1 << 30
+)
type whiteSpace byte
@@ -89,21 +92,7 @@ func (p *printer) internalError(msg ...interface{}) {
}
}
-// nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max.
-//
-func (p *printer) nlines(n, min int) int {
- const max = 2 // max. number of newlines
- switch {
- case n < min:
- return min
- case n > max:
- return max
- }
- return n
-}
-
-// writeByte writes a single byte to p.output and updates p.pos.
+// writeByte writes ch to p.output and updates p.pos.
func (p *printer) writeByte(ch byte) {
p.output.WriteByte(ch)
p.pos.Offset++
@@ -128,13 +117,11 @@ func (p *printer) writeByte(ch byte) {
}
}
-// writeNewlines writes up to n newlines to p.output and updates p.pos.
-// The actual number of newlines written is limited by nlines.
-// nl must be one of '\n' or '\f'.
-//
-func (p *printer) writeNewlines(n int, nl byte) {
- for n = p.nlines(n, 0); n > 0; n-- {
- p.writeByte(nl)
+// writeByteN writes ch n times to p.output and updates p.pos.
+func (p *printer) writeByteN(ch byte, n int) {
+ for n > 0 {
+ p.writeByte(ch)
+ n--
}
}
@@ -223,8 +210,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
}
if pos.IsValid() && pos.Filename != p.last.Filename {
- // comment in a different file - separate with newlines (writeNewlines will limit the number)
- p.writeNewlines(10, '\f')
+ // comment in a different file - separate with newlines
+ p.writeByteN('\f', maxNewlines)
return
}
@@ -270,6 +257,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
} else {
// comment on a different line:
// separate with at least one line break
+ droppedLinebreak := false
if prev == nil {
// first comment of a comment group
j := 0
@@ -295,6 +283,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
case newline, formfeed:
// TODO(gri): may want to keep formfeed info in some cases
p.wsbuf[i] = ignore
+ droppedLinebreak = true
}
j = i
break
@@ -302,25 +291,41 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
p.writeWhitespace(j)
}
- // turn off indent if we're about to print a line directive.
- indent := p.indent
- if strings.HasPrefix(comment.Text, linePrefix) {
- p.indent = 0
+ // determine number of linebreaks before the comment
+ n := 0
+ if pos.IsValid() && p.last.IsValid() {
+ n = pos.Line - p.last.Line
+ if n < 0 { // should never happen
+ n = 0
+ }
+ }
+
+ // at the package scope level only (p.indent == 0),
+ // add an extra newline if we dropped one before:
+ // this preserves a blank line before documentation
+ // comments at the package scope level (issue 2570)
+ if p.indent == 0 && droppedLinebreak {
+ n++
}
- // use formfeeds to break columns before a comment;
- // this is analogous to using formfeeds to separate
- // individual lines of /*-style comments - but make
- // sure there is at least one line break if the previous
- // comment was a line comment
- n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
- if n <= 0 && prev != nil && prev.Text[1] == '/' {
+ // make sure there is at least one line break
+ // if the previous comment was a line comment
+ if n == 0 && prev != nil && prev.Text[1] == '/' {
n = 1
}
+
if n > 0 {
- p.writeNewlines(n, '\f')
+ // turn off indent if we're about to print a line directive
+ indent := p.indent
+ if strings.HasPrefix(comment.Text, linePrefix) {
+ p.indent = 0
+ }
+ // use formfeeds to break columns before a comment;
+ // this is analogous to using formfeeds to separate
+ // individual lines of /*-style comments
+ p.writeByteN('\f', nlimit(n))
+ p.indent = indent // restore indent
}
- p.indent = indent
}
}
@@ -550,10 +555,11 @@ func (p *printer) writeComment(comment *ast.Comment) {
// writeCommentSuffix writes a line break after a comment if indicated
// and processes any leftover indentation information. If a line break
// is needed, the kind of break (newline vs formfeed) depends on the
-// pending whitespace. writeCommentSuffix returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// pending whitespace. The writeCommentSuffix result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace
+// buffer.
//
-func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, droppedFF bool) {
for i, ch := range p.wsbuf {
switch ch {
case blank, vtab:
@@ -566,6 +572,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// but remember if we dropped any formfeeds
if needsLinebreak {
needsLinebreak = false
+ wroteNewline = true
} else {
if ch == formfeed {
droppedFF = true
@@ -579,6 +586,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// make sure we have a line break
if needsLinebreak {
p.writeByte('\n')
+ wroteNewline = true
}
return
@@ -587,10 +595,10 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// intersperseComments consumes all comments that appear before the next token
// tok and prints it together with the buffered whitespace (i.e., the whitespace
// that needs to be written before the next token). A heuristic is used to mix
-// the comments and whitespace. intersperseComments returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// the comments and whitespace. The intersperseComments result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace buffer.
//
-func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
var last *ast.Comment
for ; p.commentBefore(next); p.cindex++ {
for _, c := range p.comments[p.cindex].List {
@@ -618,7 +626,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
// no comment was written - we should never reach here since
// intersperseComments should not be called in that case
p.internalError("intersperseComments called without pending comments")
- return false
+ return
}
// whiteWhitespace writes the first n whitespace entries.
@@ -671,6 +679,14 @@ func (p *printer) writeWhitespace(n int) {
// ----------------------------------------------------------------------------
// Printing interface
+// nlines limits n to maxNewlines.
+func nlimit(n int) int {
+ if n > maxNewlines {
+ n = maxNewlines
+ }
+ return n
+}
+
func mayCombine(prev token.Token, next byte) (b bool) {
switch prev {
case token.INT:
@@ -765,17 +781,22 @@ func (p *printer) print(args ...interface{}) {
p.pos = next
if data != "" {
- nl := byte('\n')
- if p.flush(next, tok) {
- nl = '\f' // dropped formfeed before
- }
+ wroteNewline, droppedFF := p.flush(next, tok)
// intersperse extra newlines if present in the source
// (don't do this in flush as it will cause extra newlines
- // at the end of a file) - use formfeeds if we dropped one
- // before
- if n := next.Line - p.pos.Line; n > 0 {
- p.writeNewlines(n, nl)
+ // at the end of a file)
+ n := nlimit(next.Line - p.pos.Line)
+ // don't exceed maxNewlines if we already wrote one
+ if wroteNewline && n == maxNewlines {
+ n = maxNewlines - 1
+ }
+ if n > 0 {
+ ch := byte('\n')
+ if droppedFF {
+ ch = '\f' // use formfeed since we dropped one before
+ }
+ p.writeByteN(ch, n)
}
p.writeItem(next, data, isLit)
@@ -790,16 +811,15 @@ func (p *printer) commentBefore(next token.Position) bool {
return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
}
-// Flush prints any pending comments and whitespace occurring
-// textually before the position of the next token tok. Flush
-// returns true if a pending formfeed character was dropped
-// from the whitespace buffer as a result of interspersing
-// comments.
+// Flush prints any pending comments and whitespace occurring textually
+// before the position of the next token tok. The Flush result indicates
+// if a newline was written or if a formfeed was dropped from the whitespace
+// buffer.
//
-func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
if p.commentBefore(next) {
// if there are comments before the next item, intersperse them
- droppedFF = p.intersperseComments(next, tok)
+ wroteNewline, droppedFF = p.intersperseComments(next, tok)
} else {
// otherwise, write any leftover whitespace
p.writeWhitespace(len(p.wsbuf))
@@ -810,7 +830,8 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
// getNode returns the ast.CommentGroup associated with n, if any.
func getDoc(n ast.Node) *ast.CommentGroup {
switch n := n.(type) {
- // *ast.Fields cannot be printed separately - ignore for now
+ case *ast.Field:
+ return n.Doc
case *ast.ImportSpec:
return n.Doc
case *ast.ValueSpec:
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index 7b33225..d2ad9e3 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -106,7 +106,7 @@ type S3 struct {
var x int // x
var ()
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
func f0() {
const pi = 3.14 // pi
var s1 struct{} /* an empty struct */ /* foo */
@@ -115,8 +115,9 @@ func f0() {
var s2 struct{} = struct{}{}
x := pi
}
+
//
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
//
func f1() {
f0()
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index 2a9a86b..222e0a7 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -107,7 +107,7 @@ var x int // x
var ()
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
func f0() {
const pi = 3.14 // pi
var s1 struct {} /* an empty struct */ /* foo */
@@ -117,7 +117,7 @@ func f0() {
x := pi
}
//
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
//
func f1() {
f0()
@@ -130,7 +130,7 @@ func f1() {
func _() {
- // this comment should be properly indented
+// this comment should be properly indented
}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
index bfa2568..239ba89 100644
--- a/libgo/go/go/printer/testdata/declarations.golden
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -115,6 +115,18 @@ import _ "io"
var _ int
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+
+// T2 comment
+type T2 struct {
+} // should be a two-line struct
+
+// T3 comment
+type T2 struct {
+} // should be a two-line struct
+
// printing of constant literals
const (
_ = "foobar"
@@ -286,6 +298,15 @@ type _ struct {
}
}
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{}
+type _ struct {
+}
+
+type _ interface{}
+type _ interface {
+}
+
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
index 1d69c57..68f9030 100644
--- a/libgo/go/go/printer/testdata/declarations.input
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -115,6 +115,20 @@ import (
import _ "io"
var _ int
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+// T2 comment
+type T2 struct {
+} // should be a two-line struct
+
+
+// T3 comment
+type T2 struct {
+
+
+} // should be a two-line struct
+
// printing of constant literals
const (
@@ -293,6 +307,18 @@ type _ struct {
}
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{ }
+type _ struct {
+
+}
+
+type _ interface{ }
+type _ interface {
+
+}
+
+
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
index a6d8510..90e1743 100644
--- a/libgo/go/go/printer/testdata/statements.golden
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -271,7 +271,6 @@ func _() {
// Known bug: The first use call may have more than one empty line before
// (see go/printer/nodes.go, func linebreak).
-
use(x)
if x < x {
@@ -386,7 +385,6 @@ L: // A comment on the same line as the label, followed by a single empty line.
// Known bug: There may be more than one empty line before MoreCode()
// (see go/printer/nodes.go, func linebreak).
-
MoreCode()
}
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index cef9c48..7fb0104 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -426,13 +426,16 @@ func (S *Scanner) scanString() {
S.next()
}
-func (S *Scanner) scanRawString() {
+func (S *Scanner) scanRawString() (hasCR bool) {
// '`' opening already consumed
offs := S.offset - 1
for S.ch != '`' {
ch := S.ch
S.next()
+ if ch == '\r' {
+ hasCR = true
+ }
if ch < 0 {
S.error(offs, "string not terminated")
break
@@ -440,6 +443,7 @@ func (S *Scanner) scanRawString() {
}
S.next()
+ return
}
func (S *Scanner) skipWhitespace() {
@@ -490,6 +494,18 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Tok
return tok0
}
+func stripCR(b []byte) []byte {
+ c := make([]byte, len(b))
+ i := 0
+ for _, ch := range b {
+ if ch != '\r' {
+ c[i] = ch
+ i++
+ }
+ }
+ return c[:i]
+}
+
// Scan scans the next token and returns the token position,
// the token, and the literal string corresponding to the
// token. The source end is indicated by token.EOF.
@@ -518,6 +534,7 @@ scanAgain:
insertSemi := false
offs := S.offset
tok := token.ILLEGAL
+ hasCR := false
// determine token value
switch ch := S.ch; {
@@ -556,7 +573,7 @@ scanAgain:
case '`':
insertSemi = true
tok = token.STRING
- S.scanRawString()
+ hasCR = S.scanRawString()
case ':':
tok = S.switch2(token.COLON, token.DEFINE)
case '.':
@@ -663,5 +680,9 @@ scanAgain:
// TODO(gri): The scanner API should change such that the literal string
// is only valid if an actual literal was scanned. This will
// permit a more efficient implementation.
- return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
+ lit := S.src[offs:S.offset]
+ if hasCR {
+ lit = stripCR(lit)
+ }
+ return S.file.Pos(offs), tok, string(lit)
}
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 7ed927a..dc8ab2a 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -83,6 +83,8 @@ var tokens = [...]elt{
"`",
literal,
},
+ {token.STRING, "`\r`", literal},
+ {token.STRING, "`foo\r\nbar`", literal},
// Operators and delimiters
{token.ADD, "+", operator},
@@ -239,8 +241,16 @@ func TestScan(t *testing.T) {
if tok != e.tok {
t.Errorf("bad token for %q: got %s, expected %s", lit, tok, e.tok)
}
- if e.tok.IsLiteral() && lit != e.lit {
- t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+ if e.tok.IsLiteral() {
+ // no CRs in raw string literals
+ elit := e.lit
+ if elit[0] == '`' {
+ elit = string(stripCR([]byte(elit)))
+ epos.Offset += len(e.lit) - len(lit) // correct position
+ }
+ if lit != elit {
+ t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, elit)
+ }
}
if tokenclass(tok) != e.class {
t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
diff --git a/libgo/go/html/const.go b/libgo/go/html/const.go
index 832e9db..d7cc8bb 100644
--- a/libgo/go/html/const.go
+++ b/libgo/go/html/const.go
@@ -7,7 +7,7 @@ package html
// Section 12.2.3.2 of the HTML5 specification says "The following elements
// have varying levels of special parsing rules".
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
-var isSpecialElement = map[string]bool{
+var isSpecialElementMap = map[string]bool{
"address": true,
"applet": true,
"area": true,
@@ -88,3 +88,13 @@ var isSpecialElement = map[string]bool{
"wbr": true,
"xmp": true,
}
+
+func isSpecialElement(element *Node) bool {
+ switch element.Namespace {
+ case "", "html":
+ return isSpecialElementMap[element.Data]
+ case "svg":
+ return element.Data == "foreignObject"
+ }
+ return false
+}
diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go
index 4cb24696..6962e64 100644
--- a/libgo/go/html/parse.go
+++ b/libgo/go/html/parse.go
@@ -319,10 +319,7 @@ func (p *parser) resetInsertionMode() {
case "html":
p.im = beforeHeadIM
default:
- if p.top().Namespace == "" {
- continue
- }
- p.im = inForeignContentIM
+ continue
}
return
}
@@ -705,7 +702,7 @@ func inBodyIM(p *parser) bool {
case "address", "div", "p":
continue
default:
- if !isSpecialElement[node.Data] {
+ if !isSpecialElement(node) {
continue
}
}
@@ -723,7 +720,7 @@ func inBodyIM(p *parser) bool {
case "address", "div", "p":
continue
default:
- if !isSpecialElement[node.Data] {
+ if !isSpecialElement(node) {
continue
}
}
@@ -814,7 +811,6 @@ func inBodyIM(p *parser) bool {
// TODO: adjust foreign attributes.
p.addElement(p.tok.Data, p.tok.Attr)
p.top().Namespace = namespace
- p.im = inForeignContentIM
return true
case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr":
// Ignore the token.
@@ -895,7 +891,7 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
// Steps 5-6. Find the furthest block.
var furthestBlock *Node
for _, e := range p.oe[feIndex:] {
- if isSpecialElement[e.Data] {
+ if isSpecialElement(e) {
furthestBlock = e
break
}
@@ -988,7 +984,7 @@ func (p *parser) inBodyEndTagOther(tag string) {
p.oe = p.oe[:i]
break
}
- if isSpecialElement[p.oe[i].Data] {
+ if isSpecialElement(p.oe[i]) {
break
}
}
@@ -1206,6 +1202,13 @@ func inTableBodyIM(p *parser) bool {
add = true
data = "tr"
consumed = false
+ case "caption", "col", "colgroup", "tbody", "tfoot", "thead":
+ if !p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
+ // Ignore the token.
+ return true
+ }
+ p.im = inTableIM
+ return false
default:
// TODO.
}
@@ -1569,6 +1572,19 @@ func afterAfterFramesetIM(p *parser) bool {
Type: CommentNode,
Data: p.tok.Data,
})
+ case TextToken:
+ // Ignore all text but whitespace.
+ s := strings.Map(func(c rune) rune {
+ switch c {
+ case ' ', '\t', '\n', '\f', '\r':
+ return c
+ }
+ return -1
+ }, p.tok.Data)
+ if s != "" {
+ p.reconstructActiveFormattingElements()
+ p.addText(s)
+ }
case StartTagToken:
switch p.tok.Data {
case "html":
@@ -1583,8 +1599,19 @@ func afterAfterFramesetIM(p *parser) bool {
}
// Section 12.2.5.5.
-func inForeignContentIM(p *parser) bool {
+func parseForeignContent(p *parser) bool {
switch p.tok.Type {
+ case TextToken:
+ // TODO: HTML integration points.
+ if p.top().Namespace == "" {
+ inBodyIM(p)
+ p.resetInsertionMode()
+ return true
+ }
+ if p.framesetOK {
+ p.framesetOK = strings.TrimLeft(p.tok.Data, whitespace) == ""
+ }
+ p.addText(p.tok.Data)
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
@@ -1592,7 +1619,14 @@ func inForeignContentIM(p *parser) bool {
})
case StartTagToken:
if breakout[p.tok.Data] {
- // TODO.
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ // TODO: HTML, MathML integration points.
+ if p.oe[i].Namespace == "" {
+ p.oe = p.oe[:i+1]
+ break
+ }
+ }
+ return false
}
switch p.top().Namespace {
case "mathml":
@@ -1606,13 +1640,36 @@ func inForeignContentIM(p *parser) bool {
// TODO: adjust foreign attributes.
p.addElement(p.tok.Data, p.tok.Attr)
case EndTagToken:
- // TODO.
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ if p.oe[i].Namespace == "" {
+ return p.im(p)
+ }
+ if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
+ p.oe = p.oe[:i]
+ break
+ }
+ }
+ return true
default:
// Ignore the token.
}
return true
}
+// Section 12.2.5.
+func (p *parser) inForeignContent() bool {
+ if len(p.oe) == 0 {
+ return false
+ }
+ n := p.oe[len(p.oe)-1]
+ if n.Namespace == "" {
+ return false
+ }
+ // TODO: MathML, HTML integration points.
+ // TODO: MathML's annotation-xml combining with SVG's svg.
+ return true
+}
+
func (p *parser) parse() error {
// Iterate until EOF. Any other error will cause an early return.
consumed := true
@@ -1625,7 +1682,11 @@ func (p *parser) parse() error {
return err
}
}
- consumed = p.im(p)
+ if p.inForeignContent() {
+ consumed = parseForeignContent(p)
+ } else {
+ consumed = p.im(p)
+ }
}
// Loop until the final token (the ErrorToken signifying EOF) is consumed.
for {
diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go
index e887631..015b583 100644
--- a/libgo/go/html/parse_test.go
+++ b/libgo/go/html/parse_test.go
@@ -172,7 +172,8 @@ func TestParser(t *testing.T) {
{"tests3.dat", -1},
{"tests4.dat", -1},
{"tests5.dat", -1},
- {"tests6.dat", 36},
+ {"tests6.dat", 47},
+ {"tests10.dat", 16},
}
for _, tf := range testFiles {
f, err := os.Open("testdata/webkit/" + tf.filename)
diff --git a/libgo/go/html/template/error.go b/libgo/go/html/template/error.go
index 9622d7e..dcac748 100644
--- a/libgo/go/html/template/error.go
+++ b/libgo/go/html/template/error.go
@@ -183,11 +183,11 @@ const (
func (e *Error) Error() string {
if e.Line != 0 {
- return fmt.Sprintf("exp/template/html:%s:%d: %s", e.Name, e.Line, e.Description)
+ return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
} else if e.Name != "" {
- return fmt.Sprintf("exp/template/html:%s: %s", e.Name, e.Description)
+ return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
}
- return "exp/template/html: " + e.Description
+ return "html/template: " + e.Description
}
// errorf creates an error given a format string f and args.
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index 2f6be3b..c6f723a 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -486,9 +486,17 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
}
t := e.template(name)
if t == nil {
+ // Two cases: The template exists but is empty, or has never been mentioned at
+ // all. Distinguish the cases in the error messages.
+ if e.tmpl.set[name] != nil {
+ return context{
+ state: stateError,
+ err: errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name),
+ }, dname
+ }
return context{
state: stateError,
- err: errorf(ErrNoSuchTemplate, line, "no such template %s", name),
+ err: errorf(ErrNoSuchTemplate, line, "no such template %q", name),
}, dname
}
if dname != name {
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index 2d15c71..a57f982 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -928,7 +928,7 @@ func TestErrors(t *testing.T) {
},
{
`{{template "foo"}}`,
- "z:1: no such template foo",
+ "z:1: no such template \"foo\"",
},
{
`<div{{template "y"}}>` +
@@ -944,23 +944,23 @@ func TestErrors(t *testing.T) {
},
{
`<input type=button value=onclick=>`,
- `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+ `html/template:z: "=" in unquoted attr: "onclick="`,
},
{
`<input type=button value= onclick=>`,
- `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+ `html/template:z: "=" in unquoted attr: "onclick="`,
},
{
`<input type=button value= 1+1=2>`,
- `exp/template/html:z: "=" in unquoted attr: "1+1=2"`,
+ `html/template:z: "=" in unquoted attr: "1+1=2"`,
},
{
"<a class=`foo>",
- "exp/template/html:z: \"`\" in unquoted attr: \"`foo\"",
+ "html/template:z: \"`\" in unquoted attr: \"`foo\"",
},
{
`<a style=font:'Arial'>`,
- `exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`,
+ `html/template:z: "'" in unquoted attr: "font:'Arial'"`,
},
{
`<a=foo>`,
diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go
new file mode 100644
index 0000000..c79816d
--- /dev/null
+++ b/libgo/go/image/color/ycbcr.go
@@ -0,0 +1,99 @@
+// 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 color
+
+// RGBToYCbCr converts an RGB triple to a Y'CbCr triple. All components lie
+// within the range [0, 255].
+func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // Y' = 0.2990*R + 0.5870*G + 0.1140*B
+ // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
+ // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ r1 := int(r)
+ g1 := int(g)
+ b1 := int(b)
+ yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
+ cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
+ if yy < 0 {
+ yy = 0
+ } else if yy > 255 {
+ yy = 255
+ }
+ if cb < 0 {
+ cb = 0
+ } else if cb > 255 {
+ cb = 255
+ }
+ if cr < 0 {
+ cr = 0
+ } else if cr > 255 {
+ cr = 255
+ }
+ return uint8(yy), uint8(cb), uint8(cr)
+}
+
+// YCbCrToRGB converts a Y'CbCr triple to an RGB triple. All components lie
+// within the range [0, 255].
+func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // R = Y' + 1.40200*(Cr-128)
+ // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
+ // B = Y' + 1.77200*(Cb-128)
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ yy1 := int(y)<<16 + 1<<15
+ cb1 := int(cb) - 128
+ cr1 := int(cr) - 128
+ r := (yy1 + 91881*cr1) >> 16
+ g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+ b := (yy1 + 116130*cb1) >> 16
+ if r < 0 {
+ r = 0
+ } else if r > 255 {
+ r = 255
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+ return uint8(r), uint8(g), uint8(b)
+}
+
+// YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for
+// one luma and two chroma components.
+//
+// JPEG, VP8, the MPEG family and other codecs use this color model. Such
+// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
+// speaking, the term YUV applies only to analog video signals, and Y' (luma)
+// is Y (luminance) after applying gamma correction.
+//
+// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
+// different formulae for converting between the two. This package follows
+// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+type YCbCr struct {
+ Y, Cb, Cr uint8
+}
+
+func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
+ r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+ return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+}
+
+// YCbCrModel is the Model for Y'CbCr colors.
+var YCbCrModel Model = ModelFunc(func(c Color) Color {
+ if _, ok := c.(YCbCr); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ return YCbCr{y, u, v}
+})
diff --git a/libgo/go/image/ycbcr/ycbcr_test.go b/libgo/go/image/color/ycbcr_test.go
index 2e60a6f..92a0e6f 100644
--- a/libgo/go/image/ycbcr/ycbcr_test.go
+++ b/libgo/go/image/color/ycbcr_test.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 ycbcr
+package color
import (
"testing"
diff --git a/libgo/go/image/draw/bench_test.go b/libgo/go/image/draw/bench_test.go
index 2be9118..4cd2095 100644
--- a/libgo/go/image/draw/bench_test.go
+++ b/libgo/go/image/draw/bench_test.go
@@ -7,7 +7,6 @@ package draw
import (
"image"
"image/color"
- "image/ycbcr"
"testing"
)
@@ -51,7 +50,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
}
dst = dst1
default:
- panic("unreachable")
+ b.Fatal("unknown destination color model", dcm)
}
var src image.Image
@@ -97,7 +96,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
}
}
src = src1
- case ycbcr.YCbCrColorModel:
+ case color.YCbCrModel:
yy := make([]uint8, srcw*srch)
cb := make([]uint8, srcw*srch)
cr := make([]uint8, srcw*srch)
@@ -106,17 +105,17 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
cb[i] = uint8(5 * i % 0x100)
cr[i] = uint8(7 * i % 0x100)
}
- src = &ycbcr.YCbCr{
+ src = &image.YCbCr{
Y: yy,
Cb: cb,
Cr: cr,
YStride: srcw,
CStride: srcw,
- SubsampleRatio: ycbcr.SubsampleRatio444,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
Rect: image.Rect(0, 0, srcw, srch),
}
default:
- panic("unreachable")
+ b.Fatal("unknown source color model", scm)
}
var mask image.Image
@@ -137,7 +136,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
}
mask = mask1
default:
- panic("unreachable")
+ b.Fatal("unknown mask color model", mcm)
}
b.StartTimer()
@@ -177,7 +176,7 @@ func BenchmarkNRGBASrc(b *testing.B) {
}
func BenchmarkYCbCr(b *testing.B) {
- bench(b, color.RGBAModel, ycbcr.YCbCrColorModel, nil, Over)
+ bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
}
func BenchmarkGlyphOver(b *testing.B) {
diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go
index af02639..228ed6e 100644
--- a/libgo/go/image/draw/draw.go
+++ b/libgo/go/image/draw/draw.go
@@ -11,7 +11,6 @@ package draw
import (
"image"
"image/color"
- "image/ycbcr"
)
// m is the maximum color value returned by image.Color.RGBA.
@@ -81,7 +80,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
case *image.NRGBA:
drawNRGBAOver(dst0, r, src0, sp)
return
- case *ycbcr.YCbCr:
+ case *image.YCbCr:
drawYCbCr(dst0, r, src0, sp)
return
}
@@ -104,7 +103,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
case *image.NRGBA:
drawNRGBASrc(dst0, r, src0, sp)
return
- case *ycbcr.YCbCr:
+ case *image.YCbCr:
drawYCbCr(dst0, r, src0, sp)
return
}
@@ -346,8 +345,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
}
}
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
- // A YCbCr image is always fully opaque, and so if the mask is implicitly nil
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
+ // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
// (i.e. fully opaque) then the op is effectively always Src.
var (
yy, cb, cr uint8
@@ -357,7 +356,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
y0 := r.Min.Y - dst.Rect.Min.Y
y1 := r.Max.Y - dst.Rect.Min.Y
switch src.SubsampleRatio {
- case ycbcr.SubsampleRatio422:
+ case image.YCbCrSubsampleRatio422:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
@@ -365,14 +364,14 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+i]
cr = src.Cr[sy*src.CStride+i]
- rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
dpix[x+3] = 255
}
}
- case ycbcr.SubsampleRatio420:
+ case image.YCbCrSubsampleRatio420:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
@@ -380,7 +379,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[j*src.CStride+i]
cr = src.Cr[j*src.CStride+i]
- rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
@@ -395,7 +394,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+sx]
cr = src.Cr[sy*src.CStride+sx]
- rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
diff --git a/libgo/go/image/draw/draw_test.go b/libgo/go/image/draw/draw_test.go
index 663ab67..56a4502 100644
--- a/libgo/go/image/draw/draw_test.go
+++ b/libgo/go/image/draw/draw_test.go
@@ -7,7 +7,6 @@ package draw
import (
"image"
"image/color"
- "image/ycbcr"
"testing"
)
@@ -56,13 +55,13 @@ func vgradGreenNRGBA(alpha int) image.Image {
}
func vgradCr() image.Image {
- m := &ycbcr.YCbCr{
+ m := &image.YCbCr{
Y: make([]byte, 16*16),
Cb: make([]byte, 16*16),
Cr: make([]byte, 16*16),
YStride: 16,
CStride: 16,
- SubsampleRatio: ycbcr.SubsampleRatio444,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
Rect: image.Rect(0, 0, 16, 16),
}
for y := 0; y < 16; y++ {
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index c1fc2d5..ed1a962 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -11,7 +11,6 @@ import (
"bufio"
"image"
"image/color"
- "image/ycbcr"
"io"
)
@@ -97,7 +96,7 @@ type decoder struct {
r Reader
width, height int
img1 *image.Gray
- img3 *ycbcr.YCbCr
+ img3 *image.YCbCr
ri int // Restart Interval.
nComp int
comp [nColorComponent]component
@@ -203,20 +202,20 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) {
d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
return
}
- var subsampleRatio ycbcr.SubsampleRatio
+ var subsampleRatio image.YCbCrSubsampleRatio
n := h0 * v0
switch n {
case 1:
- subsampleRatio = ycbcr.SubsampleRatio444
+ subsampleRatio = image.YCbCrSubsampleRatio444
case 2:
- subsampleRatio = ycbcr.SubsampleRatio422
+ subsampleRatio = image.YCbCrSubsampleRatio422
case 4:
- subsampleRatio = ycbcr.SubsampleRatio420
+ subsampleRatio = image.YCbCrSubsampleRatio420
default:
panic("unreachable")
}
b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
- d.img3 = &ycbcr.YCbCr{
+ d.img3 = &image.YCbCr{
Y: b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
Cb: b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
Cr: b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
@@ -466,7 +465,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
case nGrayComponent:
return image.Config{color.GrayModel, d.width, d.height}, nil
case nColorComponent:
- return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
+ return image.Config{color.YCbCrModel, d.width, d.height}, nil
}
return image.Config{}, FormatError("missing SOF marker")
}
diff --git a/libgo/go/image/jpeg/writer.go b/libgo/go/image/jpeg/writer.go
index fab0bd0..71fe37c 100644
--- a/libgo/go/image/jpeg/writer.go
+++ b/libgo/go/image/jpeg/writer.go
@@ -8,7 +8,7 @@ import (
"bufio"
"errors"
"image"
- "image/ycbcr"
+ "image/color"
"io"
)
@@ -379,7 +379,7 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
- yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
yBlock[8*j+i] = int(yy)
cbBlock[8*j+i] = int(cb)
crBlock[8*j+i] = int(cr)
@@ -404,7 +404,7 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
sx = xmax
}
pix := m.Pix[offset+sx*4:]
- yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
+ yy, cb, cr := color.RGBToYCbCr(pix[0], pix[1], pix[2])
yBlock[8*j+i] = int(yy)
cbBlock[8*j+i] = int(cb)
crBlock[8*j+i] = int(cr)
diff --git a/libgo/go/image/jpeg/writer_test.go b/libgo/go/image/jpeg/writer_test.go
index 28e8732..e4b56d2 100644
--- a/libgo/go/image/jpeg/writer_test.go
+++ b/libgo/go/image/jpeg/writer_test.go
@@ -105,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
}
}
if !img.Opaque() {
- panic("expected image to be opaque")
+ b.Fatal("expected image to be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
index 1757e14..228eccc 100644
--- a/libgo/go/image/png/writer_test.go
+++ b/libgo/go/image/png/writer_test.go
@@ -125,7 +125,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
}
}
if !img.Opaque() {
- panic("expected image to be opaque")
+ b.Fatal("expected image to be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
@@ -138,7 +138,7 @@ func BenchmarkEncodeRGBA(b *testing.B) {
b.StopTimer()
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
if img.Opaque() {
- panic("expected image to not be opaque")
+ b.Fatal("expected image to not be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
diff --git a/libgo/go/image/tiff/reader_test.go b/libgo/go/image/tiff/reader_test.go
index 1a3d23b..ee5dafd 100644
--- a/libgo/go/image/tiff/reader_test.go
+++ b/libgo/go/image/tiff/reader_test.go
@@ -113,7 +113,7 @@ func BenchmarkDecode(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := Decode(r)
if err != nil {
- panic(err)
+ b.Fatal("Decode:", err)
}
}
}
diff --git a/libgo/go/image/ycbcr.go b/libgo/go/image/ycbcr.go
new file mode 100644
index 0000000..81f3c9f
--- /dev/null
+++ b/libgo/go/image/ycbcr.go
@@ -0,0 +1,87 @@
+// 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 image
+
+import (
+ "image/color"
+)
+
+// YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
+type YCbCrSubsampleRatio int
+
+const (
+ YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
+ YCbCrSubsampleRatio422
+ YCbCrSubsampleRatio420
+)
+
+// YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
+// pixel, but each Cb and Cr sample can span one or more pixels.
+// YStride is the Y slice index delta between vertically adjacent pixels.
+// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
+// that map to separate chroma samples.
+// It is not an absolute requirement, but YStride and len(Y) are typically
+// multiples of 8, and:
+// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
+// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
+// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
+type YCbCr struct {
+ Y []uint8
+ Cb []uint8
+ Cr []uint8
+ YStride int
+ CStride int
+ SubsampleRatio YCbCrSubsampleRatio
+ Rect Rectangle
+}
+
+func (p *YCbCr) ColorModel() color.Model {
+ return color.YCbCrModel
+}
+
+func (p *YCbCr) Bounds() Rectangle {
+ return p.Rect
+}
+
+func (p *YCbCr) At(x, y int) color.Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return color.YCbCr{}
+ }
+ switch p.SubsampleRatio {
+ case YCbCrSubsampleRatio422:
+ i := x / 2
+ return color.YCbCr{
+ p.Y[y*p.YStride+x],
+ p.Cb[y*p.CStride+i],
+ p.Cr[y*p.CStride+i],
+ }
+ case YCbCrSubsampleRatio420:
+ i, j := x/2, y/2
+ return color.YCbCr{
+ p.Y[y*p.YStride+x],
+ p.Cb[j*p.CStride+i],
+ p.Cr[j*p.CStride+i],
+ }
+ }
+ // Default to 4:4:4 subsampling.
+ return color.YCbCr{
+ p.Y[y*p.YStride+x],
+ p.Cb[y*p.CStride+x],
+ p.Cr[y*p.CStride+x],
+ }
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *YCbCr) SubImage(r Rectangle) Image {
+ q := new(YCbCr)
+ *q = *p
+ q.Rect = q.Rect.Intersect(r)
+ return q
+}
+
+func (p *YCbCr) Opaque() bool {
+ return true
+}
diff --git a/libgo/go/image/ycbcr/ycbcr.go b/libgo/go/image/ycbcr/ycbcr.go
deleted file mode 100644
index 84a35a3..0000000
--- a/libgo/go/image/ycbcr/ycbcr.go
+++ /dev/null
@@ -1,184 +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 ycbcr provides images from the Y'CbCr color model.
-//
-// JPEG, VP8, the MPEG family and other codecs use this color model. Such
-// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
-// speaking, the term YUV applies only to analog video signals.
-//
-// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
-// different formulae for converting between the two. This package follows
-// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
-package ycbcr
-
-import (
- "image"
- "image/color"
-)
-
-// RGBToYCbCr converts an RGB triple to a YCbCr triple. All components lie
-// within the range [0, 255].
-func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
- // The JFIF specification says:
- // Y' = 0.2990*R + 0.5870*G + 0.1140*B
- // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
- // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
- // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- r1 := int(r)
- g1 := int(g)
- b1 := int(b)
- yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
- cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
- cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
- if yy < 0 {
- yy = 0
- } else if yy > 255 {
- yy = 255
- }
- if cb < 0 {
- cb = 0
- } else if cb > 255 {
- cb = 255
- }
- if cr < 0 {
- cr = 0
- } else if cr > 255 {
- cr = 255
- }
- return uint8(yy), uint8(cb), uint8(cr)
-}
-
-// YCbCrToRGB converts a YCbCr triple to an RGB triple. All components lie
-// within the range [0, 255].
-func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
- // The JFIF specification says:
- // R = Y' + 1.40200*(Cr-128)
- // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
- // B = Y' + 1.77200*(Cb-128)
- // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- yy1 := int(y)<<16 + 1<<15
- cb1 := int(cb) - 128
- cr1 := int(cr) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
- }
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
- }
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
- }
- return uint8(r), uint8(g), uint8(b)
-}
-
-// YCbCrColor represents a fully opaque 24-bit Y'CbCr color, having 8 bits for
-// each of one luma and two chroma components.
-type YCbCrColor struct {
- Y, Cb, Cr uint8
-}
-
-func (c YCbCrColor) RGBA() (uint32, uint32, uint32, uint32) {
- r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
- return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
-}
-
-func toYCbCrColor(c color.Color) color.Color {
- if _, ok := c.(YCbCrColor); ok {
- return c
- }
- r, g, b, _ := c.RGBA()
- y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
- return YCbCrColor{y, u, v}
-}
-
-// YCbCrColorModel is the color model for YCbCrColor.
-var YCbCrColorModel color.Model = color.ModelFunc(toYCbCrColor)
-
-// SubsampleRatio is the chroma subsample ratio used in a YCbCr image.
-type SubsampleRatio int
-
-const (
- SubsampleRatio444 SubsampleRatio = iota
- SubsampleRatio422
- SubsampleRatio420
-)
-
-// YCbCr is an in-memory image of YCbCr colors. There is one Y sample per pixel,
-// but each Cb and Cr sample can span one or more pixels.
-// YStride is the Y slice index delta between vertically adjacent pixels.
-// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
-// that map to separate chroma samples.
-// It is not an absolute requirement, but YStride and len(Y) are typically
-// multiples of 8, and:
-// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
-// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
-// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
-type YCbCr struct {
- Y []uint8
- Cb []uint8
- Cr []uint8
- YStride int
- CStride int
- SubsampleRatio SubsampleRatio
- Rect image.Rectangle
-}
-
-func (p *YCbCr) ColorModel() color.Model {
- return YCbCrColorModel
-}
-
-func (p *YCbCr) Bounds() image.Rectangle {
- return p.Rect
-}
-
-func (p *YCbCr) At(x, y int) color.Color {
- if !(image.Point{x, y}.In(p.Rect)) {
- return YCbCrColor{}
- }
- switch p.SubsampleRatio {
- case SubsampleRatio422:
- i := x / 2
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[y*p.CStride+i],
- p.Cr[y*p.CStride+i],
- }
- case SubsampleRatio420:
- i, j := x/2, y/2
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[j*p.CStride+i],
- p.Cr[j*p.CStride+i],
- }
- }
- // Default to 4:4:4 subsampling.
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[y*p.CStride+x],
- p.Cr[y*p.CStride+x],
- }
-}
-
-// SubImage returns an image representing the portion of the image p visible
-// through r. The returned value shares pixels with the original image.
-func (p *YCbCr) SubImage(r image.Rectangle) image.Image {
- q := new(YCbCr)
- *q = *p
- q.Rect = q.Rect.Intersect(r)
- return q
-}
-
-func (p *YCbCr) Opaque() bool {
- return true
-}
diff --git a/libgo/go/io/ioutil/ioutil_test.go b/libgo/go/io/ioutil/ioutil_test.go
index 89d6815..1030668 100644
--- a/libgo/go/io/ioutil/ioutil_test.go
+++ b/libgo/go/io/ioutil/ioutil_test.go
@@ -37,7 +37,11 @@ func TestReadFile(t *testing.T) {
}
func TestWriteFile(t *testing.T) {
- filename := "_test/rumpelstilzchen"
+ f, err := TempFile("", "ioutil-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ filename := f.Name()
data := "Programming today is a race between software engineers striving to " +
"build bigger and better idiot-proof programs, and the Universe trying " +
"to produce bigger and better idiots. So far, the Universe is winning."
@@ -56,6 +60,7 @@ func TestWriteFile(t *testing.T) {
}
// cleanup
+ f.Close()
os.Remove(filename) // ignore error
}
@@ -66,26 +71,28 @@ func TestReadDir(t *testing.T) {
t.Fatalf("ReadDir %s: error expected, none found", dirname)
}
- dirname = "."
+ dirname = ".."
list, err := ReadDir(dirname)
if err != nil {
t.Fatalf("ReadDir %s: %v", dirname, err)
}
- foundTest := false
- foundTestDir := false
+/* Does not work in gccgo testing environment.
+ foundFile := false
+ foundSubDir := false
for _, dir := range list {
switch {
- case !dir.IsDir() && dir.Name() == "ioutil_test.go":
- foundTest = true
- case dir.IsDir() && dir.Name() == "_test":
- foundTestDir = true
+ case !dir.IsDir() && dir.Name() == "io_test.go":
+ foundFile = true
+ case dir.IsDir() && dir.Name() == "ioutil":
+ foundSubDir = true
}
}
- if !foundTest {
- t.Fatalf("ReadDir %s: test file not found", dirname)
+ if !foundFile {
+ t.Fatalf("ReadDir %s: io_test.go file not found", dirname)
}
- if !foundTestDir {
- t.Fatalf("ReadDir %s: _test directory not found", dirname)
+ if !foundSubDir {
+ t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
}
+*/
}
diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go
index 546bc29..914391a 100644
--- a/libgo/go/log/syslog/syslog.go
+++ b/libgo/go/log/syslog/syslog.go
@@ -92,11 +92,13 @@ func (w *Writer) Emerg(m string) (err error) {
_, err = w.writeString(LOG_EMERG, m)
return err
}
+
// Crit logs a message using the LOG_CRIT priority.
func (w *Writer) Crit(m string) (err error) {
_, err = w.writeString(LOG_CRIT, m)
return err
}
+
// ERR logs a message using the LOG_ERR priority.
func (w *Writer) Err(m string) (err error) {
_, err = w.writeString(LOG_ERR, m)
@@ -114,11 +116,13 @@ func (w *Writer) Notice(m string) (err error) {
_, err = w.writeString(LOG_NOTICE, m)
return err
}
+
// Info logs a message using the LOG_INFO priority.
func (w *Writer) Info(m string) (err error) {
_, err = w.writeString(LOG_INFO, m)
return err
}
+
// Debug logs a message using the LOG_DEBUG priority.
func (w *Writer) Debug(m string) (err error) {
_, err = w.writeString(LOG_DEBUG, m)
diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go
index 0a3cb03..101c8dd 100644
--- a/libgo/go/math/all_test.go
+++ b/libgo/go/math/all_test.go
@@ -22,6 +22,7 @@ var vf = []float64{
1.8253080916808550e+00,
-8.6859247685756013e+00,
}
+
// The expected results below were computed by the high precision calculators
// at http://keisan.casio.com/. More exact input values (array vf[], above)
// were obtained by printing them with "%.26f". The answers were calculated
@@ -159,6 +160,7 @@ var cos = []float64{
-2.517729313893103197176091e-01,
-7.39241351595676573201918e-01,
}
+
// Results for 100000 * Pi + vf[i]
var cosLarge = []float64{
2.634752141185559426744e-01,
@@ -514,6 +516,7 @@ var sin = []float64{
9.6778633541687993721617774e-01,
-6.734405869050344734943028e-01,
}
+
// Results for 100000 * Pi + vf[i]
var sinLarge = []float64{
-9.646661658548936063912e-01,
@@ -563,6 +566,7 @@ var tan = []float64{
-3.843885560201130679995041e+00,
9.10988793377685105753416e-01,
}
+
// Results for 100000 * Pi + vf[i]
var tanLarge = []float64{
-3.66131656475596512705e+00,
diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go
index aa7c194..9c4b730 100644
--- a/libgo/go/math/big/int_test.go
+++ b/libgo/go/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/gob"
"encoding/hex"
"fmt"
+ "math/rand"
"testing"
"testing/quick"
)
@@ -1405,3 +1406,9 @@ func TestIntGobEncoding(t *testing.T) {
}
}
}
+
+func TestIssue2607(t *testing.T) {
+ // This code sequence used to hang.
+ n := NewInt(10)
+ n.Rand(rand.New(rand.NewSource(9)), n)
+}
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index ead1a88..69681ae 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -1196,12 +1196,16 @@ func (x nat) powersOfTwoDecompose() (q nat, k int) {
// random creates a random integer in [0..limit), using the space in z if
// possible. n is the bit length of limit.
func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+ if alias(z, limit) {
+ z = nil // z is an alias for limit - cannot reuse
+ }
+ z = z.make(len(limit))
+
bitLengthOfMSW := uint(n % _W)
if bitLengthOfMSW == 0 {
bitLengthOfMSW = _W
}
mask := Word((1 << bitLengthOfMSW) - 1)
- z = z.make(len(limit))
for {
for i := range z {
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index e3c6552..25e3927 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -5,7 +5,6 @@
package big
import (
- "fmt"
"io"
"strings"
"testing"
@@ -402,7 +401,7 @@ func ScanHelper(b *testing.B, base int, x, y Word) {
var s string
s = z.string(lowercaseDigits[0:base])
if t := toString(z, lowercaseDigits[0:base]); t != s {
- panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+ b.Fatalf("scanning: got %s; want %s", s, t)
}
b.StartTimer()
diff --git a/libgo/go/math/sin.go b/libgo/go/math/sin.go
index 2fbe3e7..ebde7d4 100644
--- a/libgo/go/math/sin.go
+++ b/libgo/go/math/sin.go
@@ -98,6 +98,7 @@ var _sin = [...]float64{
8.33333333332211858878E-3, // 0x3f8111111110f7d0
-1.66666666666666307295E-1, // 0xbfc5555555555548
}
+
// cos coefficients
var _cos = [...]float64{
-1.13585365213876817300E-11, // 0xbda8fa49a0861a9b
diff --git a/libgo/go/mime/type_unix.go b/libgo/go/mime/type_unix.go
index 45127ba..2dab1ea 100644
--- a/libgo/go/mime/type_unix.go
+++ b/libgo/go/mime/type_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 darwin freebsd linux netbsd openbsd plan9
+
package mime
import (
diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go
index fbe6150..66aff83 100644
--- a/libgo/go/net/cgo_stub.go
+++ b/libgo/go/net/cgo_stub.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.
-// +build openbsd
+// +build nocgo
// Stub cgo routines for systems that do not use cgo to do network lookups.
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 43866dc..00acb84 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -4,6 +4,10 @@
package net
+import (
+ "time"
+)
+
func resolveNetAddr(op, net, addr string) (a Addr, err error) {
if addr == "" {
return nil, &OpError{op, net, nil, errMissingAddress}
@@ -42,11 +46,15 @@ func resolveNetAddr(op, net, addr string) (a Addr, err error) {
// Dial("tcp", "google.com:80")
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
//
-func Dial(net, addr string) (c Conn, err error) {
+func Dial(net, addr string) (Conn, error) {
addri, err := resolveNetAddr("dial", net, addr)
if err != nil {
return nil, err
}
+ return dialAddr(net, addr, addri)
+}
+
+func dialAddr(net, addr string, addri Addr) (c Conn, err error) {
switch ra := addri.(type) {
case *TCPAddr:
c, err = DialTCP(net, nil, ra)
@@ -65,6 +73,62 @@ func Dial(net, addr string) (c Conn, err error) {
return
}
+// DialTimeout acts like Dial but takes a timeout.
+// The timeout includes name resolution, if required.
+func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
+ // TODO(bradfitz): the timeout should be pushed down into the
+ // net package's event loop, so on timeout to dead hosts we
+ // don't have a goroutine sticking around for the default of
+ // ~3 minutes.
+ t := time.NewTimer(timeout)
+ defer t.Stop()
+ type pair struct {
+ Conn
+ error
+ }
+ ch := make(chan pair, 1)
+ resolvedAddr := make(chan Addr, 1)
+ go func() {
+ addri, err := resolveNetAddr("dial", net, addr)
+ if err != nil {
+ ch <- pair{nil, err}
+ return
+ }
+ resolvedAddr <- addri // in case we need it for OpError
+ c, err := dialAddr(net, addr, addri)
+ ch <- pair{c, err}
+ }()
+ select {
+ case <-t.C:
+ // Try to use the real Addr in our OpError, if we resolved it
+ // before the timeout. Otherwise we just use stringAddr.
+ var addri Addr
+ select {
+ case a := <-resolvedAddr:
+ addri = a
+ default:
+ addri = &stringAddr{net, addr}
+ }
+ err := &OpError{
+ Op: "dial",
+ Net: net,
+ Addr: addri,
+ Err: &timeoutError{},
+ }
+ return nil, err
+ case p := <-ch:
+ return p.Conn, p.error
+ }
+ panic("unreachable")
+}
+
+type stringAddr struct {
+ net, addr string
+}
+
+func (a stringAddr) Network() string { return a.net }
+func (a stringAddr) String() string { return a.addr }
+
// Listen announces on the local network address laddr.
// The network string net must be a stream-oriented
// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
new file mode 100644
index 0000000..16b7263
--- /dev/null
+++ b/libgo/go/net/dial_test.go
@@ -0,0 +1,88 @@
+// 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 net
+
+import (
+ "runtime"
+ "testing"
+ "time"
+)
+
+func newLocalListener(t *testing.T) Listener {
+ ln, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ errc := make(chan error)
+
+ const SOMAXCONN = 0x80 // copied from syscall, but not always available
+ const numConns = SOMAXCONN + 10
+
+ // TODO(bradfitz): It's hard to test this in a portable
+ // way. This is unforunate, but works for now.
+ switch runtime.GOOS {
+ case "linux":
+ // The kernel will start accepting TCP connections before userspace
+ // gets a chance to not accept them, so fire off a bunch to fill up
+ // the kernel's backlog. Then we test we get a failure after that.
+ for i := 0; i < numConns; i++ {
+ go func() {
+ _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
+ errc <- err
+ }()
+ }
+ case "darwin":
+ // At least OS X 10.7 seems to accept any number of
+ // connections, ignoring listen's backlog, so resort
+ // to connecting to a hopefully-dead 127/8 address.
+ go func() {
+ _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
+ errc <- err
+ }()
+ default:
+ // TODO(bradfitz): this probably doesn't work on
+ // Windows? SOMAXCONN is huge there. I'm not sure how
+ // listen works there.
+ // OpenBSD may have a reject route to 10/8.
+ // FreeBSD likely works, but is untested.
+ t.Logf("skipping test on %q; untested.", runtime.GOOS)
+ return
+ }
+
+ connected := 0
+ for {
+ select {
+ case <-time.After(15 * time.Second):
+ t.Fatal("too slow")
+ case err := <-errc:
+ if err == nil {
+ connected++
+ if connected == numConns {
+ t.Fatal("all connections connected; expected some to time out")
+ }
+ } else {
+ terr, ok := err.(timeout)
+ if !ok {
+ t.Fatalf("got error %q; want error with timeout interface", err)
+ }
+ if !terr.Timeout() {
+ t.Fatalf("got error %q; not a timeout", err)
+ }
+ // Pass. We saw a timeout error.
+ return
+ }
+ }
+ }
+}
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
index 79a958e..07e72cc 100644
--- a/libgo/go/net/dnsclient_unix.go
+++ b/libgo/go/net/dnsclient_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
diff --git a/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go
index 379fec9..c0ab802 100644
--- a/libgo/go/net/dnsconfig.go
+++ b/libgo/go/net/dnsconfig.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Read system DNS config from /etc/resolv.conf
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index 5318c51..3dec9f4 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package net
@@ -377,14 +377,6 @@ func (fd *netFD) CloseWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
-type timeoutError struct{}
-
-func (e *timeoutError) Error() string { return "i/o timeout" }
-func (e *timeoutError) Timeout() bool { return true }
-func (e *timeoutError) Temporary() bool { return true }
-
-var errTimeout error = &timeoutError{}
-
func (fd *netFD) Read(p []byte) (n int, err error) {
if fd == nil {
return 0, os.EINVAL
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
index 8e07833..c8df9c9 100644
--- a/libgo/go/net/fd_linux.go
+++ b/libgo/go/net/fd_linux.go
@@ -37,11 +37,17 @@ func newpollster() (p *pollster, err error) {
p = new(pollster)
var e error
- // The arg to epoll_create is a hint to the kernel
- // about the number of FDs we will care about.
- // We don't know, and since 2.6.8 the kernel ignores it anyhow.
- if p.epfd, e = syscall.EpollCreate(16); e != nil {
- return nil, os.NewSyscallError("epoll_create", e)
+ if p.epfd, e = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); e != nil {
+ if e != syscall.ENOSYS {
+ return nil, os.NewSyscallError("epoll_create1", e)
+ }
+ // The arg to epoll_create is a hint to the kernel
+ // about the number of FDs we will care about.
+ // We don't know, and since 2.6.8 the kernel ignores it anyhow.
+ if p.epfd, e = syscall.EpollCreate(16); e != nil {
+ return nil, os.NewSyscallError("epoll_create", e)
+ }
+ syscall.CloseOnExec(p.epfd)
}
p.events = make(map[int]uint32)
return p, nil
diff --git a/libgo/go/net/fd_netbsd.go b/libgo/go/net/fd_netbsd.go
new file mode 100644
index 0000000..31d0744
--- /dev/null
+++ b/libgo/go/net/fd_netbsd.go
@@ -0,0 +1,116 @@
+// 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.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err error) {
+ p = new(pollster)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
+ }
+ syscall.CloseOnExec(p.kq)
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if e != nil {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", e)
+ }
+ if ev.Data != 0 {
+ return false, syscall.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+ syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if e != nil {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go
index e52ac35..31d0744 100644
--- a/libgo/go/net/fd_openbsd.go
+++ b/libgo/go/net/fd_openbsd.go
@@ -26,6 +26,7 @@ func newpollster() (p *pollster, err error) {
if p.kq, err = syscall.Kqueue(); err != nil {
return nil, os.NewSyscallError("kqueue", err)
}
+ syscall.CloseOnExec(p.kq)
p.events = p.eventbuf[0:0]
return p, nil
}
diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go
index bf8cd9d..4ac280b 100644
--- a/libgo/go/net/file.go
+++ b/libgo/go/net/file.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package net
diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go
index 211ac44..a4f8f19 100644
--- a/libgo/go/net/http/client.go
+++ b/libgo/go/net/http/client.go
@@ -38,6 +38,11 @@ type Client struct {
// If CheckRedirect is nil, the Client uses its default policy,
// which is to stop after 10 consecutive requests.
CheckRedirect func(req *Request, via []*Request) error
+
+ // Jar specifies the cookie jar.
+ // If Jar is nil, cookies are not sent in requests and ignored
+ // in responses.
+ Jar CookieJar
}
// DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -180,6 +185,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
return nil, errors.New("http: nil Request.URL")
}
+ jar := c.Jar
+ if jar == nil {
+ jar = blackHoleJar{}
+ }
+
req := ireq
urlStr := "" // next relative or absolute URL to fetch (after first request)
for redirect := 0; ; redirect++ {
@@ -203,12 +213,19 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
break
}
}
+ for _, cookie := range jar.Cookies(req.URL) {
+ req.AddCookie(cookie)
+ }
}
urlStr = req.URL.String()
if r, err = send(req, c.Transport); err != nil {
break
}
+ if c := r.Cookies(); len(c) > 0 {
+ jar.SetCookies(req.URL, c)
+ }
+
if shouldRedirect(r.StatusCode) {
r.Body.Close()
if urlStr = r.Header.Get("Location"); urlStr == "" {
diff --git a/libgo/go/net/http/jar.go b/libgo/go/net/http/jar.go
new file mode 100644
index 0000000..2c2caa2
--- /dev/null
+++ b/libgo/go/net/http/jar.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 http
+
+import (
+ "net/url"
+)
+
+// A CookieJar manages storage and use of cookies in HTTP requests.
+//
+// Implementations of CookieJar must be safe for concurrent use by multiple
+// goroutines.
+type CookieJar interface {
+ // SetCookies handles the receipt of the cookies in a reply for the
+ // given URL. It may or may not choose to save the cookies, depending
+ // on the jar's policy and implementation.
+ SetCookies(u *url.URL, cookies []*Cookie)
+
+ // Cookies returns the cookies to send in a request for the given URL.
+ // It is up to the implementation to honor the standard cookie use
+ // restrictions such as in RFC 6265.
+ Cookies(u *url.URL) []*Cookie
+}
+
+type blackHoleJar struct{}
+
+func (blackHoleJar) SetCookies(u *url.URL, cookies []*Cookie) {}
+func (blackHoleJar) Cookies(u *url.URL) []*Cookie { return nil }
diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go
index c64fff6..ad7e3c0 100644
--- a/libgo/go/net/http/readrequest_test.go
+++ b/libgo/go/net/http/readrequest_test.go
@@ -219,7 +219,7 @@ func TestReadRequest(t *testing.T) {
t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
}
if !reflect.DeepEqual(tt.Trailer, req.Trailer) {
- t.Errorf("%#d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
+ t.Errorf("#%d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
}
}
}
diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go
index 714cb64..7b78645 100644
--- a/libgo/go/net/http/request_test.go
+++ b/libgo/go/net/http/request_test.go
@@ -202,8 +202,8 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
if g, e := req.FormValue("texta"), textaValue; g != e {
t.Errorf("texta value = %q, want %q", g, e)
}
- if g, e := req.FormValue("texta"), textaValue; g != e {
- t.Errorf("texta value = %q, want %q", g, e)
+ if g, e := req.FormValue("textb"), textbValue; g != e {
+ t.Errorf("textb value = %q, want %q", g, e)
}
if g := req.FormValue("missing"); g != "" {
t.Errorf("missing value = %q, want empty string", g)
@@ -214,14 +214,16 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
t.Error(n, " is *os.File, should not be")
}
}
- fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
- assertMem("filea", fd)
- fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+ fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
+ defer fda.Close()
+ assertMem("filea", fda)
+ fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+ defer fdb.Close()
if allMem {
- assertMem("fileb", fd)
+ assertMem("fileb", fdb)
} else {
- if _, ok := fd.(*os.File); !ok {
- t.Errorf("fileb has unexpected underlying type %T", fd)
+ if _, ok := fdb.(*os.File); !ok {
+ t.Errorf("fileb has unexpected underlying type %T", fdb)
}
}
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index c68e661..24e6b50 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -1164,15 +1164,15 @@ func BenchmarkClientServer(b *testing.B) {
for i := 0; i < b.N; i++ {
res, err := Get(ts.URL)
if err != nil {
- panic("Get: " + err.Error())
+ b.Fatal("Get:", err)
}
all, err := ioutil.ReadAll(res.Body)
if err != nil {
- panic("ReadAll: " + err.Error())
+ b.Fatal("ReadAll:", err)
}
body := string(all)
if body != "Hello world.\n" {
- panic("Got body: " + body)
+ b.Fatal("Got body:", body)
}
}
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
index e896d43..907f80a 100644
--- a/libgo/go/net/interface_bsd.go
+++ b/libgo/go/net/interface_bsd.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
// Network interface identification for BSD variants
@@ -18,21 +18,16 @@ import (
// network interfaces. Otheriwse it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
- var (
- tab []byte
- e error
- msgs []syscall.RoutingMessage
- ift []Interface
- )
-
- tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
- if e != nil {
- return nil, os.NewSyscallError("route rib", e)
+ var ift []Interface
+
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != nil {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
for _, m := range msgs {
@@ -54,9 +49,9 @@ func interfaceTable(ifindex int) ([]Interface, error) {
func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
var ift []Interface
- sas, e := syscall.ParseRoutingSockaddr(m)
- if e != nil {
- return nil, os.NewSyscallError("route sockaddr", e)
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
for _, s := range sas {
@@ -108,21 +103,16 @@ func linkFlags(rawFlags int32) Flags {
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
- var (
- tab []byte
- e error
- msgs []syscall.RoutingMessage
- ifat []Addr
- )
-
- tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
- if e != nil {
- return nil, os.NewSyscallError("route rib", e)
+ var ifat []Addr
+
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != nil {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
for _, m := range msgs {
@@ -133,7 +123,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
if err != nil {
return nil, err
}
- ifat = append(ifat, ifa...)
+ ifat = append(ifat, ifa)
}
}
}
@@ -141,32 +131,41 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
return ifat, nil
}
-func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) {
- var ifat []Addr
+func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
+ ifa := &IPNet{}
- sas, e := syscall.ParseRoutingSockaddr(m)
- if e != nil {
- return nil, os.NewSyscallError("route sockaddr", e)
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
- for _, s := range sas {
+ for i, s := range sas {
switch v := s.(type) {
case *syscall.SockaddrInet4:
- ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
- ifat = append(ifat, ifa.toAddr())
+ switch i {
+ case 0:
+ ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ case 1:
+ ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ }
case *syscall.SockaddrInet6:
- ifa := &IPAddr{IP: make(IP, IPv6len)}
- copy(ifa.IP, v.Addr[:])
- // NOTE: KAME based IPv6 protcol stack usually embeds
- // the interface index in the interface-local or link-
- // local address as the kernel-internal form.
- if ifa.IP.IsLinkLocalUnicast() {
- // remove embedded scope zone ID
- ifa.IP[2], ifa.IP[3] = 0, 0
+ switch i {
+ case 0:
+ ifa.Mask = make(IPMask, IPv6len)
+ copy(ifa.Mask, v.Addr[:])
+ case 1:
+ ifa.IP = make(IP, IPv6len)
+ copy(ifa.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifa.IP.IsLinkLocalUnicast() {
+ // remove embedded scope zone ID
+ ifa.IP[2], ifa.IP[3] = 0, 0
+ }
}
- ifat = append(ifat, ifa.toAddr())
}
}
- return ifat, nil
+ return ifa, nil
}
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index 96db718..c0887c5 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -17,21 +17,16 @@ import (
// network interfaces. Otheriwse it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
- var (
- ift []Interface
- tab []byte
- msgs []syscall.NetlinkMessage
- e error
- )
+ var ift []Interface
- tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
- if e != nil {
- return nil, os.NewSyscallError("netlink rib", e)
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink rib", err)
}
- msgs, e = syscall.ParseNetlinkMessage(tab)
- if e != nil {
- return nil, os.NewSyscallError("netlink message", e)
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink message", err)
}
for _, m := range msgs {
@@ -41,11 +36,11 @@ func interfaceTable(ifindex int) ([]Interface, error) {
case syscall.RTM_NEWLINK:
ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
if ifindex == 0 || ifindex == int(ifim.Index) {
- attrs, e := syscall.ParseNetlinkRouteAttr(&m)
- if e != nil {
- return nil, os.NewSyscallError("netlink routeattr", e)
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink routeattr", err)
}
- ifi := newLink(attrs, ifim)
+ ifi := newLink(ifim, attrs)
ift = append(ift, ifi)
}
}
@@ -55,7 +50,7 @@ done:
return ift, nil
}
-func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
@@ -102,19 +97,19 @@ func linkFlags(rawFlags uint32) Flags {
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
- tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
- if e != nil {
- return nil, os.NewSyscallError("netlink rib", e)
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink rib", err)
}
- msgs, e := syscall.ParseNetlinkMessage(tab)
- if e != nil {
- return nil, os.NewSyscallError("netlink message", e)
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink message", err)
}
- ifat, e := addrTable(msgs, ifindex)
- if e != nil {
- return nil, e
+ ifat, err := addrTable(msgs, ifindex)
+ if err != nil {
+ return nil, err
}
return ifat, nil
@@ -130,11 +125,11 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
case syscall.RTM_NEWADDR:
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
if ifindex == 0 || ifindex == int(ifam.Index) {
- attrs, e := syscall.ParseNetlinkRouteAttr(&m)
- if e != nil {
- return nil, os.NewSyscallError("netlink routeattr", e)
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink routeattr", err)
}
- ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
}
}
}
@@ -143,25 +138,23 @@ done:
return ifat, nil
}
-func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
- var ifat []Addr
-
+func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
+ ifa := &IPNet{}
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFA_ADDRESS:
switch family {
case syscall.AF_INET:
- ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
- ifat = append(ifat, ifa.toAddr())
+ ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+ ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
case syscall.AF_INET6:
- ifa := &IPAddr{IP: make(IP, IPv6len)}
+ ifa.IP = make(IP, IPv6len)
copy(ifa.IP, a.Value[:])
- ifat = append(ifat, ifa.toAddr())
+ ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
}
}
}
-
- return ifat
+ return ifa
}
// If the ifindex is zero, interfaceMulticastAddrTable returns
@@ -169,8 +162,8 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
- ifi *Interface
err error
+ ifi *Interface
)
if ifindex > 0 {
diff --git a/libgo/go/net/interface_netbsd.go b/libgo/go/net/interface_netbsd.go
new file mode 100644
index 0000000..4150e9a
--- /dev/null
+++ b/libgo/go/net/interface_netbsd.go
@@ -0,0 +1,14 @@
+// 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.
+
+// Network interface identification for NetBSD
+
+package net
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
index cc61491..4ce01dc 100644
--- a/libgo/go/net/interface_test.go
+++ b/libgo/go/net/interface_test.go
@@ -24,7 +24,7 @@ func sameInterface(i, j *Interface) bool {
func TestInterfaces(t *testing.T) {
ift, err := Interfaces()
if err != nil {
- t.Fatalf("Interfaces() failed: %v", err)
+ t.Fatalf("Interfaces failed: %v", err)
}
t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
@@ -43,34 +43,57 @@ func TestInterfaces(t *testing.T) {
if !sameInterface(ifxn, &ifi) {
t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
}
- ifat, err := ifi.Addrs()
- if err != nil {
- t.Fatalf("Interface.Addrs() failed: %v", err)
- }
- ifmat, err := ifi.MulticastAddrs()
- if err != nil {
- t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
- }
t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
- for _, ifa := range ifat {
- t.Logf("\tinterface address %q\n", ifa.String())
- }
- for _, ifma := range ifmat {
- t.Logf("\tjoined group address %q\n", ifma.String())
- }
t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+ testInterfaceAddrs(t, &ifi)
+ testInterfaceMulticastAddrs(t, &ifi)
}
}
func TestInterfaceAddrs(t *testing.T) {
ifat, err := InterfaceAddrs()
if err != nil {
- t.Fatalf("InterfaceAddrs() failed: %v", err)
+ t.Fatalf("InterfaceAddrs failed: %v", err)
}
t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+ testAddrs(t, ifat)
+}
+
+func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatalf("Interface.Addrs failed: %v", err)
+ }
+ testAddrs(t, ifat)
+}
+
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+ }
+ testMulticastAddrs(t, ifmat)
+}
+func testAddrs(t *testing.T, ifat []Addr) {
for _, ifa := range ifat {
- t.Logf("interface address %q\n", ifa.String())
+ switch ifa.(type) {
+ case *IPAddr, *IPNet:
+ t.Logf("\tinterface address %q\n", ifa.String())
+ default:
+ t.Errorf("\tunexpected type: %T", ifa)
+ }
+ }
+}
+
+func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+ for _, ifma := range ifmat {
+ switch ifma.(type) {
+ case *IPAddr:
+ t.Logf("\tjoined group address %q\n", ifma.String())
+ default:
+ t.Errorf("\tunexpected type: %T", ifma)
+ }
}
}
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index 4a38882..979d7ac 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -450,6 +450,9 @@ func (n *IPNet) String() string {
return nn.String() + "/" + itod(uint(l))
}
+// Network returns the address's network name, "ip+net".
+func (n *IPNet) Network() string { return "ip+net" }
+
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
index 60c405a..67a4049 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/ipraw_test.go
@@ -59,6 +59,7 @@ func parsePingReply(p []byte) (id, seq int) {
}
var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
+
// 127.0.0.1 because this is an IPv4-specific test.
var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index d3cb38a..7bb4c7d 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
// (Raw) IP sockets
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index f0ca7da..d141c05 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
package net
diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
index aae6d6c..5c47547 100644
--- a/libgo/go/net/lookup_unix.go
+++ b/libgo/go/net/lookup_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package net
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 48f0ae7..b236dfd 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -157,6 +157,14 @@ func (e *OpError) Timeout() bool {
return ok && t.Timeout()
}
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var errTimeout error = &timeoutError{}
+
type AddrError struct {
Err string
Addr string
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
index 035df4a..a410bb6 100644
--- a/libgo/go/net/newpollserver.go
+++ b/libgo/go/net/newpollserver.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package net
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
index 80597f7..16780da 100644
--- a/libgo/go/net/port.go
+++ b/libgo/go/net/port.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Read system port mappings from /etc/services
diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go
index a52a86e..c1845fa 100644
--- a/libgo/go/net/rpc/server_test.go
+++ b/libgo/go/net/rpc/server_test.go
@@ -516,12 +516,10 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
for atomic.AddInt32(&N, -1) >= 0 {
err = client.Call("Arith.Add", args, reply)
if err != nil {
- fmt.Printf("Add: expected no error but got string %q", err.Error())
- panic("rpc error")
+ b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
- fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B)
- panic("rpc error")
+ b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
}
}
wg.Done()
@@ -536,8 +534,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
once.Do(startServer)
client, err := dial()
if err != nil {
- fmt.Println("error dialing", err)
- return
+ b.Fatalf("error dialing:", err)
}
// Asynchronous calls
@@ -561,12 +558,11 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
}()
go func() {
for call := range res {
- a := call.Args.(*Args).A
- b := call.Args.(*Args).B
- c := call.Reply.(*Reply).C
- if a+b != c {
- fmt.Printf("Add: expected %d got %d", a+b, c)
- panic("incorrect reply")
+ A := call.Args.(*Args).A
+ B := call.Args.(*Args).B
+ C := call.Reply.(*Reply).C
+ if A+B != C {
+ b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
}
<-gate
if atomic.AddInt32(&recv, -1) == 0 {
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
index b0adea4..ff76ab9 100644
--- a/libgo/go/net/sendfile_stub.go
+++ b/libgo/go/net/sendfile_stub.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
package net
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index 777f204..dc07392 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
// Sockets
diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go
index 7025edf..816e4fc 100644
--- a/libgo/go/net/sock_bsd.go
+++ b/libgo/go/net/sock_bsd.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
// Sockets for BSD variants
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index 44890ba..a7c09c7 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
// TCP sockets
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
index 5aefe39..0460c1c 100644
--- a/libgo/go/net/textproto/reader_test.go
+++ b/libgo/go/net/textproto/reader_test.go
@@ -203,7 +203,7 @@ func TestRFC959Lines(t *testing.T) {
t.Errorf("#%d: code=%d, want %d", i, code, tt.wantCode)
}
if msg != tt.wantMsg {
- t.Errorf("%#d: msg=%q, want %q", i, msg, tt.wantMsg)
+ t.Errorf("#%d: msg=%q, want %q", i, msg, tt.wantMsg)
}
}
}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index c25ec9c..6bb1571 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
// UDP sockets
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index 929f640..10632c1 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
// Unix domain sockets
diff --git a/libgo/go/old/regexp/all_test.go b/libgo/go/old/regexp/all_test.go
index 9a04360..180dac4 100644
--- a/libgo/go/old/regexp/all_test.go
+++ b/libgo/go/old/regexp/all_test.go
@@ -321,8 +321,7 @@ func BenchmarkLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatal("no match!")
}
}
}
@@ -334,8 +333,7 @@ func BenchmarkNotLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatal("no match!")
}
}
}
@@ -347,8 +345,7 @@ func BenchmarkMatchClass(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatal("no match!")
}
}
}
@@ -362,8 +359,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatal("no match!")
}
}
}
diff --git a/libgo/go/old/template/template_test.go b/libgo/go/old/template/template_test.go
index a6e0c3e..f42a61a 100644
--- a/libgo/go/old/template/template_test.go
+++ b/libgo/go/old/template/template_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "os"
"strings"
"testing"
)
@@ -463,23 +464,32 @@ func TestAll(t *testing.T) {
// Parse
testAll(t, func(test *Test) (*Template, error) { return Parse(test.in, formatters) })
// ParseFile
+ f, err := ioutil.TempFile("", "template-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ name := f.Name()
+ f.Close()
+ os.Remove(name)
+ }()
testAll(t, func(test *Test) (*Template, error) {
- err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
if err != nil {
t.Error("unexpected write error:", err)
return nil, err
}
- return ParseFile("_test/test.tmpl", formatters)
+ return ParseFile(f.Name(), formatters)
})
// tmpl.ParseFile
testAll(t, func(test *Test) (*Template, error) {
- err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
if err != nil {
t.Error("unexpected write error:", err)
return nil, err
}
tmpl := New(formatters)
- return tmpl, tmpl.ParseFile("_test/test.tmpl")
+ return tmpl, tmpl.ParseFile(f.Name())
})
}
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
index e4dff83..e7a2955 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package os
diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go
index dbe1b9a..ebbe436 100644
--- a/libgo/go/os/error_posix.go
+++ b/libgo/go/os/error_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
package os
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index 4c95c1b..a00fdad 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -67,6 +67,9 @@ type Cmd struct {
// ExtraFiles specifies additional open files to be inherited by the
// new process. It does not include standard input, standard output, or
// standard error. If non-nil, entry i becomes file descriptor 3+i.
+ //
+ // BUG: on OS X 10.6, child processes may sometimes inherit extra fds.
+ // http://golang.org/issue/2603
ExtraFiles []*os.File
// SysProcAttr holds optional, operating system-specific attributes.
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index 8f63653..c684980 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -10,6 +10,9 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net"
+ "net/http"
+ "net/http/httptest"
"os"
"runtime"
"strconv"
@@ -18,7 +21,7 @@ import (
)
func helperCommand(s ...string) *Cmd {
- cs := []string{"-test.run=exec.TestHelperProcess", "--"}
+ cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
cmd := Command(os.Args[0], cs...)
cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
@@ -146,6 +149,23 @@ func TestExtraFiles(t *testing.T) {
t.Logf("no operating system support; skipping")
return
}
+
+ // Force network usage, to verify the epoll (or whatever) fd
+ // doesn't leak to the child,
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ // Force TLS root certs to be loaded (which might involve
+ // cgo), to make sure none of that potential C code leaks fds.
+ ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("Hello"))
+ }))
+ defer ts.Close()
+ http.Get(ts.URL) // ignore result; just calling to force root cert loading
+
tf, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("TempFile: %v", err)
@@ -167,7 +187,7 @@ func TestExtraFiles(t *testing.T) {
c.ExtraFiles = []*os.File{tf}
bs, err := c.CombinedOutput()
if err != nil {
- t.Fatalf("CombinedOutput: %v", err)
+ t.Fatalf("CombinedOutput: %v; output %q", err, bs)
}
if string(bs) != text {
t.Errorf("got %q; want %q", string(bs), text)
@@ -246,6 +266,32 @@ func TestHelperProcess(*testing.T) {
fmt.Printf("ReadAll from fd 3: %v", err)
os.Exit(1)
}
+ switch runtime.GOOS {
+ case "darwin":
+ // TODO(bradfitz): broken? Sometimes.
+ // http://golang.org/issue/2603
+ // Skip this additional part of the test for now.
+ default:
+ // Now verify that there are no other open fds.
+ var files []*os.File
+ for wantfd := os.Stderr.Fd() + 2; wantfd <= 100; wantfd++ {
+ f, err := os.Open(os.Args[0])
+ if err != nil {
+ fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
+ os.Exit(1)
+ }
+ if got := f.Fd(); got != wantfd {
+ fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
+ out, _ := Command("lsof", "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+ fmt.Print(string(out))
+ os.Exit(1)
+ }
+ files = append(files, f)
+ }
+ for _, f := range files {
+ f.Close()
+ }
+ }
os.Stderr.Write(bs)
case "exit":
n, _ := strconv.Atoi(args[0])
diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go
index 9665ea8..a221137 100644
--- a/libgo/go/os/exec/lp_unix.go
+++ b/libgo/go/os/exec/lp_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package exec
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 8b08eeb..218b8cd 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
package os
@@ -24,7 +24,7 @@ func (sig UnixSignal) String() string {
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
-// StartProcess is a low-level interface. The exec package provides
+// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
@@ -56,7 +56,7 @@ func (p *Process) Kill() error {
// If successful, Exec never returns. If it fails, it returns an error.
//
// To run a child process, see StartProcess (for a low-level interface)
-// or the exec package (for higher-level interfaces).
+// or the os/exec package (for higher-level interfaces).
func Exec(name string, argv []string, envv []string) error {
if envv == nil {
envv = Environ()
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 3dcac41..3758138 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package os
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index a4ab5d6..8231ef4 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.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.
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
package os
@@ -24,39 +24,6 @@ func epipecheck(file *File, e error) {
}
}
-// Remove removes the named file or directory.
-func Remove(name string) error {
- // System call interface forces us to know
- // whether name is a file or directory.
- // Try both: it is cheaper on average than
- // doing a Stat plus the right one.
- e := syscall.Unlink(name)
- if e == nil {
- return nil
- }
- e1 := syscall.Rmdir(name)
- if e1 == nil {
- return nil
- }
-
- // Both failed: figure out which error to return.
- // OS X and Linux differ on whether unlink(dir)
- // returns EISDIR, so can't use that. However,
- // both agree that rmdir(file) returns ENOTDIR,
- // so we can use that to decide which error is real.
- // Rmdir might also return ENOTDIR if given a bad
- // file path, like /etc/passwd/foo, but in that case,
- // both errors will be ENOTDIR, so it's okay to
- // use the error from unlink.
- // For windows syscall.ENOTDIR is set
- // to syscall.ERROR_PATH_NOT_FOUND, hopefully it should
- // do the trick.
- if e1 != syscall.ENOTDIR {
- e = e1
- }
- return &PathError{"remove", name, e}
-}
-
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 671d1a4..069baa1 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package os
@@ -67,8 +67,13 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
}
// There's a race here with fork/exec, which we are
- // content to live with. See ../syscall/exec.go
- if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+ // content to live with. See ../syscall/exec_unix.go.
+ // On OS X 10.6, the O_CLOEXEC flag is not respected.
+ // On OS X 10.7, the O_CLOEXEC flag works.
+ // Without a cheap & reliable way to detect 10.6 vs 10.7 at
+ // runtime, we just always call syscall.CloseOnExec on Darwin.
+ // Once >=10.7 is prevalent, this extra call can removed.
+ if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
syscall.CloseOnExec(r)
}
@@ -216,6 +221,36 @@ func Truncate(name string, size int64) error {
return nil
}
+// Remove removes the named file or directory.
+func Remove(name string) error {
+ // System call interface forces us to know
+ // whether name is a file or directory.
+ // Try both: it is cheaper on average than
+ // doing a Stat plus the right one.
+ e := syscall.Unlink(name)
+ if e == nil {
+ return nil
+ }
+ e1 := syscall.Rmdir(name)
+ if e1 == nil {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ // OS X and Linux differ on whether unlink(dir)
+ // returns EISDIR, so can't use that. However,
+ // both agree that rmdir(file) returns ENOTDIR,
+ // so we can use that to decide which error is real.
+ // Rmdir might also return ENOTDIR if given a bad
+ // file path, like /etc/passwd/foo, but in that case,
+ // both errors will be ENOTDIR, so it's okay to
+ // use the error from unlink.
+ if e1 != syscall.ENOTDIR {
+ e = e1
+ }
+ return &PathError{"remove", name, e}
+}
+
// basename removes trailing slashes and the leading directory name from path name
func basename(name string) string {
i := len(name) - 1
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 299d2e8..9a60990 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -917,7 +917,7 @@ func TestReadAt(t *testing.T) {
b := make([]byte, 5)
n, err := f.ReadAt(b, 7)
if err != nil || n != len(b) {
- t.Fatalf("ReadAt 7: %d, %r", n, err)
+ t.Fatalf("ReadAt 7: %d, %v", n, err)
}
if string(b) != "world" {
t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
index 3109a81..1f800d7 100644
--- a/libgo/go/os/os_unix_test.go
+++ b/libgo/go/os/os_unix_test.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package os_test
diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go
index 33045b6..30a167b 100644
--- a/libgo/go/os/path_unix.go
+++ b/libgo/go/os/path_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package os
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
index 520f3f8..bce4530 100644
--- a/libgo/go/os/signal/signal.go
+++ b/libgo/go/os/signal/signal.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 darwin freebsd linux netbsd openbsd
+
// Package signal implements operating system-independent signal handling.
package signal
@@ -31,3 +33,5 @@ func init() {
Incoming = ch
go process(ch)
}
+
+// BUG(rsc): This package is unavailable on Plan 9 and Windows.
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
index 00eb295..4568aa9 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.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 darwin freebsd linux netbsd openbsd
+
package signal
import (
diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go
index c6a6de5..d196469 100644
--- a/libgo/go/os/sys_bsd.go
+++ b/libgo/go/os/sys_bsd.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
// os code shared between *BSD systems including OS X (Darwin)
// and FreeBSD.
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index 0999ded..42fa557 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.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.
-// +build openbsd plan9 windows
+// +build nocgo windows
package user
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index 89886cb..602a3da 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build darwin freebsd linux
+// +build cgo
package user
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index e3d6c34..3dc52aa 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -147,6 +147,7 @@ func SplitList(path string) []string {
// separating it into a directory and file name component.
// If there is no Separator in 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) {
vol := VolumeName(path)
i := len(path) - 1
@@ -262,6 +263,8 @@ func Abs(path string) (string, error) {
// Rel returns a relative path that is lexically equivalent to targpath when
// joined to basepath with an intervening separator. That is,
// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
+// On success, the returned path will always be relative to basepath,
+// even if basepath and targpath share no elements.
// An error is returned if targpath can't be made relative to basepath or if
// knowing the current working directory would be necessary to compute it.
func Rel(basepath, targpath string) (string, error) {
@@ -423,6 +426,8 @@ func Base(path string) string {
for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
path = path[0 : len(path)-1]
}
+ // Throw away volume name
+ path = path[len(VolumeName(path)):]
// Find the last element
i := len(path) - 1
for i >= 0 && !os.IsPathSeparator(path[i]) {
@@ -437,3 +442,25 @@ func Base(path string) string {
}
return path
}
+
+// Dir returns the 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.
+// The returned path does not end in a separator unless it is the root directory.
+func Dir(path string) string {
+ vol := VolumeName(path)
+ i := len(path) - 1
+ for i >= len(vol) && !os.IsPathSeparator(path[i]) {
+ i--
+ }
+ dir := Clean(path[len(vol) : i+1])
+ last := len(dir) - 1
+ if last > 0 && os.IsPathSeparator(dir[last]) {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return vol + dir
+}
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index b5b0ded..63adcb8 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -422,14 +422,77 @@ var basetests = []PathTest{
{"a/b/c.x", "c.x"},
}
+var winbasetests = []PathTest{
+ {`c:\`, `\`},
+ {`c:.`, `.`},
+ {`c:\a\b`, `b`},
+ {`c:a\b`, `b`},
+ {`c:a\b\c`, `c`},
+ {`\\host\share\`, `\`},
+ {`\\host\share\a`, `a`},
+ {`\\host\share\a\b`, `b`},
+}
+
func TestBase(t *testing.T) {
- for _, test := range basetests {
- if s := filepath.ToSlash(filepath.Base(test.path)); s != test.result {
+ tests := basetests
+ if runtime.GOOS == "windows" {
+ // make unix tests work on windows
+ for i, _ := range tests {
+ tests[i].result = filepath.Clean(tests[i].result)
+ }
+ // add windows specific tests
+ tests = append(tests, winbasetests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Base(test.path); s != test.result {
t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
}
}
}
+var dirtests = []PathTest{
+ {"", "."},
+ {".", "."},
+ {"/.", "/"},
+ {"/", "/"},
+ {"////", "/"},
+ {"/foo", "/"},
+ {"x/", "x"},
+ {"abc", "."},
+ {"abc/def", "abc"},
+ {"a/b/.x", "a/b"},
+ {"a/b/c.", "a/b"},
+ {"a/b/c.x", "a/b"},
+}
+
+var windirtests = []PathTest{
+ {`c:\`, `c:\`},
+ {`c:.`, `c:.`},
+ {`c:\a\b`, `c:\a`},
+ {`c:a\b`, `c:a`},
+ {`c:a\b\c`, `c:a\b`},
+ {`\\host\share\`, `\\host\share\`},
+ {`\\host\share\a`, `\\host\share\`},
+ {`\\host\share\a\b`, `\\host\share\a`},
+}
+
+func TestDir(t *testing.T) {
+ tests := dirtests
+ if runtime.GOOS == "windows" {
+ // make unix tests work on windows
+ for i, _ := range tests {
+ tests[i].result = filepath.Clean(tests[i].result)
+ }
+ // add windows specific tests
+ tests = append(tests, windirtests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Dir(test.path); s != test.result {
+ t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
type IsAbsTest struct {
path string
isAbs bool
diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go
index daf0eb2..c5ac71e 100644
--- a/libgo/go/path/filepath/path_unix.go
+++ b/libgo/go/path/filepath/path_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package filepath
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
index 2353846..20d89c9 100644
--- a/libgo/go/path/path.go
+++ b/libgo/go/path/path.go
@@ -160,3 +160,21 @@ func Base(path string) string {
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.
+// 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.
+func Dir(path string) string {
+ dir, _ := Split(path)
+ dir = Clean(dir)
+ last := len(dir) - 1
+ if last > 0 && dir[last] == '/' {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return dir
+}
diff --git a/libgo/go/path/path_test.go b/libgo/go/path/path_test.go
index 1fd57cc..77f0804 100644
--- a/libgo/go/path/path_test.go
+++ b/libgo/go/path/path_test.go
@@ -8,11 +8,11 @@ import (
"testing"
)
-type CleanTest struct {
- path, clean string
+type PathTest struct {
+ path, result string
}
-var cleantests = []CleanTest{
+var cleantests = []PathTest{
// Already clean
{"", "."},
{"abc", "abc"},
@@ -64,8 +64,8 @@ var cleantests = []CleanTest{
func TestClean(t *testing.T) {
for _, test := range cleantests {
- if s := Clean(test.path); s != test.clean {
- t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+ if s := Clean(test.path); s != test.result {
+ t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
}
}
}
@@ -148,7 +148,7 @@ func TestExt(t *testing.T) {
}
}
-var basetests = []CleanTest{
+var basetests = []PathTest{
// Already clean
{"", "."},
{".", "."},
@@ -165,8 +165,31 @@ var basetests = []CleanTest{
func TestBase(t *testing.T) {
for _, test := range basetests {
- if s := Base(test.path); s != test.clean {
- t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+ if s := Base(test.path); s != test.result {
+ t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
+var dirtests = []PathTest{
+ {"", "."},
+ {".", "."},
+ {"/.", "/"},
+ {"/", "/"},
+ {"////", "/"},
+ {"/foo", "/"},
+ {"x/", "x"},
+ {"abc", "."},
+ {"abc/def", "abc"},
+ {"a/b/.x", "a/b"},
+ {"a/b/c.", "a/b"},
+ {"a/b/c.x", "a/b"},
+}
+
+func TestDir(t *testing.T) {
+ for _, test := range dirtests {
+ if s := Dir(test.path); s != test.result {
+ t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
}
}
}
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
index 8810796..e729510 100644
--- a/libgo/go/regexp/all_test.go
+++ b/libgo/go/regexp/all_test.go
@@ -324,8 +324,7 @@ func BenchmarkLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -337,8 +336,7 @@ func BenchmarkNotLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -350,8 +348,7 @@ func BenchmarkMatchClass(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -365,8 +362,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
diff --git a/libgo/go/regexp/exec_test.go b/libgo/go/regexp/exec_test.go
index 312bf02..e668574 100644
--- a/libgo/go/regexp/exec_test.go
+++ b/libgo/go/regexp/exec_test.go
@@ -673,7 +673,7 @@ func benchmark(b *testing.B, re string, n int) {
b.SetBytes(int64(n))
for i := 0; i < b.N; i++ {
if r.Match(t) {
- panic("match!")
+ b.Fatal("match!")
}
}
}
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
index 83ee170..4aa4ca6 100644
--- a/libgo/go/sort/sort.go
+++ b/libgo/go/sort/sort.go
@@ -240,14 +240,18 @@ func (p StringSlice) Sort() { Sort(p) }
// Ints sorts a slice of ints in increasing order.
func Ints(a []int) { Sort(IntSlice(a)) }
+
// Float64s sorts a slice of float64s in increasing order.
func Float64s(a []float64) { Sort(Float64Slice(a)) }
+
// Strings sorts a slice of strings in increasing order.
func Strings(a []string) { Sort(StringSlice(a)) }
// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+
// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+
// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index 8bda890..42fc431 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -263,6 +263,18 @@ func (d *decimal) atof32int() float32 {
return f
}
+// Reads a uint64 decimal mantissa, which might be truncated.
+func (d *decimal) atou64() (mant uint64, digits int) {
+ const uint64digits = 19
+ for i, c := range d.d[:d.nd] {
+ if i == uint64digits {
+ return mant, i
+ }
+ mant = 10*mant + uint64(c-'0')
+ }
+ return mant, d.nd
+}
+
// Exact powers of 10.
var float64pow10 = []float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
@@ -375,6 +387,17 @@ func atof64(s string) (f float64, err error) {
if f, ok := d.atof64(); ok {
return f, nil
}
+
+ // Try another fast path.
+ ext := new(extFloat)
+ if ok := ext.AssignDecimal(&d); ok {
+ b, ovf := ext.floatBits()
+ f = math.Float64frombits(b)
+ if ovf {
+ err = rangeError(fnParseFloat, s)
+ }
+ return f, err
+ }
}
b, ovf := d.floatBits(&float64info)
f = math.Float64frombits(b)
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
index 4d5ce171..3fa637d 100644
--- a/libgo/go/strconv/atof_test.go
+++ b/libgo/go/strconv/atof_test.go
@@ -5,9 +5,12 @@
package strconv_test
import (
+ "math"
+ "math/rand"
"reflect"
. "strconv"
"testing"
+ "time"
)
type atofTest struct {
@@ -111,8 +114,22 @@ var atoftests = []atofTest{
{"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
{"2.2250738585072011e-308", "2.225073858507201e-308", nil},
+
+ // A very large number (initially wrongly parsed by the fast algorithm).
+ {"4.630813248087435e+307", "4.630813248087435e+307", nil},
+}
+
+type atofSimpleTest struct {
+ x float64
+ s string
}
+var (
+ atofRandomTests []atofSimpleTest
+ benchmarksRandomBits [1024]string
+ benchmarksRandomNormal [1024]string
+)
+
func init() {
// The atof routines return NumErrors wrapping
// the error and the string. Convert the table above.
@@ -122,6 +139,31 @@ func init() {
test.err = &NumError{"ParseFloat", test.in, test.err}
}
}
+
+ // Generate random inputs for tests and benchmarks
+ rand.Seed(time.Now().UnixNano())
+ if testing.Short() {
+ atofRandomTests = make([]atofSimpleTest, 100)
+ } else {
+ atofRandomTests = make([]atofSimpleTest, 10000)
+ }
+ for i := range atofRandomTests {
+ n := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ x := math.Float64frombits(n)
+ s := FormatFloat(x, 'g', -1, 64)
+ atofRandomTests[i] = atofSimpleTest{x, s}
+ }
+
+ for i := range benchmarksRandomBits {
+ bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ x := math.Float64frombits(bits)
+ benchmarksRandomBits[i] = FormatFloat(x, 'g', -1, 64)
+ }
+
+ for i := range benchmarksRandomNormal {
+ x := rand.NormFloat64()
+ benchmarksRandomNormal[i] = FormatFloat(x, 'g', -1, 64)
+ }
}
func testAtof(t *testing.T, opt bool) {
@@ -156,6 +198,19 @@ func TestAtof(t *testing.T) { testAtof(t, true) }
func TestAtofSlow(t *testing.T) { testAtof(t, false) }
+func TestAtofRandom(t *testing.T) {
+ for _, test := range atofRandomTests {
+ x, _ := ParseFloat(test.s, 64)
+ switch {
+ default:
+ t.Errorf("number %s badly parsed as %b (expected %b)", test.s, x, test.x)
+ case x == test.x:
+ case math.IsNaN(test.x) && math.IsNaN(x):
+ }
+ }
+ t.Logf("tested %d random numbers", len(atofRandomTests))
+}
+
func BenchmarkAtof64Decimal(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseFloat("33909", 64)
@@ -179,3 +234,15 @@ func BenchmarkAtof64Big(b *testing.B) {
ParseFloat("123456789123456789123456789", 64)
}
}
+
+func BenchmarkAtof64RandomBits(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ParseFloat(benchmarksRandomBits[i%1024], 64)
+ }
+}
+
+func BenchmarkAtof64RandomFloats(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ParseFloat(benchmarksRandomNormal[i%1024], 64)
+ }
+}
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
index 5415530..cc5591a 100644
--- a/libgo/go/strconv/decimal.go
+++ b/libgo/go/strconv/decimal.go
@@ -14,9 +14,9 @@ package strconv
type decimal struct {
// TODO(rsc): Can make d[] a bit smaller and add
// truncated bool;
- d [2000]byte // digits
- nd int // number of digits used
- dp int // decimal point
+ d [800]byte // digits
+ nd int // number of digits used
+ dp int // decimal point
neg bool
}
diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go
new file mode 100644
index 0000000..980052a7
--- /dev/null
+++ b/libgo/go/strconv/extfloat.go
@@ -0,0 +1,311 @@
+// 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 strconv
+
+import "math"
+
+// An extFloat represents an extended floating-point number, with more
+// precision than a float64. It does not try to save bits: the
+// number represented by the structure is mant*(2^exp), with a negative
+// sign if neg is true.
+type extFloat struct {
+ mant uint64
+ exp int
+ neg bool
+}
+
+// Powers of ten taken from double-conversion library.
+// http://code.google.com/p/double-conversion/
+const (
+ firstPowerOfTen = -348
+ stepPowerOfTen = 8
+)
+
+var smallPowersOfTen = [...]extFloat{
+ {1 << 63, -63, false}, // 1
+ {0xa << 60, -60, false}, // 1e1
+ {0x64 << 57, -57, false}, // 1e2
+ {0x3e8 << 54, -54, false}, // 1e3
+ {0x2710 << 50, -50, false}, // 1e4
+ {0x186a0 << 47, -47, false}, // 1e5
+ {0xf4240 << 44, -44, false}, // 1e6
+ {0x989680 << 40, -40, false}, // 1e7
+}
+
+var powersOfTen = [...]extFloat{
+ {0xfa8fd5a0081c0288, -1220, false}, // 10^-348
+ {0xbaaee17fa23ebf76, -1193, false}, // 10^-340
+ {0x8b16fb203055ac76, -1166, false}, // 10^-332
+ {0xcf42894a5dce35ea, -1140, false}, // 10^-324
+ {0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
+ {0xe61acf033d1a45df, -1087, false}, // 10^-308
+ {0xab70fe17c79ac6ca, -1060, false}, // 10^-300
+ {0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
+ {0xbe5691ef416bd60c, -1007, false}, // 10^-284
+ {0x8dd01fad907ffc3c, -980, false}, // 10^-276
+ {0xd3515c2831559a83, -954, false}, // 10^-268
+ {0x9d71ac8fada6c9b5, -927, false}, // 10^-260
+ {0xea9c227723ee8bcb, -901, false}, // 10^-252
+ {0xaecc49914078536d, -874, false}, // 10^-244
+ {0x823c12795db6ce57, -847, false}, // 10^-236
+ {0xc21094364dfb5637, -821, false}, // 10^-228
+ {0x9096ea6f3848984f, -794, false}, // 10^-220
+ {0xd77485cb25823ac7, -768, false}, // 10^-212
+ {0xa086cfcd97bf97f4, -741, false}, // 10^-204
+ {0xef340a98172aace5, -715, false}, // 10^-196
+ {0xb23867fb2a35b28e, -688, false}, // 10^-188
+ {0x84c8d4dfd2c63f3b, -661, false}, // 10^-180
+ {0xc5dd44271ad3cdba, -635, false}, // 10^-172
+ {0x936b9fcebb25c996, -608, false}, // 10^-164
+ {0xdbac6c247d62a584, -582, false}, // 10^-156
+ {0xa3ab66580d5fdaf6, -555, false}, // 10^-148
+ {0xf3e2f893dec3f126, -529, false}, // 10^-140
+ {0xb5b5ada8aaff80b8, -502, false}, // 10^-132
+ {0x87625f056c7c4a8b, -475, false}, // 10^-124
+ {0xc9bcff6034c13053, -449, false}, // 10^-116
+ {0x964e858c91ba2655, -422, false}, // 10^-108
+ {0xdff9772470297ebd, -396, false}, // 10^-100
+ {0xa6dfbd9fb8e5b88f, -369, false}, // 10^-92
+ {0xf8a95fcf88747d94, -343, false}, // 10^-84
+ {0xb94470938fa89bcf, -316, false}, // 10^-76
+ {0x8a08f0f8bf0f156b, -289, false}, // 10^-68
+ {0xcdb02555653131b6, -263, false}, // 10^-60
+ {0x993fe2c6d07b7fac, -236, false}, // 10^-52
+ {0xe45c10c42a2b3b06, -210, false}, // 10^-44
+ {0xaa242499697392d3, -183, false}, // 10^-36
+ {0xfd87b5f28300ca0e, -157, false}, // 10^-28
+ {0xbce5086492111aeb, -130, false}, // 10^-20
+ {0x8cbccc096f5088cc, -103, false}, // 10^-12
+ {0xd1b71758e219652c, -77, false}, // 10^-4
+ {0x9c40000000000000, -50, false}, // 10^4
+ {0xe8d4a51000000000, -24, false}, // 10^12
+ {0xad78ebc5ac620000, 3, false}, // 10^20
+ {0x813f3978f8940984, 30, false}, // 10^28
+ {0xc097ce7bc90715b3, 56, false}, // 10^36
+ {0x8f7e32ce7bea5c70, 83, false}, // 10^44
+ {0xd5d238a4abe98068, 109, false}, // 10^52
+ {0x9f4f2726179a2245, 136, false}, // 10^60
+ {0xed63a231d4c4fb27, 162, false}, // 10^68
+ {0xb0de65388cc8ada8, 189, false}, // 10^76
+ {0x83c7088e1aab65db, 216, false}, // 10^84
+ {0xc45d1df942711d9a, 242, false}, // 10^92
+ {0x924d692ca61be758, 269, false}, // 10^100
+ {0xda01ee641a708dea, 295, false}, // 10^108
+ {0xa26da3999aef774a, 322, false}, // 10^116
+ {0xf209787bb47d6b85, 348, false}, // 10^124
+ {0xb454e4a179dd1877, 375, false}, // 10^132
+ {0x865b86925b9bc5c2, 402, false}, // 10^140
+ {0xc83553c5c8965d3d, 428, false}, // 10^148
+ {0x952ab45cfa97a0b3, 455, false}, // 10^156
+ {0xde469fbd99a05fe3, 481, false}, // 10^164
+ {0xa59bc234db398c25, 508, false}, // 10^172
+ {0xf6c69a72a3989f5c, 534, false}, // 10^180
+ {0xb7dcbf5354e9bece, 561, false}, // 10^188
+ {0x88fcf317f22241e2, 588, false}, // 10^196
+ {0xcc20ce9bd35c78a5, 614, false}, // 10^204
+ {0x98165af37b2153df, 641, false}, // 10^212
+ {0xe2a0b5dc971f303a, 667, false}, // 10^220
+ {0xa8d9d1535ce3b396, 694, false}, // 10^228
+ {0xfb9b7cd9a4a7443c, 720, false}, // 10^236
+ {0xbb764c4ca7a44410, 747, false}, // 10^244
+ {0x8bab8eefb6409c1a, 774, false}, // 10^252
+ {0xd01fef10a657842c, 800, false}, // 10^260
+ {0x9b10a4e5e9913129, 827, false}, // 10^268
+ {0xe7109bfba19c0c9d, 853, false}, // 10^276
+ {0xac2820d9623bf429, 880, false}, // 10^284
+ {0x80444b5e7aa7cf85, 907, false}, // 10^292
+ {0xbf21e44003acdd2d, 933, false}, // 10^300
+ {0x8e679c2f5e44ff8f, 960, false}, // 10^308
+ {0xd433179d9c8cb841, 986, false}, // 10^316
+ {0x9e19db92b4e31ba9, 1013, false}, // 10^324
+ {0xeb96bf6ebadf77d9, 1039, false}, // 10^332
+ {0xaf87023b9bf0ee6b, 1066, false}, // 10^340
+}
+
+// floatBits returns the bits of the float64 that best approximates
+// the extFloat passed as receiver. Overflow is set to true if
+// the resulting float64 is ±Inf.
+func (f *extFloat) floatBits() (bits uint64, overflow bool) {
+ flt := &float64info
+ f.Normalize()
+
+ exp := f.exp + 63
+
+ // Exponent too small.
+ if exp < flt.bias+1 {
+ n := flt.bias + 1 - exp
+ f.mant >>= uint(n)
+ exp += n
+ }
+
+ // Extract 1+flt.mantbits bits.
+ mant := f.mant >> (63 - flt.mantbits)
+ if f.mant&(1<<(62-flt.mantbits)) != 0 {
+ // Round up.
+ mant += 1
+ }
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<<flt.mantbits {
+ mant >>= 1
+ exp++
+ }
+
+ // Infinities.
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+
+ // Denormalized?
+ if mant&(1<<flt.mantbits) == 0 {
+ exp = flt.bias
+ }
+ goto out
+
+overflow:
+ // ±Inf
+ mant = 0
+ exp = 1<<flt.expbits - 1 + flt.bias
+ overflow = true
+
+out:
+ // Assemble bits.
+ bits = mant & (uint64(1)<<flt.mantbits - 1)
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+ if f.neg {
+ bits |= 1 << (flt.mantbits + flt.expbits)
+ }
+ return
+}
+
+// Assign sets f to the value of x.
+func (f *extFloat) Assign(x float64) {
+ if x < 0 {
+ x = -x
+ f.neg = true
+ }
+ x, f.exp = math.Frexp(x)
+ f.mant = uint64(x * float64(1<<64))
+ f.exp -= 64
+}
+
+// Normalize normalizes f so that the highest bit of the mantissa is
+// set, and returns the number by which the mantissa was left-shifted.
+func (f *extFloat) Normalize() uint {
+ if f.mant == 0 {
+ return 0
+ }
+ exp_before := f.exp
+ for f.mant < (1 << 55) {
+ f.mant <<= 8
+ f.exp -= 8
+ }
+ for f.mant < (1 << 63) {
+ f.mant <<= 1
+ f.exp -= 1
+ }
+ return uint(exp_before - f.exp)
+}
+
+// Multiply sets f to the product f*g: the result is correctly rounded,
+// but not normalized.
+func (f *extFloat) Multiply(g extFloat) {
+ fhi, flo := f.mant>>32, uint64(uint32(f.mant))
+ ghi, glo := g.mant>>32, uint64(uint32(g.mant))
+
+ // Cross products.
+ cross1 := fhi * glo
+ cross2 := flo * ghi
+
+ // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
+ f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
+ rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+ // Round up.
+ rem += (1 << 31)
+
+ f.mant += (rem >> 32)
+ f.exp = f.exp + g.exp + 64
+}
+
+var uint64pow10 = [...]uint64{
+ 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// AssignDecimal sets f to an approximate value of the decimal d. It
+// returns true if the value represented by f is guaranteed to be the
+// best approximation of d after being rounded to a float64.
+func (f *extFloat) AssignDecimal(d *decimal) (ok bool) {
+ const uint64digits = 19
+ const errorscale = 8
+ mant10, digits := d.atou64()
+ exp10 := d.dp - digits
+ errors := 0 // An upper bound for error, computed in errorscale*ulp.
+
+ if digits < d.nd {
+ // the decimal number was truncated.
+ errors += errorscale / 2
+ }
+
+ f.mant = mant10
+ f.exp = 0
+ f.neg = d.neg
+
+ // Multiply by powers of ten.
+ i := (exp10 - firstPowerOfTen) / stepPowerOfTen
+ if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
+ return false
+ }
+ adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
+
+ // We multiply by exp%step
+ if digits+adjExp <= uint64digits {
+ // We can multiply the mantissa
+ f.mant *= uint64(float64pow10[adjExp])
+ f.Normalize()
+ } else {
+ f.Normalize()
+ f.Multiply(smallPowersOfTen[adjExp])
+ errors += errorscale / 2
+ }
+
+ // We multiply by 10 to the exp - exp%step.
+ f.Multiply(powersOfTen[i])
+ if errors > 0 {
+ errors += 1
+ }
+ errors += errorscale / 2
+
+ // Normalize
+ shift := f.Normalize()
+ errors <<= shift
+
+ // Now f is a good approximation of the decimal.
+ // Check whether the error is too large: that is, if the mantissa
+ // is perturbated by the error, the resulting float64 will change.
+ // The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
+ //
+ // In many cases the approximation will be good enough.
+ const denormalExp = -1023 - 63
+ flt := &float64info
+ var extrabits uint
+ if f.exp <= denormalExp {
+ extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+ } else {
+ extrabits = uint(63 - flt.mantbits)
+ }
+
+ halfway := uint64(1) << (extrabits - 1)
+ mant_extra := f.mant & (1<<extrabits - 1)
+
+ // Do a signed comparison here! If the error estimate could make
+ // the mantissa round differently for the conversion to double,
+ // then we can't give a definite answer.
+ if int64(halfway)-int64(errors) < int64(mant_extra) &&
+ int64(mant_extra) < int64(halfway)+int64(errors) {
+ return false
+ }
+ return true
+}
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
index 692e3e4..f4434fd 100644
--- a/libgo/go/strconv/ftoa.go
+++ b/libgo/go/strconv/ftoa.go
@@ -40,11 +40,7 @@ var float64info = floatInfo{52, 11, -1023}
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
-// necessary such that Atof32 will return f exactly.
-//
-// Ftoa32(f) is not the same as Ftoa64(float32(f)),
-// because correct rounding and the number of digits
-// needed to identify f depend on the precision of the representation.
+// necessary such that ParseFloat will return f exactly.
func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
}
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index 8866d22..54046d6 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -8,7 +8,6 @@ import (
"bytes"
"io"
"reflect"
- "strconv"
. "strings"
"testing"
"unicode"
@@ -143,7 +142,7 @@ const benchmarkString = "some_text=some☺value"
func BenchmarkIndexRune(b *testing.B) {
if got := IndexRune(benchmarkString, '☺'); got != 14 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 14, got=%d", got)
}
for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, '☺')
@@ -152,7 +151,7 @@ func BenchmarkIndexRune(b *testing.B) {
func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 17, got=%d", got)
}
for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, 'v')
@@ -161,7 +160,7 @@ func BenchmarkIndexRuneFastPath(b *testing.B) {
func BenchmarkIndex(b *testing.B) {
if got := Index(benchmarkString, "v"); got != 17 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 17, got=%d", got)
}
for i := 0; i < b.N; i++ {
Index(benchmarkString, "v")
diff --git a/libgo/go/syscall/bpf_bsd.go b/libgo/go/syscall/bpf_bsd.go
index f94b723..f98036c 100644
--- a/libgo/go/syscall/bpf_bsd.go
+++ b/libgo/go/syscall/bpf_bsd.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
// Berkeley packet filter for BSD variants
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
index df25909..3ba0fb1 100644
--- a/libgo/go/syscall/env_unix.go
+++ b/libgo/go/syscall/env_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Unix environment variables.
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index c9814b7..0cd37c4 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_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 darwin freebsd linux netbsd openbsd
+
// Fork, exec, wait, etc.
package syscall
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index bc4c15e..e17d976 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.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.
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
// Routing sockets and messages
@@ -85,8 +85,8 @@ func (m *RouteMessage) sockaddr() []Sockaddr {
rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
switch i {
case RTAX_DST, RTAX_GATEWAY:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != nil {
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
return nil
}
if i == RTAX_DST {
@@ -128,8 +128,8 @@ func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
if m.Header.Addrs&RTA_IFP == 0 {
return nil
}
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
- if e != nil {
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+ if err != nil {
return nil
}
return append(sas, sa)
@@ -157,12 +157,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
switch i {
case RTAX_IFA:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != nil {
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
return nil
}
sas = append(sas, sa)
- case RTAX_NETMASK, RTAX_BRD:
+ case RTAX_NETMASK:
+ if rsa.Family == AF_UNSPEC {
+ rsa.Family = AF_INET // an old fasion, AF_UNSPEC means AF_INET
+ }
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
+ return nil
+ }
+ sas = append(sas, sa)
+ case RTAX_BRD:
// nothing to do
}
buf = buf[rsaAlignOf(int(rsa.Len)):]
diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go
new file mode 100644
index 0000000..d6d9031
--- /dev/null
+++ b/libgo/go/syscall/route_netbsd.go
@@ -0,0 +1,35 @@
+// 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.
+
+// Routing sockets and messages for NetBSD
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+ switch any.Type {
+ case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ rtm := &RouteMessage{}
+ rtm.Header = p.Header
+ rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+ return rtm
+ case RTM_IFINFO:
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ ifm := &InterfaceMessage{}
+ ifm.Header = p.Header
+ ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+ return ifm
+ case RTM_NEWADDR, RTM_DELADDR:
+ p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+ ifam := &InterfaceAddrMessage{}
+ ifam.Header = p.Header
+ ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+ return ifam
+ }
+ return nil
+}
diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go
index 84c1383..d279dec 100644
--- a/libgo/go/syscall/sockcmsg_unix.go
+++ b/libgo/go/syscall/sockcmsg_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Socket control messages
diff --git a/libgo/go/syscall/socket_linux.go b/libgo/go/syscall/socket_linux.go
index 212e0b2..42ab218 100644
--- a/libgo/go/syscall/socket_linux.go
+++ b/libgo/go/syscall/socket_linux.go
@@ -167,6 +167,9 @@ func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
//sysnb EpollCreate(size int) (fd int, err error)
//epoll_create(size int) int
+//sysnb EpollCreate1(flags int) (fd int, err error)
+//epoll_create1(flags int) int
+
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
//epoll_ctl(epfd int, op int, fd int, event *EpollEvent) int
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index 07d3af3..ba109f6 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package syscall
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index e81e5c5..4ce6370 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -25,12 +25,12 @@ type InternalBenchmark struct {
// B is a type passed to Benchmark functions to manage benchmark
// timing and to specify the number of iterations to run.
type B struct {
+ common
N int
benchmark InternalBenchmark
- ns time.Duration
bytes int64
- start time.Time
timerOn bool
+ result BenchmarkResult
}
// StartTimer starts timing a test. This function is called automatically
@@ -48,7 +48,7 @@ func (b *B) StartTimer() {
// want to measure.
func (b *B) StopTimer() {
if b.timerOn {
- b.ns += time.Now().Sub(b.start)
+ b.duration += time.Now().Sub(b.start)
b.timerOn = false
}
}
@@ -59,7 +59,7 @@ func (b *B) ResetTimer() {
if b.timerOn {
b.start = time.Now()
}
- b.ns = 0
+ b.duration = 0
}
// SetBytes records the number of bytes processed in a single operation.
@@ -70,7 +70,7 @@ func (b *B) nsPerOp() int64 {
if b.N <= 0 {
return 0
}
- return b.ns.Nanoseconds() / int64(b.N)
+ return b.duration.Nanoseconds() / int64(b.N)
}
// runN runs a single benchmark for the specified number of iterations.
@@ -127,17 +127,25 @@ func roundUp(n int) int {
return 10 * base
}
-// run times the benchmark function. It gradually increases the number
+// run times the benchmark function in a separate goroutine.
+func (b *B) run() BenchmarkResult {
+ go b.launch()
+ <-b.signal
+ return b.result
+}
+
+// launch launches the benchmark function. It gradually increases the number
// of benchmark iterations until the benchmark runs for a second in order
// to get a reasonable measurement. It prints timing information in this form
// testing.BenchmarkHello 100000 19 ns/op
-func (b *B) run() BenchmarkResult {
+// launch is run by the fun function as a separate goroutine.
+func (b *B) launch() {
// Run the benchmark for a single iteration in case it's expensive.
n := 1
b.runN(n)
// Run the benchmark for at least the specified amount of time.
d := time.Duration(*benchTime * float64(time.Second))
- for b.ns < d && n < 1e9 {
+ for !b.failed && b.duration < d && n < 1e9 {
last := n
// Predict iterations/sec.
if b.nsPerOp() == 0 {
@@ -153,7 +161,8 @@ func (b *B) run() BenchmarkResult {
n = roundUp(n)
b.runN(n)
}
- return BenchmarkResult{b.N, b.ns, b.bytes}
+ b.result = BenchmarkResult{b.N, b.duration, b.bytes}
+ b.signal <- b
}
// The results of a benchmark run.
@@ -215,14 +224,32 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
}
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
- b := &B{benchmark: Benchmark}
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: Benchmark,
+ }
benchName := Benchmark.Name
if procs != 1 {
benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
}
fmt.Printf("%s\t", benchName)
r := b.run()
+ if b.failed {
+ // The output could be very long here, but probably isn't.
+ // We print it all, regardless, because we don't want to trim the reason
+ // the benchmark failed.
+ fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
+ continue
+ }
fmt.Printf("%v\n", r)
+ // Unlike with tests, we ignore the -chatty flag and always print output for
+ // benchmarks since the output generation time will skew the results.
+ if len(b.output) > 0 {
+ b.trimOutput()
+ fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
+ }
if p := runtime.GOMAXPROCS(-1); p != procs {
fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
}
@@ -230,9 +257,31 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
}
}
+// trimOutput shortens the output from a benchmark, which can be very long.
+func (b *B) trimOutput() {
+ // The output is likely to appear multiple times because the benchmark
+ // is run multiple times, but at least it will be seen. This is not a big deal
+ // because benchmarks rarely print, but just in case, we trim it if it's too long.
+ const maxNewlines = 10
+ for nlCount, j := 0, 0; j < len(b.output); j++ {
+ if b.output[j] == '\n' {
+ nlCount++
+ if nlCount >= maxNewlines {
+ b.output = append(b.output[:j], "\n\t... [output truncated]\n"...)
+ break
+ }
+ }
+ }
+}
+
// Benchmark benchmarks a single function. Useful for creating
// custom benchmarks that do not use gotest.
func Benchmark(f func(b *B)) BenchmarkResult {
- b := &B{benchmark: InternalBenchmark{"", f}}
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: InternalBenchmark{"", f},
+ }
return b.run()
}
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index e23f13b..fdeda13 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
+ "strings"
"time"
)
@@ -67,11 +68,9 @@ func RunExamples(examples []InternalExample) (ok bool) {
// report any errors
tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
- if out != eg.Output {
- fmt.Printf(
- "--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
- eg.Name, tstr, out, eg.Output,
- )
+ if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
+ fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
+ eg.Name, tstr, g, e)
ok = false
} else if *chatty {
fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index ca2fced..16890e0 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -23,8 +23,8 @@
// }
// The benchmark package will vary b.N until the benchmark function lasts
// long enough to be timed reliably. The output
-// testing.BenchmarkHello 500000 4076 ns/op
-// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+// testing.BenchmarkHello 10000000 282 ns/op
+// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
// If a benchmark needs some expensive setup before running, the timer
// may be stopped:
@@ -70,6 +70,17 @@ var (
cpuList []int
)
+// common holds the elements common between T and B and
+// captures common methods such as Errorf.
+type common struct {
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ start time.Time // Time test or benchmark started
+ duration time.Duration
+ self interface{} // To be sent on signal channel when done.
+ signal chan interface{} // Output for serial tests.
+}
+
// Short reports whether the -test.short flag is set.
func Short() bool {
return *short
@@ -79,7 +90,7 @@ func Short() bool {
// If addFileLine is true, it also prefixes the string with the file and line of the call site.
func decorate(s string, addFileLine bool) string {
if addFileLine {
- _, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+ _, file, line, ok := runtime.Caller(4) // decorate + log + public function.
if ok {
// Truncate file name at last file name separator.
if index := strings.LastIndex(file, "/"); index >= 0 {
@@ -111,70 +122,68 @@ func decorate(s string, addFileLine bool) string {
// T is a type passed to Test functions to manage test state and support formatted test logs.
// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
- name string // Name of test.
- errors string // Error string from test.
- failed bool // Test has failed.
- ch chan *T // Output for serial tests.
- startParallel chan bool // Parallel tests will wait on this.
- start time.Time // Time test started
- dt time.Duration // Length of test
+ common
+ name string // Name of test.
+ startParallel chan bool // Parallel tests will wait on this.
}
-// Fail marks the Test function as having failed but continues execution.
-func (t *T) Fail() { t.failed = true }
+// Fail marks the function as having failed but continues execution.
+func (c *common) Fail() { c.failed = true }
-// Failed returns whether the Test function has failed.
-func (t *T) Failed() bool { return t.failed }
+// Failed returns whether the function has failed.
+func (c *common) Failed() bool { return c.failed }
-// FailNow marks the Test function as having failed and stops its execution.
+// FailNow marks the function as having failed and stops its execution.
// Execution will continue at the next Test.
-func (t *T) FailNow() {
- t.dt = time.Now().Sub(t.start)
- t.Fail()
- t.ch <- t
+func (c *common) FailNow() {
+ c.duration = time.Now().Sub(c.start)
+ c.Fail()
+ c.signal <- c.self
runtime.Goexit()
}
// log generates the output. It's always at the same stack depth.
-func (t *T) log(s string) { t.errors += decorate(s, true) }
+func (c *common) log(s string) {
+ c.output = append(c.output, decorate(s, true)...)
+}
-// Log formats its arguments using default formatting, analogous to Print(),
+// Log formats its arguments using default formatting, analogous to Println(),
// and records the text in the error log.
-func (t *T) Log(args ...interface{}) { t.log(fmt.Sprintln(args...)) }
+func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
// Logf formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
-func (t *T) Logf(format string, args ...interface{}) { t.log(fmt.Sprintf(format, args...)) }
+func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log() followed by Fail().
-func (t *T) Error(args ...interface{}) {
- t.log(fmt.Sprintln(args...))
- t.Fail()
+func (c *common) Error(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.Fail()
}
// Errorf is equivalent to Logf() followed by Fail().
-func (t *T) Errorf(format string, args ...interface{}) {
- t.log(fmt.Sprintf(format, args...))
- t.Fail()
+func (c *common) Errorf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.Fail()
}
// Fatal is equivalent to Log() followed by FailNow().
-func (t *T) Fatal(args ...interface{}) {
- t.log(fmt.Sprintln(args...))
- t.FailNow()
+func (c *common) Fatal(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.FailNow()
}
// Fatalf is equivalent to Logf() followed by FailNow().
-func (t *T) Fatalf(format string, args ...interface{}) {
- t.log(fmt.Sprintf(format, args...))
- t.FailNow()
+func (c *common) Fatalf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.FailNow()
}
// Parallel signals that this test is to be run in parallel with (and only with)
// other parallel tests in this CPU group.
func (t *T) Parallel() {
- t.ch <- nil // Release main testing loop
- <-t.startParallel // Wait for serial tests to finish
+ t.signal <- (*T)(nil) // Release main testing loop
+ <-t.startParallel // Wait for serial tests to finish
}
// An internal type but exported because it is cross-package; part of the implementation
@@ -187,8 +196,8 @@ type InternalTest struct {
func tRunner(t *T, test *InternalTest) {
t.start = time.Now()
test.F(t)
- t.dt = time.Now().Sub(t.start)
- t.ch <- t
+ t.duration = time.Now().Sub(t.start)
+ t.signal <- t
}
// An internal function but exported because it is cross-package; part of the implementation
@@ -211,13 +220,13 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
after()
}
-func report(t *T) {
- tstr := fmt.Sprintf("(%.2f seconds)", t.dt.Seconds())
+func (t *T) report() {
+ tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
format := "--- %s: %s %s\n%s"
if t.failed {
- fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
+ fmt.Printf(format, "FAIL", t.name, tstr, t.output)
} else if *chatty {
- fmt.Printf(format, "PASS", t.name, tstr, t.errors)
+ fmt.Printf(format, "PASS", t.name, tstr, t.output)
}
}
@@ -227,9 +236,14 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
return
}
- ch := make(chan *T)
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
+ // We build a new channel tree for each run of the loop.
+ // collector merges in one channel all the upstream signals from parallel tests.
+ // If all tests pump to the same channel, a bug can occur where a test
+ // kicks off a goroutine that Fails, yet the test still delivers a completion signal,
+ // which skews the counting.
+ var collector = make(chan interface{})
numParallel := 0
startParallel := make(chan bool)
@@ -247,17 +261,27 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
if procs != 1 {
testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
}
- t := &T{ch: ch, name: testName, startParallel: startParallel}
+ t := &T{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ name: testName,
+ startParallel: startParallel,
+ }
+ t.self = t
if *chatty {
fmt.Printf("=== RUN %s\n", t.name)
}
go tRunner(t, &tests[i])
- out := <-t.ch
+ out := (<-t.signal).(*T)
if out == nil { // Parallel run.
+ go func() {
+ collector <- <-t.signal
+ }()
numParallel++
continue
}
- report(t)
+ t.report()
ok = ok && !out.failed
}
@@ -269,8 +293,8 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
numParallel--
continue
}
- t := <-ch
- report(t)
+ t := (<-collector).(*T)
+ t.report()
ok = ok && !t.failed
running--
}
diff --git a/libgo/go/testing/wrapper.go b/libgo/go/testing/wrapper.go
new file mode 100644
index 0000000..2bef9df
--- /dev/null
+++ b/libgo/go/testing/wrapper.go
@@ -0,0 +1,105 @@
+// 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.
+
+// This file contains wrappers so t.Errorf etc. have documentation.
+// TODO: delete when godoc shows exported methods for unexported embedded fields.
+// TODO: need to change the argument to runtime.Caller in testing.go from 4 to 3 at that point.
+
+package testing
+
+// Fail marks the function as having failed but continues execution.
+func (b *B) Fail() {
+ b.common.Fail()
+}
+
+// Failed returns whether the function has failed.
+func (b *B) Failed() bool {
+ return b.common.Failed()
+}
+
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (b *B) FailNow() {
+ b.common.FailNow()
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
+// and records the text in the error log.
+func (b *B) Log(args ...interface{}) {
+ b.common.Log(args...)
+}
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (b *B) Logf(format string, args ...interface{}) {
+ b.common.Logf(format, args...)
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (b *B) Error(args ...interface{}) {
+ b.common.Error(args...)
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (b *B) Errorf(format string, args ...interface{}) {
+ b.common.Errorf(format, args...)
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (b *B) Fatal(args ...interface{}) {
+ b.common.Fatal(args...)
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (b *B) Fatalf(format string, args ...interface{}) {
+ b.common.Fatalf(format, args...)
+}
+
+// Fail marks the function as having failed but continues execution.
+func (t *T) Fail() {
+ t.common.Fail()
+}
+
+// Failed returns whether the function has failed.
+func (t *T) Failed() bool {
+ return t.common.Failed()
+}
+
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (t *T) FailNow() {
+ t.common.FailNow()
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
+// and records the text in the error log.
+func (t *T) Log(args ...interface{}) {
+ t.common.Log(args...)
+}
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (t *T) Logf(format string, args ...interface{}) {
+ t.common.Logf(format, args...)
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (t *T) Error(args ...interface{}) {
+ t.common.Error(args...)
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (t *T) Errorf(format string, args ...interface{}) {
+ t.common.Errorf(format, args...)
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (t *T) Fatal(args ...interface{}) {
+ t.common.Fatal(args...)
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (t *T) Fatalf(format string, args ...interface{}) {
+ t.common.Fatalf(format, args...)
+}
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index b74bc3b..acb88af 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -107,7 +107,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
vars: []variable{{"$", value}},
}
if t.Tree == nil || t.Root == nil {
- state.errorf("must be parsed before execution")
+ state.errorf("%q is an incomplete or empty template", t.name)
}
state.walk(value, t.Root)
return
@@ -497,7 +497,13 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node,
// validateType guarantees that the value is valid and assignable to the type.
func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
if !value.IsValid() {
- s.errorf("invalid value; expected %s", typ)
+ switch typ.Kind() {
+ case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Map, reflect.Slice, reflect.Func:
+ // An untyped nil interface{}. Accept as a proper nil value.
+ value = reflect.Zero(typ)
+ default:
+ s.errorf("invalid value; expected %s", typ)
+ }
}
if !value.Type().AssignableTo(typ) {
// Does one dereference or indirection work? We could do more, as we
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index cf3c415..e33988b 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -157,6 +157,10 @@ func (t *T) Method2(a uint16, b string) string {
return fmt.Sprintf("Method2: %d %s", a, b)
}
+func (t *T) Method3(v interface{}) string {
+ return fmt.Sprintf("Method3: %v", v)
+}
+
func (t *T) MAdd(a int, b []int) []int {
v := make([]int, len(b))
for i, x := range b {
@@ -293,6 +297,7 @@ var execTests = []execTest{
{".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
{".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
{".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
+ {".Method3(nil)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
{"method on chained var",
"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
@@ -322,6 +327,8 @@ var execTests = []execTest{
{"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
{"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
{"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if map unset", "{{if .MXI.none}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if map not unset", "{{if not .MXI.none}}ZERO{{else}}NON-ZERO{{end}}", "ZERO", tVal, true},
{"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
{"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 55ae5f7..56a7414 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
package time
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index e580996..33d557f 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -7,6 +7,8 @@
// The calendrical calculations always assume a Gregorian calendar.
package time
+import "errors"
+
// A Time represents an instant in time with nanosecond precision.
//
// Programs using times should typically store and pass them as values,
@@ -564,6 +566,20 @@ func (t Time) Sub(u Time) Duration {
return Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
}
+// AddDate returns the time corresponding to adding the
+// given number of years, months, and days to t.
+// For example, AddDate(-1, 2, 3) applied to January 1, 2011
+// returns March 4, 2010.
+//
+// AddDate normalizes its result in the same way that Date does,
+// so, for example, adding one month to October 31 yields
+// December 1, the normalized form for November 31.
+func (t Time) AddDate(years int, months int, days int) Time {
+ year, month, day := t.Date()
+ hour, min, sec := t.Clock()
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc)
+}
+
const (
secondsPerMinute = 60
secondsPerHour = 60 * 60
@@ -751,11 +767,11 @@ func (t Time) GobEncode() ([]byte, error) {
} else {
_, offset := t.Zone()
if offset%60 != 0 {
- return nil, gobError("Time.GobEncode: zone offset has fractional minute")
+ return nil, errors.New("Time.GobEncode: zone offset has fractional minute")
}
offset /= 60
if offset < -32768 || offset == -1 || offset > 32767 {
- return nil, gobError("Time.GobEncode: unexpected zone offset")
+ return nil, errors.New("Time.GobEncode: unexpected zone offset")
}
offsetMin = int16(offset)
}
@@ -784,15 +800,15 @@ func (t Time) GobEncode() ([]byte, error) {
// GobDecode implements the gob.GobDecoder interface.
func (t *Time) GobDecode(buf []byte) error {
if len(buf) == 0 {
- return gobError("Time.GobDecode: no data")
+ return errors.New("Time.GobDecode: no data")
}
if buf[0] != timeGobVersion {
- return gobError("Time.GobDecode: unsupported version")
+ return errors.New("Time.GobDecode: unsupported version")
}
if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
- return gobError("Time.GobDecode: invalid length")
+ return errors.New("Time.GobDecode: invalid length")
}
buf = buf[1:]
@@ -816,6 +832,52 @@ func (t *Time) GobDecode(buf []byte) error {
return nil
}
+// MarshalJSON implements the json.Marshaler interface.
+// Time is formatted as RFC3339.
+func (t Time) MarshalJSON() ([]byte, error) {
+ yearInt := t.Year()
+ if yearInt < 0 || yearInt > 9999 {
+ return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
+ }
+
+ // We need a four-digit year, but Format produces variable-width years.
+ year := itoa(yearInt)
+ year = "0000"[:4-len(year)] + year
+
+ var formattedTime string
+ if t.nsec == 0 {
+ // RFC3339, no fractional second
+ formattedTime = t.Format("-01-02T15:04:05Z07:00")
+ } else {
+ // RFC3339 with fractional second
+ formattedTime = t.Format("-01-02T15:04:05.000000000Z07:00")
+
+ // Trim trailing zeroes from fractional second.
+ const nanoEnd = 24 // Index of last digit of fractional second
+ var i int
+ for i = nanoEnd; formattedTime[i] == '0'; i-- {
+ // Seek backwards until first significant digit is found.
+ }
+
+ formattedTime = formattedTime[:i+1] + formattedTime[nanoEnd+1:]
+ }
+
+ buf := make([]byte, 0, 1+len(year)+len(formattedTime)+1)
+ buf = append(buf, '"')
+ buf = append(buf, year...)
+ buf = append(buf, formattedTime...)
+ buf = append(buf, '"')
+ return buf, nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+// Time is expected in RFC3339 format.
+func (t *Time) UnmarshalJSON(data []byte) (err error) {
+ *t, err = Parse("\""+RFC3339+"\"", string(data))
+ // Fractional seconds are handled implicitly by Parse.
+ return
+}
+
// Unix returns the local Time corresponding to the given Unix time,
// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
// It is valid to pass nsec outside the range [0, 999999999].
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 2a22e7b..484ae42 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -7,6 +7,7 @@ package time_test
import (
"bytes"
"encoding/gob"
+ "encoding/json"
"strconv"
"strings"
"testing"
@@ -634,6 +635,32 @@ func TestDate(t *testing.T) {
}
}
+// Several ways of getting from
+// Fri Nov 18 7:56:35 PST 2011
+// to
+// Thu Mar 19 7:56:35 PST 2016
+var addDateTests = []struct {
+ years, months, days int
+}{
+ {4, 4, 1},
+ {3, 16, 1},
+ {3, 15, 30},
+ {5, -6, -18 - 30 - 12},
+}
+
+func TestAddDate(t *testing.T) {
+ t0 := Date(2011, 11, 18, 7, 56, 35, 0, UTC)
+ t1 := Date(2016, 3, 19, 7, 56, 35, 0, UTC)
+ for _, at := range addDateTests {
+ time := t0.AddDate(at.years, at.months, at.days)
+ if !time.Equal(t1) {
+ t.Errorf("AddDate(%d, %d, %d) = %v, want %v",
+ at.years, at.months, at.days,
+ time, t1)
+ }
+ }
+}
+
var daysInTests = []struct {
year, month, di int
}{
@@ -668,6 +695,12 @@ func TestAddToExactSecond(t *testing.T) {
}
}
+func equalTimeAndZone(a, b Time) bool {
+ aname, aoffset := a.Zone()
+ bname, boffset := b.Zone()
+ return a.Equal(b) && aoffset == boffset && aname == bname
+}
+
var gobTests = []Time{
Date(0, 1, 2, 3, 4, 5, 6, UTC),
Date(7, 8, 9, 10, 11, 12, 13, FixedZone("", 0)),
@@ -687,12 +720,8 @@ func TestTimeGob(t *testing.T) {
t.Errorf("%v gob Encode error = %q, want nil", tt, err)
} else if err := dec.Decode(&gobtt); err != nil {
t.Errorf("%v gob Decode error = %q, want nil", tt, err)
- } else {
- gobname, goboffset := gobtt.Zone()
- name, offset := tt.Zone()
- if !gobtt.Equal(tt) || goboffset != offset || gobname != name {
- t.Errorf("Decoded time = %v, want %v", gobtt, tt)
- }
+ } else if !equalTimeAndZone(gobtt, tt) {
+ t.Errorf("Decoded time = %v, want %v", gobtt, tt)
}
b.Reset()
}
@@ -736,6 +765,57 @@ func TestNotGobEncodableTime(t *testing.T) {
}
}
+var jsonTests = []struct {
+ time Time
+ json string
+}{
+ {Date(9999, 4, 12, 23, 20, 50, .52*1e9, UTC), `"9999-04-12T23:20:50.52Z"`},
+ {Date(1996, 12, 19, 16, 39, 57, 0, Local), `"1996-12-19T16:39:57-08:00"`},
+ {Date(0, 1, 1, 0, 0, 0, 1, FixedZone("", 1*60)), `"0000-01-01T00:00:00.000000001+00:01"`},
+}
+
+func TestTimeJSON(t *testing.T) {
+ for _, tt := range jsonTests {
+ var jsonTime Time
+
+ if jsonBytes, err := json.Marshal(tt.time); err != nil {
+ t.Errorf("%v json.Marshal error = %v, want nil", tt.time, err)
+ } else if string(jsonBytes) != tt.json {
+ t.Errorf("%v JSON = %q, want %q", tt.time, string(jsonBytes), tt.json)
+ } else if err = json.Unmarshal(jsonBytes, &jsonTime); err != nil {
+ t.Errorf("%v json.Unmarshal error = %v, want nil", tt.time, err)
+ } else if !equalTimeAndZone(jsonTime, tt.time) {
+ t.Errorf("Unmarshaled time = %v, want %v", jsonTime, tt.time)
+ }
+ }
+}
+
+func TestInvalidTimeJSON(t *testing.T) {
+ var tt Time
+ err := json.Unmarshal([]byte(`{"now is the time":"buddy"}`), &tt)
+ _, isParseErr := err.(*ParseError)
+ if !isParseErr {
+ t.Errorf("expected *time.ParseError unmarshaling JSON, got %v", err)
+ }
+}
+
+var notJSONEncodableTimes = []struct {
+ time Time
+ want string
+}{
+ {Date(10000, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+ {Date(-1, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+}
+
+func TestNotJSONEncodableTime(t *testing.T) {
+ for _, tt := range notJSONEncodableTimes {
+ _, err := tt.time.MarshalJSON()
+ if err == nil || err.Error() != tt.want {
+ t.Errorf("%v MarshalJSON error = %v, want %v", tt.time, err, tt.want)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
Now()
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 83d5b98..540b653 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.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.
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/libgo/go/websocket/server.go b/libgo/go/websocket/server.go
index 8320b03..63f48e2 100644
--- a/libgo/go/websocket/server.go
+++ b/libgo/go/websocket/server.go
@@ -74,7 +74,7 @@ A trivial example server:
http.Handle("/echo", websocket.Handler(EchoServer));
err := http.ListenAndServe(":12345", nil);
if err != nil {
- panic("ListenAndServe: " + err.String())
+ panic("ListenAndServe: " + err.Error())
}
}
*/