summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-03-06 17:57:23 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-03-06 17:57:23 +0000
commit593f74bbab63d34c7060918088bcbad686c31c66 (patch)
tree4ce83ca433796a728e9fdd00af105bce158532b5 /libgo
parent46402cbe0ba3ea92be9642cf18eedaefe57a414c (diff)
downloadgcc-593f74bbab63d34c7060918088bcbad686c31c66.tar.gz
libgo: Update to weekly.2012-03-04 release.
From-SVN: r185010
Diffstat (limited to 'libgo')
-rw-r--r--libgo/MERGE2
-rw-r--r--libgo/Makefile.am13
-rw-r--r--libgo/Makefile.in16
-rw-r--r--libgo/go/archive/zip/reader.go141
-rw-r--r--libgo/go/archive/zip/reader_test.go2
-rw-r--r--libgo/go/archive/zip/struct.go10
-rw-r--r--libgo/go/archive/zip/writer.go155
-rw-r--r--libgo/go/bufio/bufio.go1
-rw-r--r--libgo/go/crypto/ecdsa/ecdsa.go2
-rw-r--r--libgo/go/crypto/tls/root_darwin.go32
-rw-r--r--libgo/go/crypto/x509/verify.go4
-rw-r--r--libgo/go/crypto/x509/x509.go6
-rw-r--r--libgo/go/encoding/binary/binary.go8
-rw-r--r--libgo/go/encoding/gob/codec_test.go5
-rw-r--r--libgo/go/encoding/gob/debug.go5
-rw-r--r--libgo/go/encoding/gob/decode.go23
-rw-r--r--libgo/go/encoding/gob/dump.go1
-rw-r--r--libgo/go/encoding/gob/encoder_test.go2
-rw-r--r--libgo/go/encoding/json/decode_test.go10
-rw-r--r--libgo/go/encoding/json/encode.go18
-rw-r--r--libgo/go/encoding/json/encode_test.go19
-rw-r--r--libgo/go/encoding/json/indent.go13
-rw-r--r--libgo/go/encoding/xml/marshal_test.go16
-rw-r--r--libgo/go/exp/gotype/doc.go2
-rw-r--r--libgo/go/exp/gotype/gotype.go8
-rw-r--r--libgo/go/exp/html/node.go2
-rw-r--r--libgo/go/exp/norm/forminfo.go6
-rw-r--r--libgo/go/exp/proxy/per_host.go2
-rw-r--r--libgo/go/exp/types/gcimporter.go12
-rw-r--r--libgo/go/exp/types/types.go4
-rw-r--r--libgo/go/go/ast/print.go2
-rw-r--r--libgo/go/go/build/build.go942
-rw-r--r--libgo/go/go/build/build_test.go110
-rw-r--r--libgo/go/go/build/cgotest/cgotest.go19
-rw-r--r--libgo/go/go/build/cmdtest/main.go12
-rw-r--r--libgo/go/go/build/dir.go705
-rw-r--r--libgo/go/go/build/doc.go109
-rw-r--r--libgo/go/go/build/path.go182
-rw-r--r--libgo/go/go/build/pkgtest/pkgtest.go13
-rw-r--r--libgo/go/go/build/pkgtest/sqrt_386_test.go1
-rw-r--r--libgo/go/go/build/pkgtest/sqrt_amd64_test.go1
-rw-r--r--libgo/go/go/build/pkgtest/sqrt_arm_test.go1
-rw-r--r--libgo/go/go/build/pkgtest/sqrt_test.go9
-rw-r--r--libgo/go/go/build/pkgtest/xsqrt_test.go9
-rw-r--r--libgo/go/go/build/syslist_test.go2
-rw-r--r--libgo/go/go/build/testdata/other/file/file.go5
-rw-r--r--libgo/go/go/build/testdata/other/main.go11
-rw-r--r--libgo/go/go/doc/reader.go20
-rw-r--r--libgo/go/go/parser/parser.go17
-rw-r--r--libgo/go/go/parser/parser_test.go46
-rw-r--r--libgo/go/go/printer/nodes.go361
-rw-r--r--libgo/go/go/printer/printer.go75
-rw-r--r--libgo/go/go/printer/printer_test.go5
-rw-r--r--libgo/go/go/printer/testdata/comments.golden85
-rw-r--r--libgo/go/go/printer/testdata/comments.input85
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden10
-rw-r--r--libgo/go/go/printer/testdata/declarations.input6
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden22
-rw-r--r--libgo/go/go/printer/testdata/expressions.input22
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw22
-rw-r--r--libgo/go/go/printer/testdata/parser.go2
-rw-r--r--libgo/go/go/printer/testdata/statements.golden76
-rw-r--r--libgo/go/go/printer/testdata/statements.input76
-rw-r--r--libgo/go/html/template/doc.go2
-rw-r--r--libgo/go/html/template/escape.go2
-rw-r--r--libgo/go/html/template/escape_test.go11
-rw-r--r--libgo/go/html/template/html.go2
-rw-r--r--libgo/go/io/io.go7
-rw-r--r--libgo/go/io/pipe.go4
-rw-r--r--libgo/go/math/const.go8
-rw-r--r--libgo/go/net/dial.go2
-rw-r--r--libgo/go/net/dial_test.go81
-rw-r--r--libgo/go/net/dialgoogle_test.go15
-rw-r--r--libgo/go/net/http/cgi/child.go1
-rw-r--r--libgo/go/net/http/cgi/host_test.go1
-rw-r--r--libgo/go/net/http/cgi/matryoshka_test.go21
-rw-r--r--libgo/go/net/http/fs_test.go10
-rw-r--r--libgo/go/net/http/httptest/server.go36
-rw-r--r--libgo/go/net/http/httputil/dump.go16
-rw-r--r--libgo/go/net/http/httputil/dump_test.go12
-rw-r--r--libgo/go/net/http/httputil/persist.go2
-rw-r--r--libgo/go/net/http/lex.go8
-rw-r--r--libgo/go/net/http/sniff_test.go3
-rw-r--r--libgo/go/net/http/status.go2
-rw-r--r--libgo/go/net/http/transfer.go2
-rw-r--r--libgo/go/net/http/transport.go6
-rw-r--r--libgo/go/net/http/transport_test.go31
-rw-r--r--libgo/go/net/http/triv.go1
-rw-r--r--libgo/go/net/interface.go77
-rw-r--r--libgo/go/net/interface_test.go45
-rw-r--r--libgo/go/net/lookup_plan9.go2
-rw-r--r--libgo/go/net/lookup_test.go39
-rw-r--r--libgo/go/net/mac.go84
-rw-r--r--libgo/go/net/mac_test.go54
-rw-r--r--libgo/go/net/net_test.go118
-rw-r--r--libgo/go/net/rpc/client.go2
-rw-r--r--libgo/go/net/rpc/server.go39
-rw-r--r--libgo/go/net/sockoptip_netbsd.go39
-rw-r--r--libgo/go/net/timeout_test.go2
-rw-r--r--libgo/go/net/udp_test.go10
-rw-r--r--libgo/go/os/doc.go72
-rw-r--r--libgo/go/os/exec.go2
-rw-r--r--libgo/go/os/exec_plan9.go44
-rw-r--r--libgo/go/os/exec_posix.go41
-rw-r--r--libgo/go/os/exec_unix.go16
-rw-r--r--libgo/go/os/exec_windows.go40
-rw-r--r--libgo/go/os/file.go2
-rw-r--r--libgo/go/os/os_test.go37
-rw-r--r--libgo/go/path/filepath/path.go1
-rw-r--r--libgo/go/path/filepath/path_plan9.go2
-rw-r--r--libgo/go/path/filepath/path_unix.go2
-rw-r--r--libgo/go/path/filepath/path_windows.go3
-rw-r--r--libgo/go/reflect/all_test.go22
-rw-r--r--libgo/go/reflect/deepequal.go10
-rw-r--r--libgo/go/reflect/type.go2
-rw-r--r--libgo/go/reflect/value.go16
-rw-r--r--libgo/go/runtime/pprof/pprof.go6
-rw-r--r--libgo/go/runtime/pprof/pprof_test.go13
-rw-r--r--libgo/go/strconv/extfloat.go2
-rw-r--r--libgo/go/strings/example_test.go1
-rw-r--r--libgo/go/sync/example_test.go20
-rw-r--r--libgo/go/sync/waitgroup.go15
-rw-r--r--libgo/go/syscall/socket.go12
-rw-r--r--libgo/go/testing/example.go10
-rw-r--r--libgo/go/testing/testing.go4
-rw-r--r--libgo/go/text/template/doc.go23
-rw-r--r--libgo/go/text/template/exec.go5
-rw-r--r--libgo/go/text/template/exec_test.go29
-rw-r--r--libgo/go/text/template/funcs.go48
-rw-r--r--libgo/go/text/template/multi_test.go6
-rw-r--r--libgo/go/text/template/parse/parse.go2
-rw-r--r--libgo/go/text/template/parse/parse_test.go3
-rw-r--r--libgo/go/text/template/template.go20
-rw-r--r--libgo/go/time/format.go8
-rw-r--r--libgo/go/time/sleep_test.go7
-rw-r--r--libgo/go/time/time.go15
-rw-r--r--libgo/runtime/go-main.c2
-rw-r--r--libgo/runtime/lock_futex.c12
-rw-r--r--libgo/runtime/lock_sema.c11
-rw-r--r--libgo/runtime/malloc.goc11
-rw-r--r--libgo/runtime/mgc0.c8
-rw-r--r--libgo/runtime/mheap.c2
-rw-r--r--libgo/runtime/proc.c20
-rw-r--r--libgo/runtime/runtime.c15
-rw-r--r--libgo/runtime/runtime.h15
-rw-r--r--libgo/runtime/thread-linux.c10
-rw-r--r--libgo/runtime/thread.c33
147 files changed, 3079 insertions, 2021 deletions
diff --git a/libgo/MERGE b/libgo/MERGE
index 9605a8a9040..17d01ce7265 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-96bd78e7d35e
+f4470a54e6db
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index eb764df0eab..d43f0542938 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -658,10 +658,17 @@ go_net_sock_file = go/net/sock_linux.go
go_net_sockopt_file = go/net/sockopt_linux.go
go_net_sockoptip_file = go/net/sockoptip_linux.go
else
+if LIBGO_IS_FREEBSD
go_net_cgo_file = go/net/cgo_bsd.go
go_net_sock_file = go/net/sock_bsd.go
go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_freebsd.go
+else
+go_net_cgo_file = go/net/cgo_bsd.go
+go_net_sock_file = go/net/sock_bsd.go
+go_net_sockopt_file = go/net/sockopt_bsd.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_netbsd.go
+endif
endif
endif
endif
@@ -704,6 +711,7 @@ go_net_files = \
go/net/ipsock.go \
go/net/ipsock_posix.go \
go/net/lookup_unix.go \
+ go/net/mac.go \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
@@ -1126,8 +1134,7 @@ go_go_ast_files = \
go/go/ast/walk.go
go_go_build_files = \
go/go/build/build.go \
- go/go/build/dir.go \
- go/go/build/path.go \
+ go/go/build/doc.go \
syslist.go
go_go_doc_files = \
go/go/doc/comment.go \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 4604e560c9b..418c7876a31 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -1012,19 +1012,23 @@ go_mime_files = \
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
+@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
+@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_file = go/net/cgo_linux.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_file = go/net/cgo_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_cgo_file = go/net/cgo_linux.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
+@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
+@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
+@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
+@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockopt_file = go/net/sockopt_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go
-@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go
+@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_netbsd.go
+@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_freebsd.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockoptip_file = go/net/sockoptip_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go
@@ -1055,6 +1059,7 @@ go_net_files = \
go/net/ipsock.go \
go/net/ipsock_posix.go \
go/net/lookup_unix.go \
+ go/net/mac.go \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
@@ -1467,8 +1472,7 @@ go_go_ast_files = \
go_go_build_files = \
go/go/build/build.go \
- go/go/build/dir.go \
- go/go/build/path.go \
+ go/go/build/doc.go \
syslist.go
go_go_doc_files = \
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index c3009869b60..f3826dcc48d 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -169,48 +169,21 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
func (r *checksumReader) Close() error { return r.rc.Close() }
-func readFileHeader(f *File, r io.Reader) error {
- var b [fileHeaderLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
- return err
- }
- c := binary.LittleEndian
- if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
- return ErrFormat
- }
- f.ReaderVersion = c.Uint16(b[4:6])
- f.Flags = c.Uint16(b[6:8])
- f.Method = c.Uint16(b[8:10])
- f.ModifiedTime = c.Uint16(b[10:12])
- f.ModifiedDate = c.Uint16(b[12:14])
- f.CRC32 = c.Uint32(b[14:18])
- f.CompressedSize = c.Uint32(b[18:22])
- f.UncompressedSize = c.Uint32(b[22:26])
- filenameLen := int(c.Uint16(b[26:28]))
- extraLen := int(c.Uint16(b[28:30]))
- d := make([]byte, filenameLen+extraLen)
- if _, err := io.ReadFull(r, d); err != nil {
- return err
- }
- f.Name = string(d[:filenameLen])
- f.Extra = d[filenameLen:]
- return nil
-}
-
// findBodyOffset does the minimum work to verify the file has a header
// and returns the file body offset.
func (f *File) findBodyOffset() (int64, error) {
r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
- var b [fileHeaderLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
+ var buf [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
return 0, err
}
- c := binary.LittleEndian
- if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
+ b := readBuf(buf[:])
+ if sig := b.uint32(); sig != fileHeaderSignature {
return 0, ErrFormat
}
- filenameLen := int(c.Uint16(b[26:28]))
- extraLen := int(c.Uint16(b[28:30]))
+ b = b[22:] // skip over most of the header
+ filenameLen := int(b.uint16())
+ extraLen := int(b.uint16())
return int64(fileHeaderLen + filenameLen + extraLen), nil
}
@@ -218,30 +191,29 @@ func (f *File) findBodyOffset() (int64, error) {
// It returns io.ErrUnexpectedEOF if it cannot read a complete header,
// and ErrFormat if it doesn't find a valid header signature.
func readDirectoryHeader(f *File, r io.Reader) error {
- var b [directoryHeaderLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
+ var buf [directoryHeaderLen]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
return err
}
- c := binary.LittleEndian
- if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
+ b := readBuf(buf[:])
+ if sig := b.uint32(); sig != directoryHeaderSignature {
return ErrFormat
}
- f.CreatorVersion = c.Uint16(b[4:6])
- f.ReaderVersion = c.Uint16(b[6:8])
- f.Flags = c.Uint16(b[8:10])
- f.Method = c.Uint16(b[10:12])
- f.ModifiedTime = c.Uint16(b[12:14])
- f.ModifiedDate = c.Uint16(b[14:16])
- f.CRC32 = c.Uint32(b[16:20])
- f.CompressedSize = c.Uint32(b[20:24])
- f.UncompressedSize = c.Uint32(b[24:28])
- filenameLen := int(c.Uint16(b[28:30]))
- extraLen := int(c.Uint16(b[30:32]))
- commentLen := int(c.Uint16(b[32:34]))
- // startDiskNumber := c.Uint16(b[34:36]) // Unused
- // internalAttributes := c.Uint16(b[36:38]) // Unused
- f.ExternalAttrs = c.Uint32(b[38:42])
- f.headerOffset = int64(c.Uint32(b[42:46]))
+ f.CreatorVersion = b.uint16()
+ f.ReaderVersion = b.uint16()
+ f.Flags = b.uint16()
+ f.Method = b.uint16()
+ f.ModifiedTime = b.uint16()
+ f.ModifiedDate = b.uint16()
+ f.CRC32 = b.uint32()
+ f.CompressedSize = b.uint32()
+ f.UncompressedSize = b.uint32()
+ filenameLen := int(b.uint16())
+ extraLen := int(b.uint16())
+ commentLen := int(b.uint16())
+ b = b[4:] // skipped start disk number and internal attributes (2x uint16)
+ f.ExternalAttrs = b.uint32()
+ f.headerOffset = int64(b.uint32())
d := make([]byte, filenameLen+extraLen+commentLen)
if _, err := io.ReadFull(r, d); err != nil {
return err
@@ -253,30 +225,30 @@ func readDirectoryHeader(f *File, r io.Reader) error {
}
func readDataDescriptor(r io.Reader, f *File) error {
- var b [dataDescriptorLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
+ var buf [dataDescriptorLen]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
return err
}
- c := binary.LittleEndian
- f.CRC32 = c.Uint32(b[:4])
- f.CompressedSize = c.Uint32(b[4:8])
- f.UncompressedSize = c.Uint32(b[8:12])
+ b := readBuf(buf[:])
+ f.CRC32 = b.uint32()
+ f.CompressedSize = b.uint32()
+ f.UncompressedSize = b.uint32()
return nil
}
func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
// look for directoryEndSignature in the last 1k, then in the last 65k
- var b []byte
+ var buf []byte
for i, bLen := range []int64{1024, 65 * 1024} {
if bLen > size {
bLen = size
}
- b = make([]byte, int(bLen))
- if _, err := r.ReadAt(b, size-bLen); err != nil && err != io.EOF {
+ buf = make([]byte, int(bLen))
+ if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
return nil, err
}
- if p := findSignatureInBlock(b); p >= 0 {
- b = b[p:]
+ if p := findSignatureInBlock(buf); p >= 0 {
+ buf = buf[p:]
break
}
if i == 1 || bLen == size {
@@ -285,16 +257,21 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
}
// read header into struct
- c := binary.LittleEndian
- d := new(directoryEnd)
- d.diskNbr = c.Uint16(b[4:6])
- d.dirDiskNbr = c.Uint16(b[6:8])
- d.dirRecordsThisDisk = c.Uint16(b[8:10])
- d.directoryRecords = c.Uint16(b[10:12])
- d.directorySize = c.Uint32(b[12:16])
- d.directoryOffset = c.Uint32(b[16:20])
- d.commentLen = c.Uint16(b[20:22])
- d.comment = string(b[22 : 22+int(d.commentLen)])
+ b := readBuf(buf[4:]) // skip signature
+ d := &directoryEnd{
+ diskNbr: b.uint16(),
+ dirDiskNbr: b.uint16(),
+ dirRecordsThisDisk: b.uint16(),
+ directoryRecords: b.uint16(),
+ directorySize: b.uint32(),
+ directoryOffset: b.uint32(),
+ commentLen: b.uint16(),
+ }
+ l := int(d.commentLen)
+ if l > len(b) {
+ return nil, errors.New("zip: invalid comment length")
+ }
+ d.comment = string(b[:l])
return d, nil
}
@@ -311,3 +288,17 @@ func findSignatureInBlock(b []byte) int {
}
return -1
}
+
+type readBuf []byte
+
+func (b *readBuf) uint16() uint16 {
+ v := binary.LittleEndian.Uint16(*b)
+ *b = (*b)[2:]
+ return v
+}
+
+func (b *readBuf) uint32() uint32 {
+ v := binary.LittleEndian.Uint32(*b)
+ *b = (*b)[4:]
+ return v
+}
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index ea9e0020db4..066a61580c5 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -165,7 +165,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
}
if len(z.File) != len(zt.File) {
- t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+ t.Fatalf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
}
// test read of each file
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index 35dcec6468b..fdbd16da048 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -100,16 +100,6 @@ type directoryEnd struct {
comment string
}
-func recoverError(errp *error) {
- if e := recover(); e != nil {
- if err, ok := e.(error); ok {
- *errp = err
- return
- }
- panic(e)
- }
-}
-
// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
// The resolution is 2s.
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index c591aed5ced..b2cc55bc93b 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -37,10 +37,10 @@ func NewWriter(w io.Writer) *Writer {
// Close finishes writing the zip file by writing the central directory.
// It does not (and can not) close the underlying writer.
-func (w *Writer) Close() (err error) {
+func (w *Writer) Close() error {
if w.last != nil && !w.last.closed {
- if err = w.last.close(); err != nil {
- return
+ if err := w.last.close(); err != nil {
+ return err
}
w.last = nil
}
@@ -49,43 +49,55 @@ func (w *Writer) Close() (err error) {
}
w.closed = true
- defer recoverError(&err)
-
// write central directory
start := w.cw.count
for _, h := range w.dir {
- write(w.cw, uint32(directoryHeaderSignature))
- write(w.cw, h.CreatorVersion)
- write(w.cw, h.ReaderVersion)
- write(w.cw, h.Flags)
- write(w.cw, h.Method)
- write(w.cw, h.ModifiedTime)
- write(w.cw, h.ModifiedDate)
- write(w.cw, h.CRC32)
- write(w.cw, h.CompressedSize)
- write(w.cw, h.UncompressedSize)
- write(w.cw, uint16(len(h.Name)))
- write(w.cw, uint16(len(h.Extra)))
- write(w.cw, uint16(len(h.Comment)))
- write(w.cw, uint16(0)) // disk number start
- write(w.cw, uint16(0)) // internal file attributes
- write(w.cw, h.ExternalAttrs)
- write(w.cw, h.offset)
- writeBytes(w.cw, []byte(h.Name))
- writeBytes(w.cw, h.Extra)
- writeBytes(w.cw, []byte(h.Comment))
+ var buf [directoryHeaderLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(directoryHeaderSignature))
+ b.uint16(h.CreatorVersion)
+ b.uint16(h.ReaderVersion)
+ b.uint16(h.Flags)
+ b.uint16(h.Method)
+ b.uint16(h.ModifiedTime)
+ b.uint16(h.ModifiedDate)
+ b.uint32(h.CRC32)
+ b.uint32(h.CompressedSize)
+ b.uint32(h.UncompressedSize)
+ b.uint16(uint16(len(h.Name)))
+ b.uint16(uint16(len(h.Extra)))
+ b.uint16(uint16(len(h.Comment)))
+ b = b[4:] // skip disk number start and internal file attr (2x uint16)
+ b.uint32(h.ExternalAttrs)
+ b.uint32(h.offset)
+ if _, err := w.cw.Write(buf[:]); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w.cw, h.Name); err != nil {
+ return err
+ }
+ if _, err := w.cw.Write(h.Extra); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w.cw, h.Comment); err != nil {
+ return err
+ }
}
end := w.cw.count
// write end record
- write(w.cw, uint32(directoryEndSignature))
- write(w.cw, uint16(0)) // disk number
- write(w.cw, uint16(0)) // disk number where directory starts
- write(w.cw, uint16(len(w.dir))) // number of entries this disk
- write(w.cw, uint16(len(w.dir))) // number of entries total
- write(w.cw, uint32(end-start)) // size of directory
- write(w.cw, uint32(start)) // start of directory
- write(w.cw, uint16(0)) // size of comment
+ var buf [directoryEndLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(directoryEndSignature))
+ b = b[4:] // skip over disk number and first disk number (2x uint16)
+ b.uint16(uint16(len(w.dir))) // number of entries this disk
+ b.uint16(uint16(len(w.dir))) // number of entries total
+ b.uint32(uint32(end - start)) // size of directory
+ b.uint32(uint32(start)) // start of directory
+ // skipped size of comment (always zero)
+ if _, err := w.cw.Write(buf[:]); err != nil {
+ return err
+ }
return w.cw.w.(*bufio.Writer).Flush()
}
@@ -152,22 +164,28 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
return fw, nil
}
-func writeHeader(w io.Writer, h *FileHeader) (err error) {
- defer recoverError(&err)
- write(w, uint32(fileHeaderSignature))
- write(w, h.ReaderVersion)
- write(w, h.Flags)
- write(w, h.Method)
- write(w, h.ModifiedTime)
- write(w, h.ModifiedDate)
- write(w, h.CRC32)
- write(w, h.CompressedSize)
- write(w, h.UncompressedSize)
- write(w, uint16(len(h.Name)))
- write(w, uint16(len(h.Extra)))
- writeBytes(w, []byte(h.Name))
- writeBytes(w, h.Extra)
- return nil
+func writeHeader(w io.Writer, h *FileHeader) error {
+ var buf [fileHeaderLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(fileHeaderSignature))
+ b.uint16(h.ReaderVersion)
+ b.uint16(h.Flags)
+ b.uint16(h.Method)
+ b.uint16(h.ModifiedTime)
+ b.uint16(h.ModifiedDate)
+ b.uint32(h.CRC32)
+ b.uint32(h.CompressedSize)
+ b.uint32(h.UncompressedSize)
+ b.uint16(uint16(len(h.Name)))
+ b.uint16(uint16(len(h.Extra)))
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, h.Name); err != nil {
+ return err
+ }
+ _, err := w.Write(h.Extra)
+ return err
}
type fileWriter struct {
@@ -188,13 +206,13 @@ func (w *fileWriter) Write(p []byte) (int, error) {
return w.rawCount.Write(p)
}
-func (w *fileWriter) close() (err error) {
+func (w *fileWriter) close() error {
if w.closed {
return errors.New("zip: file closed twice")
}
w.closed = true
- if err = w.comp.Close(); err != nil {
- return
+ if err := w.comp.Close(); err != nil {
+ return err
}
// update FileHeader
@@ -204,12 +222,13 @@ func (w *fileWriter) close() (err error) {
fh.UncompressedSize = uint32(w.rawCount.count)
// write data descriptor
- defer recoverError(&err)
- write(w.zipw, fh.CRC32)
- write(w.zipw, fh.CompressedSize)
- write(w.zipw, fh.UncompressedSize)
-
- return nil
+ var buf [dataDescriptorLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(fh.CRC32)
+ b.uint32(fh.CompressedSize)
+ b.uint32(fh.UncompressedSize)
+ _, err := w.zipw.Write(buf[:])
+ return err
}
type countWriter struct {
@@ -231,18 +250,14 @@ func (w nopCloser) Close() error {
return nil
}
-func write(w io.Writer, data interface{}) {
- if err := binary.Write(w, binary.LittleEndian, data); err != nil {
- panic(err)
- }
+type writeBuf []byte
+
+func (b *writeBuf) uint16(v uint16) {
+ binary.LittleEndian.PutUint16(*b, v)
+ *b = (*b)[2:]
}
-func writeBytes(w io.Writer, b []byte) {
- n, err := w.Write(b)
- if err != nil {
- panic(err)
- }
- if n != len(b) {
- panic(io.ErrShortWrite)
- }
+func (b *writeBuf) uint32(v uint32) {
+ binary.LittleEndian.PutUint32(*b, v)
+ *b = (*b)[4:]
}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index 6f3b1eec971..b44d0e7d167 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -23,7 +23,6 @@ var (
ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
ErrBufferFull = errors.New("bufio: buffer full")
ErrNegativeCount = errors.New("bufio: negative count")
- errInternal = errors.New("bufio: internal error")
)
// Buffered input.
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
index d2f7d8f9bb3..b28239b7862 100644
--- a/libgo/go/crypto/ecdsa/ecdsa.go
+++ b/libgo/go/crypto/ecdsa/ecdsa.go
@@ -7,7 +7,7 @@
package ecdsa
// References:
-// [NSA]: Suite B implementor's guide to FIPS 186-3,
+// [NSA]: Suite B implementer's guide to FIPS 186-3,
// http://www.nsa.gov/ia/_files/ecdsa.pdf
// [SECG]: SECG, SEC1
// http://www.secg.org/download/aid-780/sec1-v2.pdf
diff --git a/libgo/go/crypto/tls/root_darwin.go b/libgo/go/crypto/tls/root_darwin.go
index db1b18b3c07..911a9a62e3c 100644
--- a/libgo/go/crypto/tls/root_darwin.go
+++ b/libgo/go/crypto/tls/root_darwin.go
@@ -5,11 +5,9 @@
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 -Wno-deprecated-declarations
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
@@ -40,26 +38,12 @@ int FetchPEMRoots(CFDataRef *pemRoots) {
continue;
}
- // SecKeychainImportExport is deprecated in >= OS X 10.7, and has been replaced by
- // SecItemExport. If we're built on a host with a Lion SDK, this code gets conditionally
- // included in the output, also for binaries meant for 10.6.
- //
- // To make sure that we run on both Mac OS X 10.6 and 10.7 we use weak linking
- // and check whether SecItemExport is available before we attempt to call it. On
- // 10.6, this won't be the case, and we'll fall back to calling SecKeychainItemExport.
-#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
- if (SecItemExport) {
- err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
- } else
-#endif
- if (data == NULL) {
- err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
}
if (data != NULL) {
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 87b1cb7bb1c..3859dd8d488 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -135,8 +135,8 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
// Verify attempts to verify c by building one or more chains from c to a
// certificate in opts.roots, using certificates in opts.Intermediates if
-// needed. If successful, it returns one or chains where the first element of
-// the chain is c and the last element is from opts.Roots.
+// needed. If successful, it returns one or more chains where the first
+// element of the chain is c and the last element is from opts.Roots.
//
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index 3116525d33d..f5da86b54a0 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -153,7 +153,7 @@ const (
//
// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
//
-// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
+// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
//
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
//
@@ -172,9 +172,9 @@ const (
//
// RFC 5758 3.1 DSA Signature Algorithms
//
-// dsaWithSha356 OBJECT IDENTIFER ::= {
+// dsaWithSha256 OBJECT IDENTIFIER ::= {
// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
-// algorithms(4) id-dsa-with-sha2(3) 2}
+// csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
//
var (
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index b26b1bb2c93..02f090d53f3 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -29,17 +29,13 @@ type ByteOrder interface {
String() string
}
-// This is byte instead of struct{} so that it can be compared,
-// allowing, e.g., order == binary.LittleEndian.
-type unused byte
-
// LittleEndian is the little-endian implementation of ByteOrder.
var LittleEndian littleEndian
// BigEndian is the big-endian implementation of ByteOrder.
var BigEndian bigEndian
-type littleEndian unused
+type littleEndian struct{}
func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
@@ -79,7 +75,7 @@ func (littleEndian) String() string { return "LittleEndian" }
func (littleEndian) GoString() string { return "binary.LittleEndian" }
-type bigEndian unused
+type bigEndian struct{}
func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go
index d365f826345..ebcbb78ebe6 100644
--- a/libgo/go/encoding/gob/codec_test.go
+++ b/libgo/go/encoding/gob/codec_test.go
@@ -1455,11 +1455,14 @@ func TestFuzz(t *testing.T) {
func TestFuzzRegressions(t *testing.T) {
// An instance triggering a type name of length ~102 GB.
testFuzz(t, 1328492090837718000, 100, new(float32))
+ // An instance triggering a type name of 1.6 GB.
+ // Commented out because it takes 5m to run.
+ //testFuzz(t, 1330522872628565000, 100, new(int))
}
func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
- t.Logf("seed=%d n=%d\n", seed, n)
for _, e := range input {
+ t.Logf("seed=%d n=%d e=%T", seed, n, e)
rng := rand.New(rand.NewSource(seed))
for i := 0; i < n; i++ {
encFuzzDec(rng, e)
diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go
index b54ef46f52c..31d1351fc4f 100644
--- a/libgo/go/encoding/gob/debug.go
+++ b/libgo/go/encoding/gob/debug.go
@@ -3,14 +3,15 @@
// license that can be found in the LICENSE file.
// Delete the next line to include in the gob package.
-// +build gob-debug
+// +build ignore
package gob
// This file is not normally included in the gob package. Used only for debugging the package itself.
-// Add debug.go to the files listed in the Makefile to add Debug to the gob package.
// Except for reading uints, it is an implementation of a reader that is independent of
// the one implemented by Decoder.
+// To enable the Debug function, delete the +build ignore line above and do
+// go install
import (
"bytes"
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index a0bb985300f..0708a83c99a 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -392,12 +392,12 @@ func decUint8Slice(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- n := int(state.decodeUint())
- if n < 0 {
- errorf("negative length decoding []byte")
+ n := state.decodeUint()
+ if n > uint64(state.b.Len()) {
+ errorf("length of []byte exceeds input size (%d bytes)", n)
}
slice := (*[]uint8)(p)
- if cap(*slice) < n {
+ if uint64(cap(*slice)) < n {
*slice = make([]uint8, n)
} else {
*slice = (*slice)[0:n]
@@ -417,7 +417,11 @@ func decString(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]byte, state.decodeUint())
+ n := state.decodeUint()
+ if n > uint64(state.b.Len()) {
+ errorf("string length exceeds input size (%d bytes)", n)
+ }
+ b := make([]byte, n)
state.b.Read(b)
// It would be a shame to do the obvious thing here,
// *(*string)(p) = string(b)
@@ -647,7 +651,11 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores the slice header through p.
// Slices are encoded as an unsigned length followed by the elements.
func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
- n := int(uintptr(state.decodeUint()))
+ nr := state.decodeUint()
+ if nr > uint64(state.b.Len()) {
+ errorf("length of slice exceeds input size (%d elements)", nr)
+ }
+ n := int(nr)
if indir > 0 {
up := unsafe.Pointer(p)
if *(*unsafe.Pointer)(up) == nil {
@@ -702,6 +710,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
*(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
return
}
+ if len(name) > 1024 {
+ errorf("name too long (%d bytes): %.20q...", len(name), name)
+ }
// The concrete type must be registered.
typ, ok := nameToConcreteType[name]
if !ok {
diff --git a/libgo/go/encoding/gob/dump.go b/libgo/go/encoding/gob/dump.go
index e23a11e48bf..17238c98df0 100644
--- a/libgo/go/encoding/gob/dump.go
+++ b/libgo/go/encoding/gob/dump.go
@@ -7,6 +7,7 @@
package main
// Need to compile package gob with debug.go to build this program.
+// See comments in debug.go for how to do this.
import (
"encoding/gob"
diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go
index 3bfae30f39a..050786dfd1f 100644
--- a/libgo/go/encoding/gob/encoder_test.go
+++ b/libgo/go/encoding/gob/encoder_test.go
@@ -709,7 +709,7 @@ func TestGobPtrSlices(t *testing.T) {
t.Fatal("decode:", err)
}
if !reflect.DeepEqual(in, out) {
- t.Fatal("got %v; wanted %v", out, in)
+ t.Fatalf("got %v; wanted %v", out, in)
}
}
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index 0eec586a9bb..d758758d978 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -239,16 +239,6 @@ func TestEscape(t *testing.T) {
}
}
-func TestHTMLEscape(t *testing.T) {
- b, err := MarshalForHTML("foobarbaz<>&quux")
- if err != nil {
- t.Fatalf("MarshalForHTML error: %v", err)
- }
- if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
- t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
- }
-}
-
// WrongString is a struct that's misusing the ,string modifier.
type WrongString struct {
Message string `json:"result,string"`
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index 8a794b79bd5..5425a3a90a1 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -123,17 +123,6 @@ func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
return buf.Bytes(), nil
}
-// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
-func MarshalForHTML(v interface{}) ([]byte, error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- HTMLEscape(&buf, b)
- return buf.Bytes(), nil
-}
-
// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
// characters inside string literals changed to \u003c, \u003e, \u0026
// so that the JSON will be safe to embed inside HTML <script> tags.
@@ -200,11 +189,6 @@ func (e *MarshalerError) Error() string {
return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error()
}
-type interfaceOrPtrValue interface {
- IsNil() bool
- Elem() reflect.Value
-}
-
var hex = "0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
@@ -276,7 +260,7 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
b, err := m.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
- err = Compact(&e.Buffer, b)
+ err = compact(&e.Buffer, b, true)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err})
diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go
index 7a726a91c47..cb1c77eb529 100644
--- a/libgo/go/encoding/json/encode_test.go
+++ b/libgo/go/encoding/json/encode_test.go
@@ -167,3 +167,22 @@ func TestRefValMarshal(t *testing.T) {
t.Errorf("got %q, want %q", got, want)
}
}
+
+// C implements Marshaler and returns unescaped JSON.
+type C int
+
+func (C) MarshalJSON() ([]byte, error) {
+ return []byte(`"<&>"`), nil
+}
+
+func TestMarshalerEscaping(t *testing.T) {
+ var c C
+ const want = `"\u003c\u0026\u003e"`
+ b, err := Marshal(c)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if got := string(b); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go
index 5ba19b07ac6..e8dfa4ec436 100644
--- a/libgo/go/encoding/json/indent.go
+++ b/libgo/go/encoding/json/indent.go
@@ -9,11 +9,24 @@ import "bytes"
// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
func Compact(dst *bytes.Buffer, src []byte) error {
+ return compact(dst, src, false)
+}
+
+func compact(dst *bytes.Buffer, src []byte, escape bool) error {
origLen := dst.Len()
var scan scanner
scan.reset()
start := 0
for i, c := range src {
+ if escape && (c == '<' || c == '>' || c == '&') {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
v := scan.step(&scan, int(c))
if v >= scanSkipSpace {
if v == scanError {
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index 9170fccd243..b6978a1e65b 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -136,12 +136,12 @@ type NamePrecedence struct {
type XMLNameWithTag struct {
XMLName Name `xml:"InXMLNameTag"`
- Value string ",chardata"
+ Value string `xml:",chardata"`
}
type XMLNameWithoutTag struct {
XMLName Name
- Value string ",chardata"
+ Value string `xml:",chardata"`
}
type NameInField struct {
@@ -532,9 +532,9 @@ var marshalTests = []struct {
InFieldName: "D",
},
ExpectXML: `<Parent>` +
- `<InTag><Value>A</Value></InTag>` +
- `<InXMLName><Value>B</Value></InXMLName>` +
- `<InXMLNameTag><Value>C</Value></InXMLNameTag>` +
+ `<InTag>A</InTag>` +
+ `<InXMLName>B</InXMLName>` +
+ `<InXMLNameTag>C</InXMLNameTag>` +
`<InFieldName>D</InFieldName>` +
`</Parent>`,
MarshalOnly: true,
@@ -548,9 +548,9 @@ var marshalTests = []struct {
InFieldName: "D",
},
ExpectXML: `<Parent>` +
- `<InTag><Value>A</Value></InTag>` +
- `<FromNameVal><Value>B</Value></FromNameVal>` +
- `<InXMLNameTag><Value>C</Value></InXMLNameTag>` +
+ `<InTag>A</InTag>` +
+ `<FromNameVal>B</FromNameVal>` +
+ `<InXMLNameTag>C</InXMLNameTag>` +
`<InFieldName>D</InFieldName>` +
`</Parent>`,
UnmarshalOnly: true,
diff --git a/libgo/go/exp/gotype/doc.go b/libgo/go/exp/gotype/doc.go
index 1aa0faa751a..1168086771f 100644
--- a/libgo/go/exp/gotype/doc.go
+++ b/libgo/go/exp/gotype/doc.go
@@ -34,6 +34,8 @@ The flags are:
Verbose mode.
Debugging flags:
+ -comments
+ Parse comments (ignored if -ast not set).
-ast
Print AST (disables concurrent parsing).
-trace
diff --git a/libgo/go/exp/gotype/gotype.go b/libgo/go/exp/gotype/gotype.go
index a2a9361866d..30eaf22fca6 100644
--- a/libgo/go/exp/gotype/gotype.go
+++ b/libgo/go/exp/gotype/gotype.go
@@ -27,8 +27,9 @@ var (
allErrors = flag.Bool("e", false, "print all (including spurious) errors")
// debugging support
- printTrace = flag.Bool("trace", false, "print parse trace")
- printAST = flag.Bool("ast", false, "print AST")
+ parseComments = flag.Bool("comments", false, "parse comments (ignored if -ast not set)")
+ printTrace = flag.Bool("trace", false, "print parse trace")
+ printAST = flag.Bool("ast", false, "print AST")
)
var exitCode = 0
@@ -73,6 +74,9 @@ func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
if *allErrors {
mode |= parser.SpuriousErrors
}
+ if *parseComments && *printAST {
+ mode |= parser.ParseComments
+ }
if *printTrace {
mode |= parser.Trace
}
diff --git a/libgo/go/exp/html/node.go b/libgo/go/exp/html/node.go
index 83f17308b18..c105a4e709a 100644
--- a/libgo/go/exp/html/node.go
+++ b/libgo/go/exp/html/node.go
@@ -110,7 +110,7 @@ func (s *nodeStack) top() *Node {
return nil
}
-// index returns the index of the top-most occurence of n in the stack, or -1
+// index returns the index of the top-most occurrence of n in the stack, or -1
// if n is not present.
func (s *nodeStack) index(n *Node) int {
for i := len(*s) - 1; i >= 0; i-- {
diff --git a/libgo/go/exp/norm/forminfo.go b/libgo/go/exp/norm/forminfo.go
index fd7b3956233..c443b78d825 100644
--- a/libgo/go/exp/norm/forminfo.go
+++ b/libgo/go/exp/norm/forminfo.go
@@ -18,17 +18,17 @@ package norm
// has the form:
// <header> <decomp_byte>* [<tccc> [<lccc>]]
// The header contains the number of bytes in the decomposition (excluding this
-// length byte). The two most significant bits of this lenght byte correspond
+// length byte). The two most significant bits of this length byte correspond
// to bit 2 and 3 of qcIfo (see below). The byte sequence itself starts at v+1.
// The byte sequence is followed by a trailing and leading CCC if the values
// for these are not zero. The value of v determines which ccc are appended
// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
-// the seqence is followed by a trailing ccc, and for v >= firstLeadingCC
+// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC
// there is an additional leading ccc.
const (
qcInfoMask = 0xF // to clear all but the relevant bits in a qcInfo
- headerLenMask = 0x3F // extract the lenght value from the header byte
+ headerLenMask = 0x3F // extract the length value from the header byte
headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
)
diff --git a/libgo/go/exp/proxy/per_host.go b/libgo/go/exp/proxy/per_host.go
index 397ef57cd92..0c627e9ab54 100644
--- a/libgo/go/exp/proxy/per_host.go
+++ b/libgo/go/exp/proxy/per_host.go
@@ -75,7 +75,7 @@ func (p *PerHost) dialerForRequest(host string) Dialer {
}
// AddFromString parses a string that contains comma-separated values
-// specifing hosts that should use the bypass proxy. Each value is either an
+// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a hostname
// (localhost). A best effort is made to parse the string and errors are
// ignored.
diff --git a/libgo/go/exp/types/gcimporter.go b/libgo/go/exp/types/gcimporter.go
index 8b28aede1ec..cb996f28055 100644
--- a/libgo/go/exp/types/gcimporter.go
+++ b/libgo/go/exp/types/gcimporter.go
@@ -18,6 +18,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "strings"
"text/scanner"
)
@@ -39,11 +40,14 @@ func findPkg(path string) (filename, id string) {
switch path[0] {
default:
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
- tree, pkg, err := build.FindTree(path)
- if err != nil {
+ bp, _ := build.Import(path, "", build.FindOnly)
+ if bp.PkgObj == "" {
return
}
- noext = filepath.Join(tree.PkgDir(), pkg)
+ noext = bp.PkgObj
+ if strings.HasSuffix(noext, ".a") {
+ noext = noext[:len(noext)-2]
+ }
case '.':
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -742,7 +746,7 @@ func (p *gcParser) parseVarDecl() {
}
// FuncBody = "{" ... "}" .
-//
+//
func (p *gcParser) parseFuncBody() {
p.expect('{')
for i := 1; i > 0; p.next() {
diff --git a/libgo/go/exp/types/types.go b/libgo/go/exp/types/types.go
index 3aa896892e3..85d244cf04a 100644
--- a/libgo/go/exp/types/types.go
+++ b/libgo/go/exp/types/types.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// PACKAGE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
-// Package types declares the types used to represent Go types.
+// Package types declares the types used to represent Go types
+// (UNDER CONSTRUCTION). ANY AND ALL PARTS MAY CHANGE.
//
package types
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
index f6c63c0d889..02cf9e02234 100644
--- a/libgo/go/go/ast/print.go
+++ b/libgo/go/go/ast/print.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.
-// This file contains printing suppport for ASTs.
+// This file contains printing support for ASTs.
package ast
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
index 68e8d342005..eece7610562 100644
--- a/libgo/go/go/build/build.go
+++ b/libgo/go/go/build/build.go
@@ -2,10 +2,948 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package build provides tools for building Go packages.
package build
-import "errors"
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// A Context specifies the supporting context for a build.
+type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ BuildTags []string // additional tags to recognize in +build lines
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Gccgo bool // assume use of gccgo when computing object paths
+
+ // By default, Import uses the operating system's file system calls
+ // to read directories and files. To read from other sources,
+ // callers can set the following functions. They all have default
+ // behaviors that use the local file system, so clients need only set
+ // the functions whose behaviors they wish to change.
+
+ // JoinPath joins the sequence of path fragments into a single path.
+ // If JoinPath is nil, Import uses filepath.Join.
+ JoinPath func(elem ...string) string
+
+ // SplitPathList splits the path list into a slice of individual paths.
+ // If SplitPathList is nil, Import uses filepath.SplitList.
+ SplitPathList func(list string) []string
+
+ // IsAbsPath reports whether path is an absolute path.
+ // If IsAbsPath is nil, Import uses filepath.IsAbs.
+ IsAbsPath func(path string) bool
+
+ // IsDir reports whether the path names a directory.
+ // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
+ IsDir func(path string) bool
+
+ // HasSubdir reports whether dir is a subdirectory of
+ // (perhaps multiple levels below) root.
+ // If so, HasSubdir sets rel to a slash-separated path that
+ // can be joined to root to produce a path equivalent to dir.
+ // If HasSubdir is nil, Import uses an implementation built on
+ // filepath.EvalSymlinks.
+ HasSubdir func(root, dir string) (rel string, ok bool)
+
+ // ReadDir returns a slice of os.FileInfo, sorted by Name,
+ // describing the content of the named directory.
+ // If ReadDir is nil, Import uses io.ReadDir.
+ ReadDir func(dir string) (fi []os.FileInfo, err error)
+
+ // OpenFile opens a file (not a directory) for reading.
+ // If OpenFile is nil, Import uses os.Open.
+ OpenFile func(path string) (r io.ReadCloser, err error)
+}
+
+// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
+func (ctxt *Context) joinPath(elem ...string) string {
+ if f := ctxt.JoinPath; f != nil {
+ return f(elem...)
+ }
+ return filepath.Join(elem...)
+}
+
+// splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
+func (ctxt *Context) splitPathList(s string) []string {
+ if f := ctxt.SplitPathList; f != nil {
+ return f(s)
+ }
+ return filepath.SplitList(s)
+}
+
+// isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs.
+func (ctxt *Context) isAbsPath(path string) bool {
+ if f := ctxt.IsAbsPath; f != nil {
+ return f(path)
+ }
+ return filepath.IsAbs(path)
+}
+
+// isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
+func (ctxt *Context) isDir(path string) bool {
+ if f := ctxt.IsDir; f != nil {
+ return f(path)
+ }
+ fi, err := os.Stat(path)
+ return err == nil && fi.IsDir()
+}
+
+// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
+// the local file system to answer the question.
+func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
+ if f := ctxt.HasSubdir; f != nil {
+ return f(root, dir)
+ }
+
+ if p, err := filepath.EvalSymlinks(root); err == nil {
+ root = p
+ }
+ if p, err := filepath.EvalSymlinks(dir); err == nil {
+ dir = p
+ }
+ const sep = string(filepath.Separator)
+ root = filepath.Clean(root)
+ if !strings.HasSuffix(root, sep) {
+ root += sep
+ }
+ dir = filepath.Clean(dir)
+ if !strings.HasPrefix(dir, root) {
+ return "", false
+ }
+ return filepath.ToSlash(dir[len(root):]), true
+}
+
+// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
+func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
+ if f := ctxt.ReadDir; f != nil {
+ return f(path)
+ }
+ return ioutil.ReadDir(path)
+}
+
+// openFile calls ctxt.OpenFile (if not nil) or else os.Open.
+func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
+ if fn := ctxt.OpenFile; fn != nil {
+ return fn(path)
+ }
+
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err // nil interface
+ }
+ return f, nil
+}
+
+// isFile determines whether path is a file by trying to open it.
+// It reuses openFile instead of adding another function to the
+// list in Context.
+func (ctxt *Context) isFile(path string) bool {
+ f, err := ctxt.openFile(path)
+ if err != nil {
+ return false
+ }
+ f.Close()
+ return true
+}
+
+// gopath returns the list of Go path directories.
+func (ctxt *Context) gopath() []string {
+ var all []string
+ for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
+ if p == "" || p == ctxt.GOROOT {
+ // Empty paths are uninteresting.
+ // If the path is the GOROOT, ignore it.
+ // People sometimes set GOPATH=$GOROOT, which is useless
+ // but would cause us to find packages with import paths
+ // like "pkg/math".
+ // Do not get confused by this common mistake.
+ continue
+ }
+ all = append(all, p)
+ }
+ return all
+}
+
+// SrcDirs returns a list of package source root directories.
+// It draws from the current Go root and Go path but omits directories
+// that do not exist.
+func (ctxt *Context) SrcDirs() []string {
+ var all []string
+ if ctxt.GOROOT != "" {
+ dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ if ctxt.isDir(dir) {
+ all = append(all, dir)
+ }
+ }
+ for _, p := range ctxt.gopath() {
+ dir := ctxt.joinPath(p, "src")
+ if ctxt.isDir(dir) {
+ all = append(all, dir)
+ }
+ }
+ return all
+}
+
+// Default is the default Context for builds.
+// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
+// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
+var Default Context = 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)
+ c.GOROOT = runtime.GOROOT()
+ c.GOPATH = envOr("GOPATH", "")
+
+ switch os.Getenv("CGO_ENABLED") {
+ 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 {
+ s := os.Getenv(name)
+ if s == "" {
+ return def
+ }
+ return s
+}
+
+// An ImportMode controls the behavior of the Import method.
+type ImportMode uint
+
+const (
+ // If FindOnly is set, Import stops after locating the directory
+ // that should contain the sources for a package. It does not
+ // read any files in the directory.
+ FindOnly ImportMode = 1 << iota
+
+ // If AllowBinary is set, Import can be satisfied by a compiled
+ // package object without corresponding sources.
+ AllowBinary
+)
+
+// A Package describes the Go package found in a directory.
+type Package struct {
+ Dir string // directory containing package sources
+ Name string // package name
+ Doc string // documentation synopsis
+ ImportPath string // import path of package ("" if unknown)
+ Root string // root of Go tree where this package lives
+ SrcRoot string // package source root directory ("" if unknown)
+ PkgRoot string // package install root directory ("" if unknown)
+ BinDir string // command install directory ("" if unknown)
+ Goroot bool // package found in Go root
+ PkgObj string // installed .a file
+
+ // Source files
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go source files that import "C"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+
+ // Cgo directives
+ CgoPkgConfig []string // Cgo pkg-config directives
+ CgoCFLAGS []string // Cgo CFLAGS directives
+ CgoLDFLAGS []string // Cgo LDFLAGS directives
+
+ // Dependency information
+ Imports []string // imports from GoFiles, CgoFiles
+ ImportPos map[string][]token.Position // line information for Imports
+
+ // Test information
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ TestImportPos map[string][]token.Position // line information for TestImports
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
+ XTestImportPos map[string][]token.Position // line information for XTestImports
+}
+
+// IsCommand reports whether the package is considered a
+// command to be installed (not just a library).
+// Packages named "main" are treated as commands.
+func (p *Package) IsCommand() bool {
+ return p.Name == "main"
+}
+
+// ImportDir is like Import but processes the Go package found in
+// the named directory.
+func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
+ return ctxt.Import(".", dir, mode)
+}
+
+// Import returns details about the Go package named by the import path,
+// interpreting local import paths relative to the src directory. If the path
+// is a local import path naming a package that can be imported using a
+// standard import path, the returned package will set p.ImportPath to
+// that path.
+//
+// In the directory containing the package, .go, .c, .h, and .s files are
+// considered part of the package except for:
+//
+// - .go files in package documentation
+// - files starting with _ or .
+// - files with build constraints not satisfied by the context
+//
+// If an error occurs, Import returns a non-nil error also returns a non-nil
+// *Package containing partial information.
+//
+func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) {
+ p := &Package{
+ ImportPath: path,
+ }
+
+ var pkga string
+ if ctxt.Gccgo {
+ dir, elem := pathpkg.Split(p.ImportPath)
+ pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
+ } else {
+ pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
+ }
+
+ binaryOnly := false
+ if IsLocalImport(path) {
+ if src == "" {
+ return p, fmt.Errorf("import %q: import relative to unknown directory", path)
+ }
+ if !ctxt.isAbsPath(path) {
+ p.Dir = ctxt.joinPath(src, path)
+ }
+ // Determine canonical import path, if any.
+ if ctxt.GOROOT != "" {
+ root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
+ p.Goroot = true
+ p.ImportPath = sub
+ p.Root = ctxt.GOROOT
+ goto Found
+ }
+ }
+ all := ctxt.gopath()
+ for i, root := range all {
+ rootsrc := ctxt.joinPath(root, "src")
+ if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
+ // We found a potential import path for dir,
+ // but check that using it wouldn't find something
+ // else first.
+ if ctxt.GOROOT != "" {
+ if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
+ goto Found
+ }
+ }
+ for _, earlyRoot := range all[:i] {
+ if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
+ goto Found
+ }
+ }
+
+ // sub would not name some other directory instead of this one.
+ // Record it.
+ p.ImportPath = sub
+ p.Root = root
+ goto Found
+ }
+ }
+ // It's okay that we didn't find a root containing dir.
+ // Keep going with the information we have.
+ } else {
+ if strings.HasPrefix(path, "/") {
+ return p, fmt.Errorf("import %q: cannot import absolute path", path)
+ }
+ // Determine directory from import path.
+ if ctxt.GOROOT != "" {
+ dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
+ isDir := ctxt.isDir(dir)
+ binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
+ if isDir || binaryOnly {
+ p.Dir = dir
+ p.Goroot = true
+ p.Root = ctxt.GOROOT
+ goto Found
+ }
+ }
+ for _, root := range ctxt.gopath() {
+ dir := ctxt.joinPath(root, "src", path)
+ isDir := ctxt.isDir(dir)
+ binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(root, pkga))
+ if isDir || binaryOnly {
+ p.Dir = dir
+ p.Root = root
+ goto Found
+ }
+ }
+ return p, fmt.Errorf("import %q: cannot find package", path)
+ }
+
+Found:
+ if p.Root != "" {
+ if p.Goroot {
+ p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
+ } else {
+ p.SrcRoot = ctxt.joinPath(p.Root, "src")
+ }
+ p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
+ p.BinDir = ctxt.joinPath(p.Root, "bin")
+ p.PkgObj = ctxt.joinPath(p.Root, pkga)
+ }
+
+ if mode&FindOnly != 0 {
+ return p, nil
+ }
+ if binaryOnly && (mode&AllowBinary) != 0 {
+ return p, nil
+ }
+
+ dirs, err := ctxt.readDir(p.Dir)
+ if err != nil {
+ return p, err
+ }
+
+ var Sfiles []string // files with ".S" (capital S)
+ var firstFile string
+ imported := make(map[string][]token.Position)
+ testImported := make(map[string][]token.Position)
+ xTestImported := make(map[string][]token.Position)
+ fset := token.NewFileSet()
+ for _, d := range dirs {
+ if d.IsDir() {
+ continue
+ }
+ name := d.Name()
+ if strings.HasPrefix(name, "_") ||
+ strings.HasPrefix(name, ".") {
+ continue
+ }
+ if !ctxt.UseAllFiles && !ctxt.goodOSArchFile(name) {
+ continue
+ }
+
+ i := strings.LastIndex(name, ".")
+ if i < 0 {
+ i = len(name)
+ }
+ ext := name[i:]
+ switch ext {
+ case ".go", ".c", ".s", ".h", ".S":
+ // tentatively okay
+ default:
+ // skip
+ continue
+ }
+
+ filename := ctxt.joinPath(p.Dir, name)
+ f, err := ctxt.openFile(filename)
+ if err != nil {
+ return p, err
+ }
+ data, err := ioutil.ReadAll(f)
+ f.Close()
+ if err != nil {
+ return p, fmt.Errorf("read %s: %v", filename, err)
+ }
+
+ // Look for +build comments to accept or reject the file.
+ if !ctxt.UseAllFiles && !ctxt.shouldBuild(data) {
+ continue
+ }
+
+ // Going to save the file. For non-Go files, can stop here.
+ switch ext {
+ case ".c":
+ p.CFiles = append(p.CFiles, name)
+ continue
+ case ".h":
+ p.HFiles = append(p.HFiles, name)
+ continue
+ case ".s":
+ p.SFiles = append(p.SFiles, name)
+ continue
+ case ".S":
+ Sfiles = append(Sfiles, name)
+ continue
+ }
+
+ pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
+ if err != nil {
+ return p, err
+ }
+
+ pkg := string(pf.Name.Name)
+ if pkg == "documentation" {
+ continue
+ }
+
+ isTest := strings.HasSuffix(name, "_test.go")
+ isXTest := false
+ if isTest && strings.HasSuffix(pkg, "_test") {
+ isXTest = true
+ pkg = pkg[:len(pkg)-len("_test")]
+ }
+
+ if p.Name == "" {
+ p.Name = pkg
+ firstFile = name
+ } else if pkg != p.Name {
+ return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
+ }
+ if pf.Doc != nil && p.Doc == "" {
+ p.Doc = doc.Synopsis(pf.Doc.Text())
+ }
+
+ // Record imports and information about cgo.
+ isCgo := false
+ for _, decl := range pf.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ continue
+ }
+ for _, dspec := range d.Specs {
+ spec, ok := dspec.(*ast.ImportSpec)
+ if !ok {
+ continue
+ }
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ if isXTest {
+ xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos()))
+ } else if isTest {
+ testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
+ } else {
+ imported[path] = append(imported[path], fset.Position(spec.Pos()))
+ }
+ if path == "C" {
+ if isTest {
+ return p, fmt.Errorf("use of cgo in test %s not supported", filename)
+ }
+ cg := spec.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
+ }
+ if cg != nil {
+ if err := ctxt.saveCgo(filename, p, cg); err != nil {
+ return p, err
+ }
+ }
+ isCgo = true
+ }
+ }
+ }
+ if isCgo {
+ if ctxt.CgoEnabled {
+ p.CgoFiles = append(p.CgoFiles, name)
+ }
+ } else if isXTest {
+ p.XTestGoFiles = append(p.XTestGoFiles, name)
+ } else if isTest {
+ p.TestGoFiles = append(p.TestGoFiles, name)
+ } else {
+ p.GoFiles = append(p.GoFiles, name)
+ }
+ }
+ if p.Name == "" {
+ return p, fmt.Errorf("no Go source files in %s", p.Dir)
+ }
+
+ p.Imports, p.ImportPos = cleanImports(imported)
+ p.TestImports, p.TestImportPos = cleanImports(testImported)
+ p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
+
+ // add the .S files only if we are using cgo
+ // (which means gcc will compile them).
+ // The standard assemblers expect .s files.
+ if len(p.CgoFiles) > 0 {
+ p.SFiles = append(p.SFiles, Sfiles...)
+ sort.Strings(p.SFiles)
+ }
+
+ return p, nil
+}
+
+func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
+ all := make([]string, 0, len(m))
+ for path := range m {
+ all = append(all, path)
+ }
+ sort.Strings(all)
+ return all, m
+}
+
+// Import is shorthand for Default.Import.
+func Import(path, src string, mode ImportMode) (*Package, error) {
+ return Default.Import(path, src, mode)
+}
+
+// ImportDir is shorthand for Default.ImportDir.
+func ImportDir(dir string, mode ImportMode) (*Package, error) {
+ return Default.ImportDir(dir, mode)
+}
+
+var slashslash = []byte("//")
+
+// shouldBuild reports whether it is okay to use this file,
+// The rule is that in the file's leading run of // comments
+// and blank lines, which must be followed by a blank line
+// (to avoid including a Go package clause doc comment),
+// lines beginning with '// +build' are taken as build directives.
+//
+// The file is accepted only if each such line lists something
+// matching the file. For example:
+//
+// // +build windows linux
+//
+// marks the file as applicable only on Windows and Linux.
+//
+func (ctxt *Context) shouldBuild(content []byte) bool {
+ // Pass 1. Identify leading run of // comments and blank lines,
+ // which must be followed by a blank line.
+ end := 0
+ p := content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 { // Blank line
+ end = cap(content) - cap(line) // &line[0] - &content[0]
+ continue
+ }
+ if !bytes.HasPrefix(line, slashslash) { // Not comment line
+ break
+ }
+ }
+ content = content[:end]
+
+ // Pass 2. Process each line in the run.
+ p = content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if bytes.HasPrefix(line, slashslash) {
+ line = bytes.TrimSpace(line[len(slashslash):])
+ if len(line) > 0 && line[0] == '+' {
+ // Looks like a comment +line.
+ f := strings.Fields(string(line))
+ if f[0] == "+build" {
+ ok := false
+ for _, tok := range f[1:] {
+ if ctxt.match(tok) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ return false // this one doesn't match
+ }
+ }
+ }
+ }
+ }
+ return true // everything matches
+}
+
+// saveCgo saves the information from the #cgo lines in the import "C" comment.
+// These lines set CFLAGS and LDFLAGS and pkg-config directives that affect
+// the way cgo's C code is built.
+//
+// TODO(rsc): This duplicates code in cgo.
+// Once the dust settles, remove this code from cgo.
+func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
+ text := cg.Text()
+ for _, line := range strings.Split(text, "\n") {
+ orig := line
+
+ // Line is
+ // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
+ //
+ line = strings.TrimSpace(line)
+ if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
+ continue
+ }
+
+ // Split at colon.
+ line = strings.TrimSpace(line[4:])
+ i := strings.Index(line, ":")
+ if i < 0 {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+ line, argstr := line[:i], line[i+1:]
+
+ // Parse GOOS/GOARCH stuff.
+ f := strings.Fields(line)
+ if len(f) < 1 {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+
+ cond, verb := f[:len(f)-1], f[len(f)-1]
+ if len(cond) > 0 {
+ ok := false
+ for _, c := range cond {
+ if ctxt.match(c) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ continue
+ }
+ }
+
+ args, err := splitQuoted(argstr)
+ if err != nil {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+ for _, arg := range args {
+ if !safeName(arg) {
+ return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
+ }
+ }
+
+ switch verb {
+ case "CFLAGS":
+ di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
+ case "LDFLAGS":
+ di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
+ case "pkg-config":
+ di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
+ default:
+ return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
+ }
+ }
+ return nil
+}
+
+var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
+
+func safeName(s string) bool {
+ if s == "" {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// a b:"c d" 'e''f' "g\""
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+//
+func splitQuoted(s string) (r []string, err error) {
+ var args []string
+ arg := make([]rune, len(s))
+ escaped := false
+ quoted := false
+ quote := '\x00'
+ i := 0
+ for _, rune := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case rune == '\\':
+ escaped = true
+ continue
+ case quote != '\x00':
+ if rune == quote {
+ quote = '\x00'
+ continue
+ }
+ case rune == '"' || rune == '\'':
+ quoted = true
+ quote = rune
+ continue
+ case unicode.IsSpace(rune):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
+ }
+ continue
+ }
+ arg[i] = rune
+ i++
+ }
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = errors.New("unclosed quote")
+ } else if escaped {
+ err = errors.New("unfinished escaping")
+ }
+ return args, err
+}
+
+// match returns true if the name is one of:
+//
+// $GOOS
+// $GOARCH
+// cgo (if cgo is enabled)
+// !cgo (if cgo is disabled)
+// tag (if tag is listed in ctxt.BuildTags)
+// !tag (if tag is not listed in ctxt.BuildTags)
+// a slash-separated list of any of these
+//
+func (ctxt *Context) match(name string) bool {
+ if name == "" {
+ return false
+ }
+ if i := strings.Index(name, ","); i >= 0 {
+ // comma-separated list
+ return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+ }
+ if strings.HasPrefix(name, "!!") { // bad syntax, reject always
+ return false
+ }
+ if strings.HasPrefix(name, "!") { // negation
+ return !ctxt.match(name[1:])
+ }
+
+ // Tags must be letters, digits, underscores.
+ // Unlike in Go identifiers, all digits is fine (e.g., "386").
+ for _, c := range name {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
+ return false
+ }
+ }
+
+ // special tags
+ if ctxt.CgoEnabled && name == "cgo" {
+ return true
+ }
+ if name == ctxt.GOOS || name == ctxt.GOARCH {
+ return true
+ }
+
+ // other tags
+ for _, tag := range ctxt.BuildTags {
+ if tag == name {
+ return true
+ }
+ }
+
+ return false
+}
+
+// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized name formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+// name_$(GOOS)_test.*
+// name_$(GOARCH)_test.*
+// name_$(GOOS)_$(GOARCH)_test.*
+//
+func (ctxt *Context) goodOSArchFile(name string) bool {
+ if dot := strings.Index(name, "."); dot != -1 {
+ name = name[:dot]
+ }
+ l := strings.Split(name, "_")
+ if n := len(l); n > 0 && l[n-1] == "test" {
+ l = l[:n-1]
+ }
+ n := len(l)
+ if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
+ return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
+ }
+ if n >= 1 && knownOS[l[n-1]] {
+ return l[n-1] == ctxt.GOOS
+ }
+ if n >= 1 && knownArch[l[n-1]] {
+ return l[n-1] == ctxt.GOARCH
+ }
+ return true
+}
+
+var knownOS = make(map[string]bool)
+var knownArch = make(map[string]bool)
+
+func init() {
+ for _, v := range strings.Fields(goosList) {
+ knownOS[v] = true
+ }
+ for _, v := range strings.Fields(goarchList) {
+ knownArch[v] = true
+ }
+}
+
+// ToolDir is the directory containing build tools.
+var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
+
+// IsLocalImport reports whether the import path is
+// a local import path, like ".", "..", "./foo", or "../foo".
+func IsLocalImport(path string) bool {
+ return path == "." || path == ".." ||
+ strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
+}
// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
index 3c706a46edd..06b8b0e94f8 100644
--- a/libgo/go/go/build/build_test.go
+++ b/libgo/go/go/build/build_test.go
@@ -5,83 +5,14 @@
package build
import (
+ "os"
"path/filepath"
- "reflect"
"runtime"
- "sort"
"testing"
)
-func sortstr(x []string) []string {
- sort.Strings(x)
- return x
-}
-
-var buildPkgs = []struct {
- dir string
- info *DirInfo
-}{
- {
- "go/build/pkgtest",
- &DirInfo{
- GoFiles: []string{"pkgtest.go"},
- SFiles: []string{"sqrt_" + runtime.GOARCH + ".s"},
- Package: "pkgtest",
- Imports: []string{"bytes"},
- TestImports: []string{"fmt", "pkgtest"},
- TestGoFiles: sortstr([]string{"sqrt_test.go", "sqrt_" + runtime.GOARCH + "_test.go"}),
- XTestGoFiles: []string{"xsqrt_test.go"},
- },
- },
- {
- "go/build/cmdtest",
- &DirInfo{
- GoFiles: []string{"main.go"},
- Package: "main",
- Imports: []string{"go/build/pkgtest"},
- TestImports: []string{},
- },
- },
- {
- "go/build/cgotest",
- &DirInfo{
- CgoFiles: ifCgo([]string{"cgotest.go"}),
- CFiles: []string{"cgotest.c"},
- HFiles: []string{"cgotest.h"},
- Imports: []string{"C", "unsafe"},
- TestImports: []string{},
- Package: "cgotest",
- },
- },
-}
-
-func ifCgo(x []string) []string {
- if DefaultContext.CgoEnabled {
- return x
- }
- return nil
-}
-
-func TestBuild(t *testing.T) {
- for _, tt := range buildPkgs {
- tree := Path[0] // Goroot
- dir := filepath.Join(tree.SrcDir(), tt.dir)
- info, err := ScanDir(dir)
- if err != nil {
- t.Errorf("ScanDir(%#q): %v", tt.dir, err)
- continue
- }
- // Don't bother testing import positions.
- tt.info.ImportPos, tt.info.TestImportPos = info.ImportPos, info.TestImportPos
- if !reflect.DeepEqual(info, tt.info) {
- t.Errorf("ScanDir(%#q) = %#v, want %#v\n", tt.dir, info, tt.info)
- continue
- }
- }
-}
-
func TestMatch(t *testing.T) {
- ctxt := DefaultContext
+ ctxt := Default
what := "default"
match := func(tag string) {
if !ctxt.match(tag) {
@@ -106,3 +37,40 @@ func TestMatch(t *testing.T) {
match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
}
+
+func TestDotSlashImport(t *testing.T) {
+ p, err := ImportDir("testdata/other", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(p.Imports) != 1 || p.Imports[0] != "./file" {
+ t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
+ }
+
+ p1, err := Import("./file", "testdata/other", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p1.Name != "file" {
+ t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
+ }
+ dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
+ if p1.Dir != dir {
+ t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
+ }
+}
+
+func TestLocalDirectory(t *testing.T) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ p, err := ImportDir(cwd, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p.ImportPath != "go/build" {
+ t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build")
+ }
+}
diff --git a/libgo/go/go/build/cgotest/cgotest.go b/libgo/go/go/build/cgotest/cgotest.go
deleted file mode 100644
index 93bbf06883f..00000000000
--- a/libgo/go/go/build/cgotest/cgotest.go
+++ /dev/null
@@ -1,19 +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 cgotest
-
-/*
-char* greeting = "hello, world";
-*/
-// #include "cgotest.h"
-import "C"
-import "unsafe"
-
-var Greeting = C.GoString(C.greeting)
-
-func DoAdd(x, y int) (sum int) {
- C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
- return
-}
diff --git a/libgo/go/go/build/cmdtest/main.go b/libgo/go/go/build/cmdtest/main.go
deleted file mode 100644
index bed4f485a0a..00000000000
--- a/libgo/go/go/build/cmdtest/main.go
+++ /dev/null
@@ -1,12 +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 main
-
-import "go/build/pkgtest"
-
-func main() {
- pkgtest.Foo()
- print(int(pkgtest.Sqrt(9)))
-}
diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go
deleted file mode 100644
index 6b30f76265b..00000000000
--- a/libgo/go/go/build/dir.go
+++ /dev/null
@@ -1,705 +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 build
-
-import (
- "bytes"
- "errors"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "io/ioutil"
- "log"
- "os"
- "path"
- "path/filepath"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "unicode"
-)
-
-// A Context specifies the supporting context for a build.
-type Context struct {
- GOARCH string // target architecture
- GOOS string // target operating system
- CgoEnabled bool // whether cgo can be used
- BuildTags []string // additional tags to recognize in +build lines
- UseAllFiles bool // use files regardless of +build lines, file names
-
- // By default, ScanDir uses the operating system's
- // file system calls to read directories and files.
- // Callers can override those calls to provide other
- // ways to read data by setting ReadDir and ReadFile.
- // ScanDir does not make any assumptions about the
- // format of the strings dir and file: they can be
- // slash-separated, backslash-separated, even URLs.
-
- // ReadDir returns a slice of os.FileInfo, sorted by Name,
- // describing the content of the named directory.
- // The dir argument is the argument to ScanDir.
- // If ReadDir is nil, ScanDir uses io.ReadDir.
- ReadDir func(dir string) (fi []os.FileInfo, err error)
-
- // ReadFile returns the content of the file named file
- // in the directory named dir. The dir argument is the
- // argument to ScanDir, and the file argument is the
- // Name field from an os.FileInfo returned by ReadDir.
- // The returned path is the full name of the file, to be
- // used in error messages.
- //
- // If ReadFile is nil, ScanDir uses filepath.Join(dir, file)
- // as the path and ioutil.ReadFile to read the data.
- ReadFile func(dir, file string) (path string, content []byte, err error)
-}
-
-func (ctxt *Context) readDir(dir string) ([]os.FileInfo, error) {
- if f := ctxt.ReadDir; f != nil {
- return f(dir)
- }
- return ioutil.ReadDir(dir)
-}
-
-func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
- if f := ctxt.ReadFile; f != nil {
- return f(dir, file)
- }
- p := filepath.Join(dir, file)
- content, err := ioutil.ReadFile(p)
- return p, content, err
-}
-
-// 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 = 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 {
- s := os.Getenv(name)
- if s == "" {
- return def
- }
- return s
-}
-
-type DirInfo struct {
- Package string // Name of package in dir
- PackageComment *ast.CommentGroup // Package comments from GoFiles
- ImportPath string // Import path of package in dir
- Imports []string // All packages imported by GoFiles
- ImportPos map[string][]token.Position // Source code location of imports
-
- // Source files
- GoFiles []string // .go files in dir (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- HFiles []string // .h files in dir
- CFiles []string // .c files in dir
- SFiles []string // .s (and, when using cgo, .S files in dir)
- CgoFiles []string // .go files that import "C"
-
- // Cgo directives
- CgoPkgConfig []string // Cgo pkg-config directives
- CgoCFLAGS []string // Cgo CFLAGS directives
- CgoLDFLAGS []string // Cgo LDFLAGS directives
-
- // Test information
- TestGoFiles []string // _test.go files in package
- XTestGoFiles []string // _test.go files outside package
- TestImports []string // All packages imported by (X)TestGoFiles
- TestImportPos map[string][]token.Position
-}
-
-func (d *DirInfo) IsCommand() bool {
- // TODO(rsc): This is at least a little bogus.
- return d.Package == "main"
-}
-
-// ScanDir calls DefaultContext.ScanDir.
-func ScanDir(dir string) (info *DirInfo, err error) {
- return DefaultContext.ScanDir(dir)
-}
-
-// TODO(rsc): Move this comment to a more appropriate place.
-
-// ScanDir returns a structure with details about the Go package
-// found in the given directory.
-//
-// Most .go, .c, .h, and .s files in the directory are considered part
-// of the package. The exceptions are:
-//
-// - .go files in package main (unless no other package is found)
-// - .go files in package documentation
-// - files starting with _ or .
-// - files with build constraints not satisfied by the context
-//
-// Build Constraints
-//
-// A build constraint is a line comment beginning with the directive +build
-// that lists the conditions under which a file should be included in the package.
-// Constraints may appear in any kind of source file (not just Go), but
-// they must be appear near the top of the file, preceded
-// only by blank lines and other line comments.
-//
-// A build constraint is evaluated as the OR of space-separated options;
-// each option evaluates as the AND of its comma-separated terms;
-// and each term is an alphanumeric word or, preceded by !, its negation.
-// That is, the build constraint:
-//
-// // +build linux,386 darwin,!cgo
-//
-// corresponds to the boolean formula:
-//
-// (linux AND 386) OR (darwin AND (NOT cgo))
-//
-// During a particular build, the following words are satisfied:
-//
-// - the target operating system, as spelled by runtime.GOOS
-// - the target architecture, as spelled by runtime.GOARCH
-// - "cgo", if ctxt.CgoEnabled is true
-// - any additional words listed in ctxt.BuildTags
-//
-// If a file's name, after stripping the extension and a possible _test suffix,
-// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
-// system and architecture values, then the file is considered to have an implicit
-// build constraint requiring those terms.
-//
-// Examples
-//
-// To keep a file from being considered for the build:
-//
-// // +build ignore
-//
-// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
-//
-// To build a file only when using cgo, and only on Linux and OS X:
-//
-// // +build linux,cgo darwin,cgo
-//
-// Such a file is usually paired with another file implementing the
-// default functionality for other systems, which in this case would
-// carry the constraint:
-//
-// // +build !linux !darwin !cgo
-//
-// Naming a file dns_windows.go will cause it to be included only when
-// building the package for Windows; similarly, math_386.s will be included
-// only when building the package for 32-bit x86.
-//
-func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
- dirs, err := ctxt.readDir(dir)
- if err != nil {
- return nil, err
- }
-
- var Sfiles []string // files with ".S" (capital S)
- var di DirInfo
- var firstFile string
- imported := make(map[string][]token.Position)
- testImported := make(map[string][]token.Position)
- fset := token.NewFileSet()
- for _, d := range dirs {
- if d.IsDir() {
- continue
- }
- name := d.Name()
- if strings.HasPrefix(name, "_") ||
- strings.HasPrefix(name, ".") {
- continue
- }
- if !ctxt.UseAllFiles && !ctxt.goodOSArchFile(name) {
- continue
- }
-
- ext := path.Ext(name)
- switch ext {
- case ".go", ".c", ".s", ".h", ".S":
- // tentatively okay
- default:
- // skip
- continue
- }
-
- filename, data, err := ctxt.readFile(dir, name)
- if err != nil {
- return nil, err
- }
-
- // Look for +build comments to accept or reject the file.
- if !ctxt.UseAllFiles && !ctxt.shouldBuild(data) {
- continue
- }
-
- // Going to save the file. For non-Go files, can stop here.
- switch ext {
- 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)
- if err != nil {
- return nil, err
- }
-
- pkg := string(pf.Name.Name)
- if pkg == "documentation" {
- continue
- }
-
- isTest := strings.HasSuffix(name, "_test.go")
- if isTest && strings.HasSuffix(pkg, "_test") {
- pkg = pkg[:len(pkg)-len("_test")]
- }
-
- if di.Package == "" {
- di.Package = pkg
- firstFile = name
- } else if pkg != di.Package {
- return nil, fmt.Errorf("%s: found packages %s (%s) and %s (%s)", dir, di.Package, firstFile, pkg, name)
- }
- if pf.Doc != nil {
- if di.PackageComment != nil {
- di.PackageComment.List = append(di.PackageComment.List, pf.Doc.List...)
- } else {
- di.PackageComment = pf.Doc
- }
- }
-
- // Record imports and information about cgo.
- isCgo := false
- for _, decl := range pf.Decls {
- d, ok := decl.(*ast.GenDecl)
- if !ok {
- continue
- }
- for _, dspec := range d.Specs {
- spec, ok := dspec.(*ast.ImportSpec)
- if !ok {
- continue
- }
- quoted := string(spec.Path.Value)
- path, err := strconv.Unquote(quoted)
- if err != nil {
- log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
- }
- if isTest {
- testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
- } else {
- imported[path] = append(imported[path], fset.Position(spec.Pos()))
- }
- if path == "C" {
- if isTest {
- return nil, fmt.Errorf("%s: use of cgo in test not supported", filename)
- }
- cg := spec.Doc
- if cg == nil && len(d.Specs) == 1 {
- cg = d.Doc
- }
- if cg != nil {
- if err := ctxt.saveCgo(filename, &di, cg); err != nil {
- return nil, err
- }
- }
- isCgo = true
- }
- }
- }
- if isCgo {
- if ctxt.CgoEnabled {
- di.CgoFiles = append(di.CgoFiles, name)
- }
- } else if isTest {
- if pkg == string(pf.Name.Name) {
- di.TestGoFiles = append(di.TestGoFiles, name)
- } else {
- di.XTestGoFiles = append(di.XTestGoFiles, name)
- }
- } else {
- di.GoFiles = append(di.GoFiles, name)
- }
- }
- if di.Package == "" {
- return nil, fmt.Errorf("%s: no Go source files", dir)
- }
- di.Imports = make([]string, len(imported))
- di.ImportPos = imported
- i := 0
- for p := range imported {
- di.Imports[i] = p
- i++
- }
- di.TestImports = make([]string, len(testImported))
- di.TestImportPos = testImported
- i = 0
- for p := range testImported {
- 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)
- return &di, nil
-}
-
-var slashslash = []byte("//")
-
-// shouldBuild reports whether it is okay to use this file,
-// The rule is that in the file's leading run of // comments
-// and blank lines, which must be followed by a blank line
-// (to avoid including a Go package clause doc comment),
-// lines beginning with '// +build' are taken as build directives.
-//
-// The file is accepted only if each such line lists something
-// matching the file. For example:
-//
-// // +build windows linux
-//
-// marks the file as applicable only on Windows and Linux.
-//
-func (ctxt *Context) shouldBuild(content []byte) bool {
- // Pass 1. Identify leading run of // comments and blank lines,
- // which must be followed by a blank line.
- end := 0
- p := content
- for len(p) > 0 {
- line := p
- if i := bytes.IndexByte(line, '\n'); i >= 0 {
- line, p = line[:i], p[i+1:]
- } else {
- p = p[len(p):]
- }
- line = bytes.TrimSpace(line)
- if len(line) == 0 { // Blank line
- end = cap(content) - cap(line) // &line[0] - &content[0]
- continue
- }
- if !bytes.HasPrefix(line, slashslash) { // Not comment line
- break
- }
- }
- content = content[:end]
-
- // Pass 2. Process each line in the run.
- p = content
- for len(p) > 0 {
- line := p
- if i := bytes.IndexByte(line, '\n'); i >= 0 {
- line, p = line[:i], p[i+1:]
- } else {
- p = p[len(p):]
- }
- line = bytes.TrimSpace(line)
- if bytes.HasPrefix(line, slashslash) {
- line = bytes.TrimSpace(line[len(slashslash):])
- if len(line) > 0 && line[0] == '+' {
- // Looks like a comment +line.
- f := strings.Fields(string(line))
- if f[0] == "+build" {
- ok := false
- for _, tok := range f[1:] {
- if ctxt.match(tok) {
- ok = true
- break
- }
- }
- if !ok {
- return false // this one doesn't match
- }
- }
- }
- }
- }
- return true // everything matches
-}
-
-// saveCgo saves the information from the #cgo lines in the import "C" comment.
-// These lines set CFLAGS and LDFLAGS and pkg-config directives that affect
-// the way cgo's C code is built.
-//
-// TODO(rsc): This duplicates code in cgo.
-// Once the dust settles, remove this code from cgo.
-func (ctxt *Context) saveCgo(filename string, di *DirInfo, cg *ast.CommentGroup) error {
- text := cg.Text()
- for _, line := range strings.Split(text, "\n") {
- orig := line
-
- // Line is
- // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
- //
- line = strings.TrimSpace(line)
- if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
- continue
- }
-
- // Split at colon.
- line = strings.TrimSpace(line[4:])
- i := strings.Index(line, ":")
- if i < 0 {
- return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
- }
- line, argstr := line[:i], line[i+1:]
-
- // Parse GOOS/GOARCH stuff.
- f := strings.Fields(line)
- if len(f) < 1 {
- return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
- }
-
- cond, verb := f[:len(f)-1], f[len(f)-1]
- if len(cond) > 0 {
- ok := false
- for _, c := range cond {
- if ctxt.match(c) {
- ok = true
- break
- }
- }
- if !ok {
- continue
- }
- }
-
- args, err := splitQuoted(argstr)
- if err != nil {
- return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
- }
- for _, arg := range args {
- if !safeName(arg) {
- return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
- }
- }
-
- switch verb {
- case "CFLAGS":
- di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
- case "LDFLAGS":
- di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
- case "pkg-config":
- di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
- default:
- return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
- }
- }
- return nil
-}
-
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
-
-func safeName(s string) bool {
- if s == "" {
- return false
- }
- for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
- return false
- }
- }
- return true
-}
-
-// splitQuoted splits the string s around each instance of one or more consecutive
-// white space characters while taking into account quotes and escaping, and
-// returns an array of substrings of s or an empty list if s contains only white space.
-// Single quotes and double quotes are recognized to prevent splitting within the
-// quoted region, and are removed from the resulting substrings. If a quote in s
-// isn't closed err will be set and r will have the unclosed argument as the
-// last element. The backslash is used for escaping.
-//
-// For example, the following string:
-//
-// a b:"c d" 'e''f' "g\""
-//
-// Would be parsed as:
-//
-// []string{"a", "b:c d", "ef", `g"`}
-//
-func splitQuoted(s string) (r []string, err error) {
- var args []string
- arg := make([]rune, len(s))
- escaped := false
- quoted := false
- quote := '\x00'
- i := 0
- for _, rune := range s {
- switch {
- case escaped:
- escaped = false
- case rune == '\\':
- escaped = true
- continue
- case quote != '\x00':
- if rune == quote {
- quote = '\x00'
- continue
- }
- case rune == '"' || rune == '\'':
- quoted = true
- quote = rune
- continue
- case unicode.IsSpace(rune):
- if quoted || i > 0 {
- quoted = false
- args = append(args, string(arg[:i]))
- i = 0
- }
- continue
- }
- arg[i] = rune
- i++
- }
- if quoted || i > 0 {
- args = append(args, string(arg[:i]))
- }
- if quote != 0 {
- err = errors.New("unclosed quote")
- } else if escaped {
- err = errors.New("unfinished escaping")
- }
- return args, err
-}
-
-// match returns true if the name is one of:
-//
-// $GOOS
-// $GOARCH
-// cgo (if cgo is enabled)
-// !cgo (if cgo is disabled)
-// tag (if tag is listed in ctxt.BuildTags)
-// !tag (if tag is not listed in ctxt.BuildTags)
-// a slash-separated list of any of these
-//
-func (ctxt *Context) match(name string) bool {
- if name == "" {
- return false
- }
- if i := strings.Index(name, ","); i >= 0 {
- // comma-separated list
- return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
- }
- if strings.HasPrefix(name, "!!") { // bad syntax, reject always
- return false
- }
- if strings.HasPrefix(name, "!") { // negation
- return !ctxt.match(name[1:])
- }
-
- // Tags must be letters, digits, underscores.
- // Unlike in Go identifiers, all digits is fine (e.g., "386").
- for _, c := range name {
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
- return false
- }
- }
-
- // special tags
- if ctxt.CgoEnabled && name == "cgo" {
- return true
- }
- if name == ctxt.GOOS || name == ctxt.GOARCH {
- return true
- }
-
- // other tags
- for _, tag := range ctxt.BuildTags {
- if tag == name {
- return true
- }
- }
-
- return false
-}
-
-// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
-// suffix which does not match the current system.
-// The recognized name formats are:
-//
-// name_$(GOOS).*
-// name_$(GOARCH).*
-// name_$(GOOS)_$(GOARCH).*
-// name_$(GOOS)_test.*
-// name_$(GOARCH)_test.*
-// name_$(GOOS)_$(GOARCH)_test.*
-//
-func (ctxt *Context) goodOSArchFile(name string) bool {
- if dot := strings.Index(name, "."); dot != -1 {
- name = name[:dot]
- }
- l := strings.Split(name, "_")
- if n := len(l); n > 0 && l[n-1] == "test" {
- l = l[:n-1]
- }
- n := len(l)
- if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
- return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
- }
- if n >= 1 && knownOS[l[n-1]] {
- return l[n-1] == ctxt.GOOS
- }
- if n >= 1 && knownArch[l[n-1]] {
- return l[n-1] == ctxt.GOARCH
- }
- return true
-}
-
-var knownOS = make(map[string]bool)
-var knownArch = make(map[string]bool)
-
-func init() {
- for _, v := range strings.Fields(goosList) {
- knownOS[v] = true
- }
- for _, v := range strings.Fields(goarchList) {
- knownArch[v] = true
- }
-}
diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go
new file mode 100644
index 00000000000..67c26ac7f4f
--- /dev/null
+++ b/libgo/go/go/build/doc.go
@@ -0,0 +1,109 @@
+// 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 build gathers information about Go packages.
+//
+// Go Path
+//
+// The Go path is a list of directory trees containing Go source code.
+// It is consulted to resolve imports that cannot be found in the standard
+// Go tree. The default path is the value of the GOPATH environment
+// variable, interpreted as a path list appropriate to the operating system
+// (on Unix, the variable is a colon-separated string;
+// on Windows, a semicolon-separated string;
+// on Plan 9, a list).
+//
+// Each directory listed in the Go path must have a prescribed structure:
+//
+// The src/ directory holds source code. The path below 'src' determines
+// the import path or executable name.
+//
+// The pkg/ directory holds installed package objects.
+// As in the Go tree, each target operating system and
+// architecture pair has its own subdirectory of pkg
+// (pkg/GOOS_GOARCH).
+//
+// If DIR is a directory listed in the Go path, a package with
+// source in DIR/src/foo/bar can be imported as "foo/bar" and
+// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
+// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
+//
+// The bin/ directory holds compiled commands.
+// Each command is named for its source directory, but only
+// using the final element, not the entire path. That is, the
+// command with source in DIR/src/foo/quux is installed into
+// DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+// so that you can add DIR/bin to your PATH to get at the
+// installed commands.
+//
+// Here's an example directory layout:
+//
+// GOPATH=/home/user/gocode
+//
+// /home/user/gocode/
+// src/
+// foo/
+// bar/ (go code in package bar)
+// x.go
+// quux/ (go code in package main)
+// y.go
+// bin/
+// quux (installed command)
+// pkg/
+// linux_amd64/
+// foo/
+// bar.a (installed package object)
+//
+// Build Constraints
+//
+// A build constraint is a line comment beginning with the directive +build
+// that lists the conditions under which a file should be included in the package.
+// Constraints may appear in any kind of source file (not just Go), but
+// they must be appear near the top of the file, preceded
+// only by blank lines and other line comments.
+//
+// A build constraint is evaluated as the OR of space-separated options;
+// each option evaluates as the AND of its comma-separated terms;
+// and each term is an alphanumeric word or, preceded by !, its negation.
+// That is, the build constraint:
+//
+// // +build linux,386 darwin,!cgo
+//
+// corresponds to the boolean formula:
+//
+// (linux AND 386) OR (darwin AND (NOT cgo))
+//
+// During a particular build, the following words are satisfied:
+//
+// - the target operating system, as spelled by runtime.GOOS
+// - the target architecture, as spelled by runtime.GOARCH
+// - "cgo", if ctxt.CgoEnabled is true
+// - any additional words listed in ctxt.BuildTags
+//
+// If a file's name, after stripping the extension and a possible _test suffix,
+// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
+// system and architecture values, then the file is considered to have an implicit
+// build constraint requiring those terms.
+//
+// To keep a file from being considered for the build:
+//
+// // +build ignore
+//
+// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
+//
+// To build a file only when using cgo, and only on Linux and OS X:
+//
+// // +build linux,cgo darwin,cgo
+//
+// Such a file is usually paired with another file implementing the
+// default functionality for other systems, which in this case would
+// carry the constraint:
+//
+// // +build !linux !darwin !cgo
+//
+// Naming a file dns_windows.go will cause it to be included only when
+// building the package for Windows; similarly, math_386.s will be included
+// only when building the package for 32-bit x86.
+//
+package build
diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go
deleted file mode 100644
index e160ac3b280..00000000000
--- a/libgo/go/go/build/path.go
+++ /dev/null
@@ -1,182 +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 build
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "runtime"
-)
-
-// ToolDir is the directory containing build tools.
-var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
-
-// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
-var Path []*Tree
-
-// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
-type Tree struct {
- Path string
- Goroot bool
-}
-
-func newTree(p string) (*Tree, error) {
- if !filepath.IsAbs(p) {
- return nil, errors.New("must be absolute")
- }
- ep, err := filepath.EvalSymlinks(p)
- if err != nil {
- return nil, err
- }
- return &Tree{Path: ep}, nil
-}
-
-// SrcDir returns the tree's package source directory.
-func (t *Tree) SrcDir() string {
- if t.Goroot {
- return filepath.Join(t.Path, "src", "pkg")
- }
- return filepath.Join(t.Path, "src")
-}
-
-// PkgDir returns the tree's package object directory.
-func (t *Tree) PkgDir() string {
- goos, goarch := runtime.GOOS, runtime.GOARCH
- if e := os.Getenv("GOOS"); e != "" {
- goos = e
- }
- if e := os.Getenv("GOARCH"); e != "" {
- goarch = e
- }
- return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
-}
-
-// BinDir returns the tree's binary executable directory.
-func (t *Tree) BinDir() string {
- if t.Goroot {
- if gobin := os.Getenv("GOBIN"); gobin != "" {
- return filepath.Clean(gobin)
- }
- }
- return filepath.Join(t.Path, "bin")
-}
-
-// HasSrc returns whether the given package's
-// source can be found inside this Tree.
-func (t *Tree) HasSrc(pkg string) bool {
- fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
- if err != nil {
- return false
- }
- return fi.IsDir()
-}
-
-// HasPkg returns whether the given package's
-// object file can be found inside this Tree.
-func (t *Tree) HasPkg(pkg string) bool {
- fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
- if err != nil {
- return false
- }
- return !fi.IsDir()
-}
-
-var (
- 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
-// tree where the package source should be and the package import path.
-func FindTree(path string) (tree *Tree, pkg string, err error) {
- if isLocalPath(path) {
- if path, err = filepath.Abs(path); err != nil {
- return
- }
- if path, err = filepath.EvalSymlinks(path); err != nil {
- return
- }
- for _, t := range Path {
- tpath := t.SrcDir() + string(filepath.Separator)
- if !filepath.HasPrefix(path, tpath) {
- continue
- }
- tree = t
- pkg = filepath.ToSlash(path[len(tpath):])
- return
- }
- err = fmt.Errorf("path %q not inside a GOPATH", path)
- return
- }
- tree = defaultTree
- pkg = filepath.ToSlash(path)
- for _, t := range Path {
- if t.HasSrc(pkg) {
- tree = t
- return
- }
- }
- if tree == nil {
- err = ErrTreeNotFound
- } else {
- err = ErrNotFound
- }
- return
-}
-
-// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
-// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
-func isLocalPath(s string) bool {
- const sep = string(filepath.Separator)
- return s == "." || s == ".." ||
- filepath.HasPrefix(s, sep) ||
- filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
- filepath.VolumeName(s) != ""
-}
-
-var (
- // argument lists used by the build's gc and ld methods
- gcImportArgs []string
- ldImportArgs []string
-
- // default tree for remote packages
- defaultTree *Tree
-)
-
-// set up Path: parse and validate GOROOT and GOPATH variables
-func init() {
- root := runtime.GOROOT()
- t, err := newTree(root)
- if err == nil {
- t.Goroot = true
- Path = []*Tree{t}
- }
-
- for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
- if p == "" {
- continue
- }
- t, err := newTree(p)
- if err != nil {
- continue
- }
-
- Path = append(Path, t)
- gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
- ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
-
- // select first GOPATH entry as default
- if defaultTree == nil {
- defaultTree = t
- }
- }
-
- // use GOROOT if no valid GOPATH specified
- if defaultTree == nil && len(Path) > 0 {
- defaultTree = Path[0]
- }
-}
diff --git a/libgo/go/go/build/pkgtest/pkgtest.go b/libgo/go/go/build/pkgtest/pkgtest.go
deleted file mode 100644
index 08eea1e2bc3..00000000000
--- a/libgo/go/go/build/pkgtest/pkgtest.go
+++ /dev/null
@@ -1,13 +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 pkgtest
-
-import "bytes"
-
-func Foo() *bytes.Buffer {
- return nil
-}
-
-func Sqrt(x float64) float64
diff --git a/libgo/go/go/build/pkgtest/sqrt_386_test.go b/libgo/go/go/build/pkgtest/sqrt_386_test.go
deleted file mode 100644
index 26b483fa0ba..00000000000
--- a/libgo/go/go/build/pkgtest/sqrt_386_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package pkgtest
diff --git a/libgo/go/go/build/pkgtest/sqrt_amd64_test.go b/libgo/go/go/build/pkgtest/sqrt_amd64_test.go
deleted file mode 100644
index 26b483fa0ba..00000000000
--- a/libgo/go/go/build/pkgtest/sqrt_amd64_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package pkgtest
diff --git a/libgo/go/go/build/pkgtest/sqrt_arm_test.go b/libgo/go/go/build/pkgtest/sqrt_arm_test.go
deleted file mode 100644
index 26b483fa0ba..00000000000
--- a/libgo/go/go/build/pkgtest/sqrt_arm_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package pkgtest
diff --git a/libgo/go/go/build/pkgtest/sqrt_test.go b/libgo/go/go/build/pkgtest/sqrt_test.go
deleted file mode 100644
index ee9fd5de688..00000000000
--- a/libgo/go/go/build/pkgtest/sqrt_test.go
+++ /dev/null
@@ -1,9 +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 pkgtest
-
-import "fmt"
-
-var _ = fmt.Printf
diff --git a/libgo/go/go/build/pkgtest/xsqrt_test.go b/libgo/go/go/build/pkgtest/xsqrt_test.go
deleted file mode 100644
index 3898d1dda59..00000000000
--- a/libgo/go/go/build/pkgtest/xsqrt_test.go
+++ /dev/null
@@ -1,9 +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 pkgtest_test
-
-import "pkgtest"
-
-var _ = pkgtest.Foo
diff --git a/libgo/go/go/build/syslist_test.go b/libgo/go/go/build/syslist_test.go
index d27630d758d..9157faf8cb9 100644
--- a/libgo/go/go/build/syslist_test.go
+++ b/libgo/go/go/build/syslist_test.go
@@ -55,7 +55,7 @@ var tests = []GoodFileTest{
func TestGoodOSArch(t *testing.T) {
for _, test := range tests {
- if DefaultContext.goodOSArchFile(test.name) != test.result {
+ if Default.goodOSArchFile(test.name) != test.result {
t.Fatalf("goodOSArchFile(%q) != %v", test.name, test.result)
}
}
diff --git a/libgo/go/go/build/testdata/other/file/file.go b/libgo/go/go/build/testdata/other/file/file.go
new file mode 100644
index 00000000000..bbfd3e9e598
--- /dev/null
+++ b/libgo/go/go/build/testdata/other/file/file.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package file
+
+func F() {}
diff --git a/libgo/go/go/build/testdata/other/main.go b/libgo/go/go/build/testdata/other/main.go
new file mode 100644
index 00000000000..e0904357c92
--- /dev/null
+++ b/libgo/go/go/build/testdata/other/main.go
@@ -0,0 +1,11 @@
+// Test data - not compiled.
+
+package main
+
+import (
+ "./file"
+)
+
+func main() {
+ file.F()
+}
diff --git a/libgo/go/go/doc/reader.go b/libgo/go/go/doc/reader.go
index 3558892ebd0..5eaae37b7de 100644
--- a/libgo/go/go/doc/reader.go
+++ b/libgo/go/go/doc/reader.go
@@ -432,6 +432,17 @@ func (r *reader) readFile(src *ast.File) {
r.readValue(d)
case token.TYPE:
// types are handled individually
+ if len(d.Specs) == 1 && !d.Lparen.IsValid() {
+ // common case: single declaration w/o parentheses
+ // (if a single declaration is parenthesized,
+ // create a new fake declaration below, so that
+ // go/doc type declarations always appear w/o
+ // parentheses)
+ if s, ok := d.Specs[0].(*ast.TypeSpec); ok {
+ r.readType(d, s)
+ }
+ break
+ }
for _, spec := range d.Specs {
if s, ok := spec.(*ast.TypeSpec); ok {
// use an individual (possibly fake) declaration
@@ -439,8 +450,13 @@ func (r *reader) readFile(src *ast.File) {
// gets to (re-)use the declaration documentation
// if there's none associated with the spec itself
fake := &ast.GenDecl{
- Doc: d.Doc,
- TokPos: d.Pos(),
+ Doc: d.Doc,
+ // don't use the existing TokPos because it
+ // will lead to the wrong selection range for
+ // the fake declaration if there are more
+ // than one type in the group (this affects
+ // src/cmd/godoc/godoc.go's posLink_urlFunc)
+ TokPos: s.Pos(),
Tok: token.TYPE,
Specs: []ast.Spec{s},
}
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index c1e61904486..a122baf0879 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -14,6 +14,9 @@ import (
"go/ast"
"go/scanner"
"go/token"
+ "strconv"
+ "strings"
+ "unicode"
)
// The parser structure holds the parser's internal state.
@@ -1913,6 +1916,17 @@ func (p *parser) parseStmt() (s ast.Stmt) {
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
+func isValidImport(lit string) bool {
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ s, _ := strconv.Unquote(lit) // go/scanner returns a legal string literal
+ for _, r := range s {
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return false
+ }
+ }
+ return s != ""
+}
+
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1929,6 +1943,9 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var path *ast.BasicLit
if p.tok == token.STRING {
+ if !isValidImport(p.lit) {
+ p.error(p.pos, "invalid import path: "+p.lit)
+ }
path = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
} else {
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
index a3ee8525de2..93ca3d6aa39 100644
--- a/libgo/go/go/parser/parser_test.go
+++ b/libgo/go/go/parser/parser_test.go
@@ -5,6 +5,7 @@
package parser
import (
+ "fmt"
"go/ast"
"go/token"
"os"
@@ -204,3 +205,48 @@ func TestVarScope(t *testing.T) {
}
}
}
+
+var imports = map[string]bool{
+ `"a"`: true,
+ "`a`": true,
+ `"a/b"`: true,
+ `"a.b"`: true,
+ `"m\x61th"`: true,
+ `"greek/αβ"`: true,
+ `""`: false,
+
+ // Each of these pairs tests both `` vs "" strings
+ // and also use of invalid characters spelled out as
+ // escape sequences and written directly.
+ // For example `"\x00"` tests import "\x00"
+ // while "`\x00`" tests import `<actual-NUL-byte>`.
+ `"\x00"`: false,
+ "`\x00`": false,
+ `"\x7f"`: false,
+ "`\x7f`": false,
+ `"a!"`: false,
+ "`a!`": false,
+ `"a b"`: false,
+ "`a b`": false,
+ `"a\\b"`: false,
+ "`a\\b`": false,
+ "\"`a`\"": false,
+ "`\"a\"`": false,
+ `"\x80\x80"`: false,
+ "`\x80\x80`": false,
+ `"\xFFFD"`: false,
+ "`\xFFFD`": false,
+}
+
+func TestImports(t *testing.T) {
+ for path, isValid := range imports {
+ src := fmt.Sprintf("package p; import %s", path)
+ _, err := ParseFile(fset, "", src, 0)
+ switch {
+ case err != nil && isValid:
+ t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
+ case err == nil && !isValid:
+ t.Errorf("ParseFile(%s): got no error; expected one", src)
+ }
+ }
+}
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index cd5e075c16c..05b4ef59a2d 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -12,6 +12,7 @@ import (
"bytes"
"go/ast"
"go/token"
+ "unicode/utf8"
)
// Other formatting issues:
@@ -82,46 +83,37 @@ func (p *printer) setComment(g *ast.CommentGroup) {
type exprListMode uint
const (
- blankStart exprListMode = 1 << iota // print a blank before a non-empty list
- blankEnd // print a blank after a non-empty list
- commaSep // elements are separated by commas
- commaTerm // list is optionally terminated by a comma
- noIndent // no extra indentation in multi-line lists
+ commaTerm exprListMode = 1 << iota // list is optionally terminated by a comma
+ noIndent // no extra indentation in multi-line lists
)
-// Sets multiLine to true if the identifier list spans multiple lines.
// If indent is set, a multi-line identifier list is indented after the
// first linebreak encountered.
-func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
+func (p *printer) identList(list []*ast.Ident, indent bool) {
// convert into an expression list so we can re-use exprList formatting
xlist := make([]ast.Expr, len(list))
for i, x := range list {
xlist[i] = x
}
- mode := commaSep
+ var mode exprListMode
if !indent {
- mode |= noIndent
+ mode = noIndent
}
- p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
+ p.exprList(token.NoPos, xlist, 1, mode, token.NoPos)
}
// Print a list of expressions. If the list spans multiple
// source lines, the original line breaks are respected between
-// expressions. Sets multiLine to true if the list spans multiple
-// lines.
+// expressions.
//
// TODO(gri) Consider rewriting this to be independent of []ast.Expr
// so that we can use the algorithm for any kind of list
// (e.g., pass list via a channel over which to range).
-func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
+func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos) {
if len(list) == 0 {
return
}
- if mode&blankStart != 0 {
- p.print(blank)
- }
-
prev := p.posFor(prev0)
next := p.posFor(next0)
line := p.lineFor(list[0].Pos())
@@ -131,17 +123,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// all list entries on a single line
for i, x := range list {
if i > 0 {
- if mode&commaSep != 0 {
- // use position of expression following the comma as
- // comma position for correct comment placement
- p.print(x.Pos(), token.COMMA)
- }
- p.print(blank)
+ // use position of expression following the comma as
+ // comma position for correct comment placement
+ p.print(x.Pos(), token.COMMA, blank)
}
- p.expr0(x, depth, multiLine)
- }
- if mode&blankEnd != 0 {
- p.print(blank)
+ p.expr0(x, depth)
}
return
}
@@ -161,7 +147,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
prevBreak := -1 // index of last expression that was followed by a linebreak
if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
ws = ignore
- *multiLine = true
prevBreak = 0
}
@@ -215,15 +200,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
if i > 0 {
needsLinebreak := prevLine < line && prevLine > 0 && line > 0
- if mode&commaSep != 0 {
- // use position of expression following the comma as
- // comma position for correct comment placement, but
- // only if the expression is on the same line
- if !needsLinebreak {
- p.print(x.Pos())
- }
- p.print(token.COMMA)
+ // use position of expression following the comma as
+ // comma position for correct comment placement, but
+ // only if the expression is on the same line
+ if !needsLinebreak {
+ p.print(x.Pos())
}
+ p.print(token.COMMA)
needsBlank := true
if needsLinebreak {
// lines are broken using newlines so comments remain aligned
@@ -231,7 +214,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// the same line in which case formfeed is used
if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
ws = ignore
- *multiLine = true
prevBreak = i
needsBlank = false // we got a line break instead
}
@@ -245,11 +227,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// we have a key:value expression that fits onto one line and
// is in a list with more then one entry: use a column for the
// key such that consecutive entries can align if possible
- p.expr(pair.Key, multiLine)
+ p.expr(pair.Key)
p.print(pair.Colon, token.COLON, vtab)
- p.expr(pair.Value, multiLine)
+ p.expr(pair.Value)
} else {
- p.expr0(x, depth, multiLine)
+ p.expr0(x, depth)
}
}
@@ -264,18 +246,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
return
}
- if mode&blankEnd != 0 {
- p.print(blank)
- }
-
if ws == ignore && mode&noIndent == 0 {
// unindent if we indented
p.print(unindent)
}
}
-// Sets multiLine to true if the the parameter list spans multiple lines.
-func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
+func (p *printer) parameters(fields *ast.FieldList) {
p.print(fields.Opening, token.LPAREN)
if len(fields.List) > 0 {
prevLine := p.lineFor(fields.Opening)
@@ -306,7 +283,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) {
// break line if the opening "(" or previous parameter ended on a different line
ws = ignore
- *multiLine = true
} else if i > 0 {
p.print(blank)
}
@@ -318,11 +294,11 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
// again at the end (and still ws == indent). Thus, a subsequent indent
// by a linebreak call after a type, or in the next multi-line identList
// will do the right thing.
- p.identList(par.Names, ws == indent, multiLine)
+ p.identList(par.Names, ws == indent)
p.print(blank)
}
// parameter type
- p.expr(par.Type, multiLine)
+ p.expr(par.Type)
prevLine = parLineEnd
}
// if the closing ")" is on a separate line from the last parameter,
@@ -339,27 +315,26 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Closing, token.RPAREN)
}
-// Sets multiLine to true if the signature spans multiple lines.
-func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
- p.parameters(params, multiLine)
+func (p *printer) signature(params, result *ast.FieldList) {
+ p.parameters(params)
n := result.NumFields()
if n > 0 {
p.print(blank)
if n == 1 && result.List[0].Names == nil {
// single anonymous result; no ()'s
- p.expr(result.List[0].Type, multiLine)
+ p.expr(result.List[0].Type)
return
}
- p.parameters(result, multiLine)
+ p.parameters(result)
}
}
func identListSize(list []*ast.Ident, maxSize int) (size int) {
for i, x := range list {
if i > 0 {
- size += 2 // ", "
+ size += len(", ")
}
- size += len(x.Name)
+ size += utf8.RuneCountInString(x.Name)
if size >= maxSize {
break
}
@@ -389,6 +364,10 @@ func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
}
+func (p *printer) isMultiLine(n ast.Node) bool {
+ return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1
+}
+
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
@@ -412,12 +391,12 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
// no comments so no need for comma position
p.print(token.COMMA, blank)
}
- p.expr(x, ignoreMultiLine)
+ p.expr(x)
}
if len(f.Names) > 0 {
p.print(blank)
}
- p.expr(f.Type, ignoreMultiLine)
+ p.expr(f.Type)
p.print(blank, rbrace, token.RBRACE)
return
}
@@ -435,23 +414,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) == 1 {
sep = blank
}
- var ml bool
+ newSection := false
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
- ml = false
extraTabs := 0
p.setComment(f.Doc)
if len(f.Names) > 0 {
// named fields
- p.identList(f.Names, false, &ml)
+ p.identList(f.Names, false)
p.print(sep)
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
extraTabs = 1
} else {
// anonymous field
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
extraTabs = 2
}
if f.Tag != nil {
@@ -459,7 +437,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
p.print(sep)
}
p.print(sep)
- p.expr(f.Tag, &ml)
+ p.expr(f.Tag)
extraTabs = 0
}
if f.Comment != nil {
@@ -468,6 +446,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
}
p.setComment(f.Comment)
}
+ newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -479,22 +458,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
} else { // interface
- var ml bool
+ newSection := false
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
- ml = false
p.setComment(f.Doc)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method
- p.expr(f.Names[0], &ml)
- p.signature(ftyp.Params, ftyp.Results, &ml)
+ p.expr(f.Names[0])
+ p.signature(ftyp.Params, ftyp.Results)
} else {
// embedded interface
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
}
p.setComment(f.Comment)
+ newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -635,15 +614,14 @@ func reduceDepth(depth int) int {
// cutoff is 6 (always use spaces) in Normal mode
// and 4 (never use spaces) in Compact mode.
//
-// Sets multiLine to true if the binary expression spans multiple lines.
-func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
+func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
prec := x.Op.Precedence()
if prec < prec1 {
// parenthesis needed
// Note: The parser inserts an ast.ParenExpr node; thus this case
// can only occur if the AST is created in a different way.
p.print(token.LPAREN)
- p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth
p.print(token.RPAREN)
return
}
@@ -651,7 +629,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
printBlank := prec < cutoff
ws := indent
- p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
+ p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
if printBlank {
p.print(blank)
}
@@ -663,14 +641,13 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
// in the source
if p.linebreak(yline, 1, ws, true) {
ws = ignore
- *multiLine = true
printBlank = false // no blank after line break
}
}
if printBlank {
p.print(blank)
}
- p.expr1(x.Y, prec+1, depth+1, multiLine)
+ p.expr1(x.Y, prec+1, depth+1)
if ws == ignore {
p.print(unindent)
}
@@ -681,8 +658,7 @@ func isBinary(expr ast.Expr) bool {
return ok
}
-// Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
+func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.print(expr.Pos())
switch x := expr.(type) {
@@ -697,12 +673,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.internalError("depth < 1:", depth)
depth = 1
}
- p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
+ p.binaryExpr(x, prec1, cutoff(x, depth), depth)
case *ast.KeyValueExpr:
- p.expr(x.Key, multiLine)
+ p.expr(x.Key)
p.print(x.Colon, token.COLON, blank)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
case *ast.StarExpr:
const prec = token.UnaryPrec
@@ -710,12 +686,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// parenthesis needed
p.print(token.LPAREN)
p.print(token.MUL)
- p.expr(x.X, multiLine)
+ p.expr(x.X)
p.print(token.RPAREN)
} else {
// no parenthesis needed
p.print(token.MUL)
- p.expr(x.X, multiLine)
+ p.expr(x.X)
}
case *ast.UnaryExpr:
@@ -723,7 +699,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if prec < prec1 {
// parenthesis needed
p.print(token.LPAREN)
- p.expr(x, multiLine)
+ p.expr(x)
p.print(token.RPAREN)
} else {
// no parenthesis needed
@@ -732,42 +708,41 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// TODO(gri) Remove this code if it cannot be reached.
p.print(blank)
}
- p.expr1(x.X, prec, depth, multiLine)
+ p.expr1(x.X, prec, depth)
}
case *ast.BasicLit:
p.print(x)
case *ast.FuncLit:
- p.expr(x.Type, multiLine)
- p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
+ p.expr(x.Type)
+ p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true)
case *ast.ParenExpr:
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
// don't print parentheses around an already parenthesized expression
// TODO(gri) consider making this more general and incorporate precedence levels
- p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
} else {
p.print(token.LPAREN)
- p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
p.print(x.Rparen, token.RPAREN)
}
case *ast.SelectorExpr:
- p.expr1(x.X, token.HighestPrec, depth, multiLine)
+ p.expr1(x.X, token.HighestPrec, depth)
p.print(token.PERIOD)
if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent)
- *multiLine = true
} else {
p.print(x.Sel.Pos(), x.Sel)
}
case *ast.TypeAssertExpr:
- p.expr1(x.X, token.HighestPrec, depth, multiLine)
+ p.expr1(x.X, token.HighestPrec, depth)
p.print(token.PERIOD, token.LPAREN)
if x.Type != nil {
- p.expr(x.Type, multiLine)
+ p.expr(x.Type)
} else {
p.print(token.TYPE)
}
@@ -775,17 +750,17 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.IndexExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
- p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
- p.expr0(x.Index, depth+1, multiLine)
+ p.expr0(x.Index, depth+1)
p.print(x.Rbrack, token.RBRACK)
case *ast.SliceExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
- p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
if x.Low != nil {
- p.expr0(x.Low, depth+1, multiLine)
+ p.expr0(x.Low, depth+1)
}
// blanks around ":" if both sides exist and either side is a binary expression
if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
@@ -794,7 +769,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.COLON)
}
if x.High != nil {
- p.expr0(x.High, depth+1, multiLine)
+ p.expr0(x.High, depth+1)
}
p.print(x.Rbrack, token.RBRACK)
@@ -802,21 +777,26 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if len(x.Args) > 1 {
depth++
}
- p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
+ p.expr1(x.Fun, token.HighestPrec, depth)
p.print(x.Lparen, token.LPAREN)
- p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
if x.Ellipsis.IsValid() {
+ p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis)
p.print(x.Ellipsis, token.ELLIPSIS)
+ if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
+ p.print(token.COMMA, formfeed)
+ }
+ } else {
+ p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen)
}
p.print(x.Rparen, token.RPAREN)
case *ast.CompositeLit:
// composite literal elements that are composite literals themselves may have the type omitted
if x.Type != nil {
- p.expr1(x.Type, token.HighestPrec, depth, multiLine)
+ p.expr1(x.Type, token.HighestPrec, depth)
}
p.print(x.Lbrace, token.LBRACE)
- p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
+ p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
// do not insert extra line breaks because of comments before
// the closing '}' as it might break the code if there is no
// trailing ','
@@ -825,16 +805,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
if x.Elt != nil {
- p.expr(x.Elt, multiLine)
+ p.expr(x.Elt)
}
case *ast.ArrayType:
p.print(token.LBRACK)
if x.Len != nil {
- p.expr(x.Len, multiLine)
+ p.expr(x.Len)
}
p.print(token.RBRACK)
- p.expr(x.Elt, multiLine)
+ p.expr(x.Elt)
case *ast.StructType:
p.print(token.STRUCT)
@@ -842,7 +822,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.FuncType:
p.print(token.FUNC)
- p.signature(x.Params, x.Results, multiLine)
+ p.signature(x.Params, x.Results)
case *ast.InterfaceType:
p.print(token.INTERFACE)
@@ -850,9 +830,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.MapType:
p.print(token.MAP, token.LBRACK)
- p.expr(x.Key, multiLine)
+ p.expr(x.Key)
p.print(token.RBRACK)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
case *ast.ChanType:
switch x.Dir {
@@ -864,7 +844,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.CHAN, token.ARROW)
}
p.print(blank)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
default:
panic("unreachable")
@@ -873,14 +853,13 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
return
}
-func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
- p.expr1(x, token.LowestPrec, depth, multiLine)
+func (p *printer) expr0(x ast.Expr, depth int) {
+ p.expr1(x, token.LowestPrec, depth)
}
-// Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr(x ast.Expr, multiLine *bool) {
+func (p *printer) expr(x ast.Expr) {
const depth = 1
- p.expr1(x, token.LowestPrec, depth, multiLine)
+ p.expr1(x, token.LowestPrec, depth)
}
// ----------------------------------------------------------------------------
@@ -894,13 +873,13 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
if _indent > 0 {
p.print(indent)
}
- var multiLine bool
+ multiLine := false
for i, s := range list {
// _indent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine)
- multiLine = false
- p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
+ p.stmt(s, nextIsRBrace && i == len(list)-1)
+ multiLine = p.isMultiLine(s)
}
if _indent > 0 {
p.print(unindent)
@@ -957,25 +936,25 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
if init == nil && post == nil {
// no semicolons required
if expr != nil {
- p.expr(stripParens(expr), ignoreMultiLine)
+ p.expr(stripParens(expr))
needsBlank = true
}
} else {
// all semicolons required
// (they are not separators, print them explicitly)
if init != nil {
- p.stmt(init, false, ignoreMultiLine)
+ p.stmt(init, false)
}
p.print(token.SEMICOLON, blank)
if expr != nil {
- p.expr(stripParens(expr), ignoreMultiLine)
+ p.expr(stripParens(expr))
needsBlank = true
}
if isForStmt {
p.print(token.SEMICOLON, blank)
needsBlank = false
if post != nil {
- p.stmt(post, false, ignoreMultiLine)
+ p.stmt(post, false)
needsBlank = true
}
}
@@ -985,8 +964,7 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
}
-// Sets multiLine to true if the statements spans multiple lines.
-func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
+func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(stmt.Pos())
switch s := stmt.(type) {
@@ -994,7 +972,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print("BadStmt")
case *ast.DeclStmt:
- p.decl(s.Decl, multiLine)
+ p.decl(s.Decl)
case *ast.EmptyStmt:
// nothing to do
@@ -1004,7 +982,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
// is applied before the line break if there is no comment
// between (see writeWhitespace)
p.print(unindent)
- p.expr(s.Label, multiLine)
+ p.expr(s.Label)
p.print(s.Colon, token.COLON, indent)
if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
if !nextIsRBrace {
@@ -1014,21 +992,21 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
} else {
p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
}
- p.stmt(s.Stmt, nextIsRBrace, multiLine)
+ p.stmt(s.Stmt, nextIsRBrace)
case *ast.ExprStmt:
const depth = 1
- p.expr0(s.X, depth, multiLine)
+ p.expr0(s.X, depth)
case *ast.SendStmt:
const depth = 1
- p.expr0(s.Chan, depth, multiLine)
+ p.expr0(s.Chan, depth)
p.print(blank, s.Arrow, token.ARROW, blank)
- p.expr0(s.Value, depth, multiLine)
+ p.expr0(s.Value, depth)
case *ast.IncDecStmt:
const depth = 1
- p.expr0(s.X, depth+1, multiLine)
+ p.expr0(s.X, depth+1)
p.print(s.TokPos, s.Tok)
case *ast.AssignStmt:
@@ -1036,56 +1014,55 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
depth++
}
- p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
- p.print(blank, s.TokPos, s.Tok)
- p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
+ p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos)
+ p.print(blank, s.TokPos, s.Tok, blank)
+ p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos)
case *ast.GoStmt:
p.print(token.GO, blank)
- p.expr(s.Call, multiLine)
+ p.expr(s.Call)
case *ast.DeferStmt:
p.print(token.DEFER, blank)
- p.expr(s.Call, multiLine)
+ p.expr(s.Call)
case *ast.ReturnStmt:
p.print(token.RETURN)
if s.Results != nil {
- p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(blank)
+ p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos)
}
case *ast.BranchStmt:
p.print(s.Tok)
if s.Label != nil {
p.print(blank)
- p.expr(s.Label, multiLine)
+ p.expr(s.Label)
}
case *ast.BlockStmt:
p.block(s, 1)
- *multiLine = true
case *ast.IfStmt:
p.print(token.IF)
p.controlClause(false, s.Init, s.Cond, nil)
p.block(s.Body, 1)
- *multiLine = true
if s.Else != nil {
p.print(blank, token.ELSE, blank)
switch s.Else.(type) {
case *ast.BlockStmt, *ast.IfStmt:
- p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
+ p.stmt(s.Else, nextIsRBrace)
default:
p.print(token.LBRACE, indent, formfeed)
- p.stmt(s.Else, true, ignoreMultiLine)
+ p.stmt(s.Else, true)
p.print(unindent, formfeed, token.RBRACE)
}
}
case *ast.CaseClause:
if s.List != nil {
- p.print(token.CASE)
- p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
+ p.print(token.CASE, blank)
+ p.exprList(s.Pos(), s.List, 1, 0, s.Colon)
} else {
p.print(token.DEFAULT)
}
@@ -1096,25 +1073,23 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(token.SWITCH)
p.controlClause(false, s.Init, s.Tag, nil)
p.block(s.Body, 0)
- *multiLine = true
case *ast.TypeSwitchStmt:
p.print(token.SWITCH)
if s.Init != nil {
p.print(blank)
- p.stmt(s.Init, false, ignoreMultiLine)
+ p.stmt(s.Init, false)
p.print(token.SEMICOLON)
}
p.print(blank)
- p.stmt(s.Assign, false, ignoreMultiLine)
+ p.stmt(s.Assign, false)
p.print(blank)
p.block(s.Body, 0)
- *multiLine = true
case *ast.CommClause:
if s.Comm != nil {
p.print(token.CASE, blank)
- p.stmt(s.Comm, false, ignoreMultiLine)
+ p.stmt(s.Comm, false)
} else {
p.print(token.DEFAULT)
}
@@ -1129,29 +1104,26 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
} else {
p.block(body, 0)
- *multiLine = true
}
case *ast.ForStmt:
p.print(token.FOR)
p.controlClause(true, s.Init, s.Cond, s.Post)
p.block(s.Body, 1)
- *multiLine = true
case *ast.RangeStmt:
p.print(token.FOR, blank)
- p.expr(s.Key, multiLine)
+ p.expr(s.Key)
if s.Value != nil {
// use position of value following the comma as
// comma position for correct comment placement
p.print(s.Value.Pos(), token.COMMA, blank)
- p.expr(s.Value, multiLine)
+ p.expr(s.Value)
}
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
- p.expr(stripParens(s.X), multiLine)
+ p.expr(stripParens(s.X))
p.print(blank)
p.block(s.Body, 1)
- *multiLine = true
default:
panic("unreachable")
@@ -1228,20 +1200,20 @@ func keepTypeColumn(specs []ast.Spec) []bool {
return m
}
-func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool) {
p.setComment(s.Doc)
- p.identList(s.Names, doIndent, multiLine) // always present
+ p.identList(s.Names, doIndent) // always present
extraTabs := 3
if s.Type != nil || keepType {
p.print(vtab)
extraTabs--
}
if s.Type != nil {
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
}
if s.Values != nil {
- p.print(vtab, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(vtab, token.ASSIGN, blank)
+ p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos)
extraTabs--
}
if s.Comment != nil {
@@ -1255,17 +1227,16 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
// The parameter n is the number of specs in the group. If doIndent is set,
// multi-line identifier lists in the spec are indented when the first
// linebreak is encountered.
-// Sets multiLine to true if the spec spans multiple lines.
//
-func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
switch s := spec.(type) {
case *ast.ImportSpec:
p.setComment(s.Doc)
if s.Name != nil {
- p.expr(s.Name, multiLine)
+ p.expr(s.Name)
p.print(blank)
}
- p.expr(s.Path, multiLine)
+ p.expr(s.Path)
p.setComment(s.Comment)
p.print(s.EndPos)
@@ -1274,26 +1245,26 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
p.internalError("expected n = 1; got", n)
}
p.setComment(s.Doc)
- p.identList(s.Names, doIndent, multiLine) // always present
+ p.identList(s.Names, doIndent) // always present
if s.Type != nil {
p.print(blank)
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
}
if s.Values != nil {
- p.print(blank, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(blank, token.ASSIGN, blank)
+ p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos)
}
p.setComment(s.Comment)
case *ast.TypeSpec:
p.setComment(s.Doc)
- p.expr(s.Name, multiLine)
+ p.expr(s.Name)
if n == 1 {
p.print(blank)
} else {
p.print(vtab)
}
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
p.setComment(s.Comment)
default:
@@ -1301,8 +1272,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
}
}
-// Sets multiLine to true if the declaration spans multiple lines.
-func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
+func (p *printer) genDecl(d *ast.GenDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), d.Tok, blank)
@@ -1315,32 +1285,31 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
// two or more grouped const/var declarations:
// determine if the type column must be kept
keepType := keepTypeColumn(d.Specs)
- var ml bool
+ newSection := false
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
- ml = false
- p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
+ p.valueSpec(s.(*ast.ValueSpec), keepType[i], false)
+ newSection = p.isMultiLine(s)
}
} else {
- var ml bool
+ newSection := false
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
- ml = false
- p.spec(s, n, false, &ml)
+ p.spec(s, n, false)
+ newSection = p.isMultiLine(s)
}
}
p.print(unindent, formfeed)
- *multiLine = true
}
p.print(d.Rparen, token.RPAREN)
} else {
// single declaration
- p.spec(d.Specs[0], 1, true, multiLine)
+ p.spec(d.Specs[0], 1, true)
}
}
@@ -1404,8 +1373,7 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
return headerSize+bodySize <= maxSize
}
-// Sets multiLine to true if the function body spans multiple lines.
-func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
+func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) {
if b == nil {
return
}
@@ -1422,7 +1390,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
if i > 0 {
p.print(token.SEMICOLON, blank)
}
- p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
+ p.stmt(s, i == len(b.List)-1)
}
p.print(blank)
}
@@ -1432,7 +1400,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
p.print(blank)
p.block(b, 1)
- *multiLine = true
}
// distance returns the column difference between from and to if both
@@ -1446,28 +1413,26 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int {
return infinity
}
-// Sets multiLine to true if the declaration spans multiple lines.
-func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
+func (p *printer) funcDecl(d *ast.FuncDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), token.FUNC, blank)
if d.Recv != nil {
- p.parameters(d.Recv, multiLine) // method: print receiver
+ p.parameters(d.Recv) // method: print receiver
p.print(blank)
}
- p.expr(d.Name, multiLine)
- p.signature(d.Type.Params, d.Type.Results, multiLine)
- p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
+ p.expr(d.Name)
+ p.signature(d.Type.Params, d.Type.Results)
+ p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false)
}
-// Sets multiLine to true if the declaration spans multiple lines.
-func (p *printer) decl(decl ast.Decl, multiLine *bool) {
+func (p *printer) decl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.BadDecl:
p.print(d.Pos(), "BadDecl")
case *ast.GenDecl:
- p.genDecl(d, multiLine)
+ p.genDecl(d)
case *ast.FuncDecl:
- p.funcDecl(d, multiLine)
+ p.funcDecl(d)
default:
panic("unreachable")
}
@@ -1490,7 +1455,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
- p.expr(src.Name, ignoreMultiLine)
+ p.expr(src.Name)
if len(src.Decls) > 0 {
tok := token.ILLEGAL
@@ -1509,7 +1474,7 @@ func (p *printer) file(src *ast.File) {
min = 2
}
p.linebreak(p.lineFor(d.Pos()), min, ignore, false)
- p.decl(d, ignoreMultiLine)
+ p.decl(d)
}
}
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index 72f65a1d852..a027d32da89 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -34,9 +34,6 @@ const (
unindent = whiteSpace('<')
)
-// Use ignoreMultiLine if the multiLine information is not important.
-var ignoreMultiLine = new(bool)
-
// A pmode value represents the current printer mode.
type pmode int
@@ -280,10 +277,9 @@ func (p *printer) writeString(pos token.Position, s string, isLit bool) {
// it as is likely to help position the comment nicely.
// pos is the comment position, next the position of the item
// after all pending comments, prev is the previous comment in
-// a group of comments (or nil), and isKeyword indicates if the
-// next item is a keyword.
+// a group of comments (or nil), and tok is the next token.
//
-func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, isKeyword bool) {
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, tok token.Token) {
if len(p.output) == 0 {
// the comment is the first item to be printed - don't write any whitespace
return
@@ -338,38 +334,41 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
// 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
- for i, ch := range p.wsbuf {
- switch ch {
- case blank, vtab:
- // ignore any horizontal whitespace before line breaks
- p.wsbuf[i] = ignore
+ j := 0
+ for i, ch := range p.wsbuf {
+ switch ch {
+ case blank, vtab:
+ // ignore any horizontal whitespace before line breaks
+ p.wsbuf[i] = ignore
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ case unindent:
+ // if this is not the last unindent, apply it
+ // as it is (likely) belonging to the last
+ // construct (e.g., a multi-line expression list)
+ // and is not part of closing a block
+ if i+1 < len(p.wsbuf) && p.wsbuf[i+1] == unindent {
continue
- case indent:
- // apply pending indentation
+ }
+ // if the next token is not a closing }, apply the unindent
+ // if it appears that the comment is aligned with the
+ // token; otherwise assume the unindent is part of a
+ // closing block and stop (this scenario appears with
+ // comments before a case label where the comments
+ // apply to the next case instead of the current one)
+ if tok != token.RBRACE && pos.Column == next.Column {
continue
- case unindent:
- // if the next token is a keyword, apply the outdent
- // if it appears that the comment is aligned with the
- // keyword; otherwise assume the outdent is part of a
- // closing block and stop (this scenario appears with
- // comments before a case label where the comments
- // apply to the next case instead of the current one)
- if isKeyword && pos.Column == next.Column {
- continue
- }
- case newline, formfeed:
- // TODO(gri): may want to keep formfeed info in some cases
- p.wsbuf[i] = ignore
- droppedLinebreak = true
}
- j = i
- break
+ case newline, formfeed:
+ p.wsbuf[i] = ignore
+ droppedLinebreak = prev == nil // record only if first comment of a group
}
- p.writeWhitespace(j)
+ j = i
+ break
}
+ p.writeWhitespace(j)
// determine number of linebreaks before the comment
n := 0
@@ -678,7 +677,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
var last *ast.Comment
for p.commentBefore(next) {
for _, c := range p.comment.List {
- p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok.IsKeyword())
+ p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok)
p.writeComment(c)
last = c
}
@@ -1011,18 +1010,18 @@ func (p *printer) printNode(node interface{}) error {
// format node
switch n := node.(type) {
case ast.Expr:
- p.expr(n, ignoreMultiLine)
+ p.expr(n)
case ast.Stmt:
// A labeled statement will un-indent to position the
// label. Set indent to 1 so we don't get indent "underflow".
if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
p.indent = 1
}
- p.stmt(n, false, ignoreMultiLine)
+ p.stmt(n, false)
case ast.Decl:
- p.decl(n, ignoreMultiLine)
+ p.decl(n)
case ast.Spec:
- p.spec(n, 1, false, ignoreMultiLine)
+ p.spec(n, 1, false)
case *ast.File:
p.file(n)
default:
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 2d4f61356c1..497d671f240 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -154,15 +154,12 @@ var data = []entry{
}
func TestFiles(t *testing.T) {
- for i, e := range data {
+ for _, e := range data {
source := filepath.Join(dataDir, e.source)
golden := filepath.Join(dataDir, e.golden)
check(t, source, golden, e.mode)
// TODO(gri) check that golden is idempotent
//check(t, golden, golden, e.mode)
- if testing.Short() && i >= 3 {
- break
- }
}
}
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index 4c6f1ab8274..d9aa2d82f7d 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -168,6 +168,91 @@ func typeswitch(x interface{}) {
// this comment should not be indented
}
+//
+// Indentation of comments after possibly indented multi-line constructs
+// (test cases for issue 3147).
+//
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+ _ = 0
+}
+
+// Test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // should be aligned with f()
+ f()
+}
+
+// Modified test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // may not be aligned with f() (source is not aligned)
+ f()
+}
+
+//
+// Test cases for alignment of lines in general comments.
+//
+
func _() {
/* freestanding comment
aligned line
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index c0f8cca3a92..6084b3fe450 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -171,6 +171,91 @@ func typeswitch(x interface{}) {
// this comment should not be indented
}
+//
+// Indentation of comments after possibly indented multi-line constructs
+// (test cases for issue 3147).
+//
+
+func _() {
+ s := 1 +
+ 2
+// should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+// should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+ _ = 0
+}
+
+// Test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // should be aligned with f()
+ f()
+}
+
+// Modified test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // may not be aligned with f() (source is not aligned)
+ f()
+}
+
+//
+// Test cases for alignment of lines in general comments.
+//
+
func _() {
/* freestanding comment
aligned line
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
index 928b8ce0a9f..7ed7cb61ae5 100644
--- a/libgo/go/go/printer/testdata/declarations.golden
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -83,13 +83,13 @@ import (
// more import examples
import (
"xxx"
- "much longer name" // comment
- "short name" // comment
+ "much_longer_name" // comment
+ "short_name" // comment
)
import (
_ "xxx"
- "much longer name" // comment
+ "much_longer_name" // comment
)
import (
@@ -500,7 +500,7 @@ type _ struct {
type _ struct {
a, b,
- c, d int // this line should be indented
+ c, d int // this line should be indented
u, v, w, x float // this line should be indented
p, q,
r, s float // this line should be indented
@@ -562,7 +562,7 @@ var a2, b2,
var (
a3, b3,
- c3, d3 int // this line should be indented
+ c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented
)
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
index 68f90308a36..df8c2b167e1 100644
--- a/libgo/go/go/printer/testdata/declarations.input
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -84,13 +84,13 @@ import (
// more import examples
import (
"xxx"
- "much longer name" // comment
- "short name" // comment
+ "much_longer_name" // comment
+ "short_name" // comment
)
import (
_ "xxx"
- "much longer name" // comment
+ "much_longer_name" // comment
)
import (
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index 95fdd95ffbb..45fa4d97a4a 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -625,3 +625,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input
index d1131498352..f545c66057c 100644
--- a/libgo/go/go/printer/testdata/expressions.input
+++ b/libgo/go/go/printer/testdata/expressions.input
@@ -654,3 +654,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index 3442ba9b950..87a4b00836d 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -625,3 +625,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/libgo/go/go/printer/testdata/parser.go b/libgo/go/go/printer/testdata/parser.go
index c85297f5831..dba8bbd4351 100644
--- a/libgo/go/go/printer/testdata/parser.go
+++ b/libgo/go/go/printer/testdata/parser.go
@@ -52,7 +52,7 @@ type parser struct {
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
- // Ordinary identifer scopes
+ // Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
topScope *ast.Scope // top-most scope; may be pkgScope
unresolved []*ast.Ident // unresolved identifiers
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
index 90e1743557d..ffca21edba9 100644
--- a/libgo/go/go/printer/testdata/statements.golden
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -8,6 +8,82 @@ var expr bool
func use(x interface{}) {}
+// Formatting of multi-line return statements.
+func _f() {
+ return
+ return x, y, z
+ return T{}
+ return T{1, 2, 3},
+ x, y, z
+ return T{1, 2, 3},
+ x, y,
+ z
+ return T{1,
+ 2,
+ 3}
+ return T{1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ 3}
+ return T{
+ 1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ T{1, 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2,
+ 3},
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ },
+ nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ },
+ nil
+ return x + y +
+ z
+ return func() {}
+ return func() {
+ _ = 0
+ }, T{
+ 1, 2,
+ }
+ return func() {
+ _ = 0
+ }
+ return func() T {
+ return T{
+ 1, 2,
+ }
+ }
+}
+
// Formatting of if-statement headers.
func _() {
if true {
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
index 86a753c5ad9..99945e9551a 100644
--- a/libgo/go/go/printer/testdata/statements.input
+++ b/libgo/go/go/printer/testdata/statements.input
@@ -8,6 +8,82 @@ var expr bool
func use(x interface{}) {}
+// Formatting of multi-line return statements.
+func _f() {
+ return
+ return x, y, z
+ return T{}
+ return T{1, 2, 3},
+ x, y, z
+ return T{1, 2, 3},
+ x, y,
+ z
+ return T{1,
+ 2,
+ 3}
+ return T{1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ 3}
+ return T{
+ 1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ T{1, 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2,
+ 3},
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ },
+ nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ },
+ nil
+ return x + y +
+ z
+ return func() {}
+ return func() {
+ _ = 0
+ }, T{
+ 1, 2,
+ }
+ return func() {
+ _ = 0
+ }
+ return func() T {
+ return T {
+ 1, 2,
+ }
+ }
+}
+
// Formatting of if-statement headers.
func _() {
if true {}
diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go
index 7f60f3b9680..3699ea1a91c 100644
--- a/libgo/go/html/template/doc.go
+++ b/libgo/go/html/template/doc.go
@@ -19,7 +19,7 @@ to parse and execute HTML templates safely.
tmpl, err := template.New("name").Parse(...)
// Error checking elided
- err = tmpl.Execute(out, "Foo", data)
+ err = tmpl.Execute(out, data)
If successful, tmpl will now be injection-safe. Otherwise, err is an error
defined in the docs for ErrorCode.
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index 02fa3eaad6b..a058e20d7b3 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -593,7 +593,7 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context {
}
}
for j := i; j < end; j++ {
- if s[j] == '<' && !bytes.HasPrefix(s[j:], doctypeBytes) {
+ if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) {
b.Write(s[written:j])
b.WriteString("&lt;")
written = j + 1
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index 70cada3f50b..2bbb1b1bc94 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -223,14 +223,14 @@ func TestEscape(t *testing.T) {
`<button onclick='alert(&quot;\x3cHello\x3e&quot;)'>`,
},
{
- "badMarshaller",
+ "badMarshaler",
`<button onclick='alert(1/{{.B}}in numbers)'>`,
`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character &#39;f&#39; looking for beginning of object key string */null in numbers)'>`,
},
{
- "jsMarshaller",
+ "jsMarshaler",
`<button onclick='alert({{.M}})'>`,
- `<button onclick='alert({&#34;&lt;foo&gt;&#34;:&#34;O&#39;Reilly&#34;})'>`,
+ `<button onclick='alert({&#34;\u003cfoo\u003e&#34;:&#34;O&#39;Reilly&#34;})'>`,
},
{
"jsStrNotUnderEscaped",
@@ -432,6 +432,11 @@ func TestEscape(t *testing.T) {
"<!DOCTYPE html>Hello, World!",
},
{
+ "HTML doctype not case-insensitive",
+ "<!doCtYPE htMl>Hello, World!",
+ "<!doCtYPE htMl>Hello, World!",
+ },
+ {
"No doctype injection",
`<!{{"DOCTYPE"}}`,
"&lt;!DOCTYPE",
diff --git a/libgo/go/html/template/html.go b/libgo/go/html/template/html.go
index 7b77d6531ab..36c88e23e6e 100644
--- a/libgo/go/html/template/html.go
+++ b/libgo/go/html/template/html.go
@@ -134,7 +134,7 @@ var htmlNospaceNormReplacementTable = []string{
'`': "&#96;",
}
-// htmlReplacer returns s with runes replaced acccording to replacementTable
+// htmlReplacer returns s with runes replaced according to replacementTable
// and when badRunes is true, certain bad runes are allowed through unescaped.
func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
written, b := 0, new(bytes.Buffer)
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
index bbfa6c2b2aa..7074834d613 100644
--- a/libgo/go/io/io.go
+++ b/libgo/go/io/io.go
@@ -6,6 +6,10 @@
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
+//
+// Because these interfaces and primitives wrap lower-level operations with
+// various implementations, unless otherwise informed clients should not
+// assume they are safe for parallel execution.
package io
import (
@@ -156,6 +160,9 @@ type WriterTo interface {
// If ReadAt is reading from an input source with a seek offset,
// ReadAt should not affect nor be affected by the underlying
// seek offset.
+//
+// Clients of ReadAt can execute parallel ReadAt calls on the
+// same input source.
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}
diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go
index cf05e0c1ad7..f3f0f175706 100644
--- a/libgo/go/io/pipe.go
+++ b/libgo/go/io/pipe.go
@@ -175,6 +175,10 @@ func (w *PipeWriter) CloseWithError(err error) error {
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
+// It is safe to call Read and Write in parallel with each other or with
+// Close. Close will complete once pending I/O is done. Parallel calls to
+// Read, and parallel calls to Write, are also safe:
+// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := new(pipe)
p.rwait.L = &p.l
diff --git a/libgo/go/math/const.go b/libgo/go/math/const.go
index edb14f6fa43..f1247c383fd 100644
--- a/libgo/go/math/const.go
+++ b/libgo/go/math/const.go
@@ -27,11 +27,11 @@ const (
// Max is the largest finite value representable by the type.
// SmallestNonzero is the smallest positive, non-zero value representable by the type.
const (
- MaxFloat32 = 3.40282346638528859811704183484516925440e+38 /* 2**127 * (2**24 - 1) / 2**23 */
- SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 /* 1 / 2**(127 - 1 + 23) */
+ MaxFloat32 = 3.40282346638528859811704183484516925440e+38 // 2**127 * (2**24 - 1) / 2**23
+ SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 // 1 / 2**(127 - 1 + 23)
- MaxFloat64 = 1.797693134862315708145274237317043567981e+308 /* 2**1023 * (2**53 - 1) / 2**52 */
- SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 /* 1 / 2**(1023 - 1 + 52) */
+ MaxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+ SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 // 1 / 2**(1023 - 1 + 52)
)
// Integer limit values.
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 61b8911fcf9..10ca5faf707 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -69,7 +69,7 @@ func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) {
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
-// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket".
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixpacket".
//
// For TCP and UDP networks, addresses have the form host:port.
// If host is a literal IPv6 address, it must be enclosed
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
index e5a797e13bf..5f5aea146a6 100644
--- a/libgo/go/net/dial_test.go
+++ b/libgo/go/net/dial_test.go
@@ -5,6 +5,8 @@
package net
import (
+ "flag"
+ "regexp"
"runtime"
"testing"
"time"
@@ -128,3 +130,82 @@ func TestSelfConnect(t *testing.T) {
}
}
}
+
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+
+type DialErrorTest struct {
+ Net string
+ Raddr string
+ Pattern string
+}
+
+var dialErrorTests = []DialErrorTest{
+ {
+ "datakit", "mh/astro/r70",
+ "dial datakit mh/astro/r70: unknown network datakit",
+ },
+ {
+ "tcp", "127.0.0.1:☺",
+ "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+ },
+ {
+ "tcp", "no-such-name.google.com.:80",
+ "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name.no-such-top-level-domain.:80",
+ "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name:80",
+ `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+ },
+ {
+ "tcp", "mh/astro/r70:http",
+ "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+ },
+ {
+ "unix", "/etc/file-not-found",
+ "dial unix /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unix", "/etc/",
+ "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+ {
+ "unixpacket", "/etc/file-not-found",
+ "dial unixpacket /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unixpacket", "/etc/",
+ "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+}
+
+var duplicateErrorPattern = `dial (.*) dial (.*)`
+
+func TestDialError(t *testing.T) {
+ if !*runErrorTest {
+ t.Logf("test disabled; use -run_error_test to enable")
+ return
+ }
+ for i, tt := range dialErrorTests {
+ c, err := Dial(tt.Net, tt.Raddr)
+ if c != nil {
+ c.Close()
+ }
+ if err == nil {
+ t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+ continue
+ }
+ s := err.Error()
+ match, _ := regexp.MatchString(tt.Pattern, s)
+ if !match {
+ t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+ }
+ match, _ = regexp.MatchString(duplicateErrorPattern, s)
+ if match {
+ t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
+ }
+ }
+}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index 14356da4ce3..03c4499720f 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -42,9 +42,8 @@ func doDial(t *testing.T, network, addr string) {
}
func TestLookupCNAME(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
cname, err := LookupCNAME("www.google.com")
@@ -67,9 +66,8 @@ var googleaddrsipv4 = []string{
}
func TestDialGoogleIPv4(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
@@ -124,9 +122,8 @@ var googleaddrsipv6 = []string{
}
func TestDialGoogleIPv6(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
// Only run tcp6 if the kernel will take it.
diff --git a/libgo/go/net/http/cgi/child.go b/libgo/go/net/http/cgi/child.go
index e6c3ef911ab..1ba7bec5fc5 100644
--- a/libgo/go/net/http/cgi/child.go
+++ b/libgo/go/net/http/cgi/child.go
@@ -144,6 +144,7 @@ func Serve(handler http.Handler) error {
bufw: bufio.NewWriter(os.Stdout),
}
handler.ServeHTTP(rw, req)
+ rw.Write(nil) // make sure a response is sent
if err = rw.bufw.Flush(); err != nil {
return err
}
diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go
index fec35b72f99..859911f9805 100644
--- a/libgo/go/net/http/cgi/host_test.go
+++ b/libgo/go/net/http/cgi/host_test.go
@@ -41,6 +41,7 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string
// Make a map to hold the test map that the CGI returns.
m := make(map[string]string)
+ m["_body"] = rw.Body.String()
linesRead := 0
readlines:
for {
diff --git a/libgo/go/net/http/cgi/matryoshka_test.go b/libgo/go/net/http/cgi/matryoshka_test.go
index 1a44df20401..e1a78c8f62f 100644
--- a/libgo/go/net/http/cgi/matryoshka_test.go
+++ b/libgo/go/net/http/cgi/matryoshka_test.go
@@ -51,6 +51,22 @@ func TestHostingOurselves(t *testing.T) {
}
}
+// Test that a child handler only writing headers works.
+func TestChildOnlyHeaders(t *testing.T) {
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ expectedMap := map[string]string{
+ "_body": "",
+ }
+ replay := runCgiTest(t, h, "GET /test.go?no-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap)
+ if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
+ t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
+ }
+}
+
// Note: not actually a test.
func TestBeChildCGIProcess(t *testing.T) {
if os.Getenv("REQUEST_METHOD") == "" {
@@ -59,8 +75,11 @@ func TestBeChildCGIProcess(t *testing.T) {
}
Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-Test-Header", "X-Test-Value")
- fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
req.ParseForm()
+ if req.FormValue("no-body") == "1" {
+ return
+ }
+ fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
for k, vv := range req.Form {
for _, v := range vv {
fmt.Fprintf(rw, "param-%s=%s\n", k, v)
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index 0409008b675..5aa93ce5837 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -152,12 +152,19 @@ func TestFileServerCleans(t *testing.T) {
}
}
+func mustRemoveAll(dir string) {
+ err := os.RemoveAll(dir)
+ if err != nil {
+ panic(err)
+ }
+}
+
func TestFileServerImplicitLeadingSlash(t *testing.T) {
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
- defer os.RemoveAll(tempDir)
+ defer mustRemoveAll(tempDir)
if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
@@ -172,6 +179,7 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) {
if err != nil {
t.Fatalf("ReadAll %s: %v", suffix, err)
}
+ res.Body.Close()
return string(b)
}
if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go
index 8d911f7575b..57cf0c9417d 100644
--- a/libgo/go/net/http/httptest/server.go
+++ b/libgo/go/net/http/httptest/server.go
@@ -13,6 +13,7 @@ import (
"net"
"net/http"
"os"
+ "sync"
)
// A Server is an HTTP server listening on a system-chosen port on the
@@ -25,6 +26,10 @@ type Server struct {
// Config may be changed after calling NewUnstartedServer and
// before Start or StartTLS.
Config *http.Server
+
+ // wg counts the number of outstanding HTTP requests on this server.
+ // Close blocks until all requests are finished.
+ wg sync.WaitGroup
}
// historyListener keeps track of all connections that it's ever
@@ -93,6 +98,7 @@ func (s *Server) Start() {
}
s.Listener = &historyListener{s.Listener, make([]net.Conn, 0)}
s.URL = "http://" + s.Listener.Addr().String()
+ s.wrapHandler()
go s.Config.Serve(s.Listener)
if *serve != "" {
fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL)
@@ -118,9 +124,21 @@ func (s *Server) StartTLS() {
s.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
s.URL = "https://" + s.Listener.Addr().String()
+ s.wrapHandler()
go s.Config.Serve(s.Listener)
}
+func (s *Server) wrapHandler() {
+ h := s.Config.Handler
+ if h == nil {
+ h = http.DefaultServeMux
+ }
+ s.Config.Handler = &waitGroupHandler{
+ s: s,
+ h: h,
+ }
+}
+
// NewTLSServer starts and returns a new Server using TLS.
// The caller should call Close when finished, to shut it down.
func NewTLSServer(handler http.Handler) *Server {
@@ -129,9 +147,11 @@ func NewTLSServer(handler http.Handler) *Server {
return ts
}
-// Close shuts down the server.
+// Close shuts down the server and blocks until all outstanding
+// requests on this server have completed.
func (s *Server) Close() {
s.Listener.Close()
+ s.wg.Wait()
}
// CloseClientConnections closes any currently open HTTP connections
@@ -146,6 +166,20 @@ func (s *Server) CloseClientConnections() {
}
}
+// waitGroupHandler wraps a handler, incrementing and decrementing a
+// sync.WaitGroup on each request, to enable Server.Close to block
+// until outstanding requests are finished.
+type waitGroupHandler struct {
+ s *Server
+ h http.Handler // non-nil
+}
+
+func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ h.s.wg.Add(1)
+ defer h.s.wg.Done() // a defer, in case ServeHTTP below panics
+ h.h.ServeHTTP(w, r)
+}
+
// localhostCert is a PEM-encoded TLS cert with SAN DNS names
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go
index c853066f1cf..892ef4eded0 100644
--- a/libgo/go/net/http/httputil/dump.go
+++ b/libgo/go/net/http/httputil/dump.go
@@ -12,6 +12,7 @@ import (
"io/ioutil"
"net"
"net/http"
+ "net/url"
"strings"
"time"
)
@@ -59,6 +60,19 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
}
}
+ // Since we're using the actual Transport code to write the request,
+ // switch to http so the Transport doesn't try to do an SSL
+ // negotiation with our dumpConn and its bytes.Buffer & pipe.
+ // The wire format for https and http are the same, anyway.
+ reqSend := req
+ if req.URL.Scheme == "https" {
+ reqSend = new(http.Request)
+ *reqSend = *req
+ reqSend.URL = new(url.URL)
+ *reqSend.URL = *req.URL
+ reqSend.URL.Scheme = "http"
+ }
+
// Use the actual Transport code to record what we would send
// on the wire, but not using TCP. Use a Transport with a
// customer dialer that returns a fake net.Conn that waits
@@ -79,7 +93,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
},
}
- _, err := t.RoundTrip(req)
+ _, err := t.RoundTrip(reqSend)
req.Body = save
if err != nil {
diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go
index 819efb5847b..5afe9ba74e3 100644
--- a/libgo/go/net/http/httputil/dump_test.go
+++ b/libgo/go/net/http/httputil/dump_test.go
@@ -71,6 +71,18 @@ var dumpTests = []dumpTest{
"User-Agent: Go http package\r\n" +
"Accept-Encoding: gzip\r\n\r\n",
},
+
+ // Test that an https URL doesn't try to do an SSL negotiation
+ // with a bytes.Buffer and hang with all goroutines not
+ // runnable.
+ {
+ Req: *mustNewRequest("GET", "https://example.com/foo", nil),
+
+ WantDumpOut: "GET /foo HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Accept-Encoding: gzip\r\n\r\n",
+ },
}
func TestDumpRequest(t *testing.T) {
diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go
index 32f4662cc0e..507938acac7 100644
--- a/libgo/go/net/http/httputil/persist.go
+++ b/libgo/go/net/http/httputil/persist.go
@@ -383,7 +383,7 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
// Make sure body is fully consumed, even if user does not call body.Close
if lastbody != nil {
// body.Close is assumed to be idempotent and multiple calls to
- // it should return the error that its first invokation
+ // it should return the error that its first invocation
// returned.
err = lastbody.Close()
if err != nil {
diff --git a/libgo/go/net/http/lex.go b/libgo/go/net/http/lex.go
index 93b67e70176..ffb393ccf6a 100644
--- a/libgo/go/net/http/lex.go
+++ b/libgo/go/net/http/lex.go
@@ -14,14 +14,6 @@ func isSeparator(c byte) bool {
return false
}
-func isSpace(c byte) bool {
- switch c {
- case ' ', '\t', '\r', '\n':
- return true
- }
- return false
-}
-
func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
func isChar(c byte) bool { return 0 <= c && c <= 127 }
diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go
index 6efa8ce1ca2..8ab72ac23f9 100644
--- a/libgo/go/net/http/sniff_test.go
+++ b/libgo/go/net/http/sniff_test.go
@@ -129,9 +129,10 @@ func TestSniffWriteSize(t *testing.T) {
}))
defer ts.Close()
for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
- _, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size))
+ res, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size))
if err != nil {
t.Fatalf("size %d: %v", size, err)
}
+ res.Body.Close()
}
}
diff --git a/libgo/go/net/http/status.go b/libgo/go/net/http/status.go
index b6e2d65c6a5..5af0b77c428 100644
--- a/libgo/go/net/http/status.go
+++ b/libgo/go/net/http/status.go
@@ -43,6 +43,7 @@ const (
StatusUnsupportedMediaType = 415
StatusRequestedRangeNotSatisfiable = 416
StatusExpectationFailed = 417
+ StatusTeapot = 418
StatusInternalServerError = 500
StatusNotImplemented = 501
@@ -90,6 +91,7 @@ var statusText = map[int]string{
StatusUnsupportedMediaType: "Unsupported Media Type",
StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
StatusExpectationFailed: "Expectation Failed",
+ StatusTeapot: "I'm a teapot",
StatusInternalServerError: "Internal Server Error",
StatusNotImplemented: "Not Implemented",
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go
index ef9564af9c5..3c8fe7f5b51 100644
--- a/libgo/go/net/http/transfer.go
+++ b/libgo/go/net/http/transfer.go
@@ -383,7 +383,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error)
// chunked encoding must always come first.
for _, encoding := range encodings {
encoding = strings.ToLower(strings.TrimSpace(encoding))
- // "identity" encoding is not recored
+ // "identity" encoding is not recorded
if encoding == "identity" {
break
}
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index 3e48abafb5e..09579f8a093 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -76,7 +76,9 @@ type Transport struct {
// ProxyFromEnvironment returns the URL of the proxy to use for a
// given request, as indicated by the environment variables
// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy).
-// Either URL or an error is returned.
+// An error is returned if the proxy environment is invalid.
+// A nil URL and nil error are returned if no proxy is defined in the
+// environment, or a proxy should not be used for the given request.
func ProxyFromEnvironment(req *Request) (*url.URL, error) {
proxy := getenvEitherCase("HTTP_PROXY")
if proxy == "" {
@@ -86,7 +88,7 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) {
return nil, nil
}
proxyURL, err := url.Parse(proxy)
- if err != nil {
+ if err != nil || proxyURL.Scheme == "" {
if u, err := url.Parse("http://" + proxy); err == nil {
proxyURL = u
err = nil
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index 1a629c1727c..cbb3884f9ea 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -16,6 +16,7 @@ import (
. "net/http"
"net/http/httptest"
"net/url"
+ "os"
"runtime"
"strconv"
"strings"
@@ -727,6 +728,36 @@ func TestTransportAltProto(t *testing.T) {
}
}
+var proxyFromEnvTests = []struct {
+ env string
+ wanturl string
+ wanterr error
+}{
+ {"127.0.0.1:8080", "http://127.0.0.1:8080", nil},
+ {"http://127.0.0.1:8080", "http://127.0.0.1:8080", nil},
+ {"https://127.0.0.1:8080", "https://127.0.0.1:8080", nil},
+ {"", "<nil>", nil},
+}
+
+func TestProxyFromEnvironment(t *testing.T) {
+ os.Setenv("HTTP_PROXY", "")
+ os.Setenv("http_proxy", "")
+ os.Setenv("NO_PROXY", "")
+ os.Setenv("no_proxy", "")
+ for i, tt := range proxyFromEnvTests {
+ os.Setenv("HTTP_PROXY", tt.env)
+ req, _ := NewRequest("GET", "http://example.com", nil)
+ url, err := ProxyFromEnvironment(req)
+ if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
+ t.Errorf("%d. got error = %q, want %q", i, g, e)
+ continue
+ }
+ if got := fmt.Sprintf("%s", url); got != tt.wanturl {
+ t.Errorf("%d. got URL = %q, want %q", i, url, tt.wanturl)
+ }
+ }
+}
+
// rgz is a gzip quine that uncompresses to itself.
var rgz = []byte{
0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
diff --git a/libgo/go/net/http/triv.go b/libgo/go/net/http/triv.go
index c88a0fbce73..269af0ca3d5 100644
--- a/libgo/go/net/http/triv.go
+++ b/libgo/go/net/http/triv.go
@@ -108,7 +108,6 @@ func DateServer(rw http.ResponseWriter, req *http.Request) {
fmt.Fprintf(rw, "fork/exec: %s\n", err)
return
}
- defer p.Release()
io.Copy(rw, r)
wait, err := p.Wait(0)
if err != nil {
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index 5e7b352ed50..f25d046c171 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -6,11 +6,7 @@
package net
-import (
- "bytes"
- "errors"
- "fmt"
-)
+import "errors"
var (
errInvalidInterface = errors.New("net: invalid interface")
@@ -20,77 +16,6 @@ var (
errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
)
-// A HardwareAddr represents a physical hardware address.
-type HardwareAddr []byte
-
-func (a HardwareAddr) String() string {
- var buf bytes.Buffer
- for i, b := range a {
- if i > 0 {
- buf.WriteByte(':')
- }
- fmt.Fprintf(&buf, "%02x", b)
- }
- return buf.String()
-}
-
-// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
-// following formats:
-// 01:23:45:67:89:ab
-// 01:23:45:67:89:ab:cd:ef
-// 01-23-45-67-89-ab
-// 01-23-45-67-89-ab-cd-ef
-// 0123.4567.89ab
-// 0123.4567.89ab.cdef
-func ParseMAC(s string) (hw HardwareAddr, err error) {
- if len(s) < 14 {
- goto error
- }
-
- if s[2] == ':' || s[2] == '-' {
- if (len(s)+1)%3 != 0 {
- goto error
- }
- n := (len(s) + 1) / 3
- if n != 6 && n != 8 {
- goto error
- }
- hw = make(HardwareAddr, n)
- for x, i := 0, 0; i < n; i++ {
- var ok bool
- if hw[i], ok = xtoi2(s[x:], s[2]); !ok {
- goto error
- }
- x += 3
- }
- } else if s[4] == '.' {
- if (len(s)+1)%5 != 0 {
- goto error
- }
- n := 2 * (len(s) + 1) / 5
- if n != 6 && n != 8 {
- goto error
- }
- hw = make(HardwareAddr, n)
- for x, i := 0, 0; i < n; i += 2 {
- var ok bool
- if hw[i], ok = xtoi2(s[x:x+2], 0); !ok {
- goto error
- }
- if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok {
- goto error
- }
- x += 5
- }
- } else {
- goto error
- }
- return hw, nil
-
-error:
- return nil, errors.New("invalid MAC address: " + s)
-}
-
// Interface represents a mapping between network interface name
// and index. It also represents network interface facility
// information.
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
index 769414e0eef..0a33bfdb517 100644
--- a/libgo/go/net/interface_test.go
+++ b/libgo/go/net/interface_test.go
@@ -6,8 +6,6 @@ package net
import (
"bytes"
- "reflect"
- "strings"
"testing"
)
@@ -96,46 +94,3 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) {
}
}
}
-
-var mactests = []struct {
- in string
- out HardwareAddr
- err string
-}{
- {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
- {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
- {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
- {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""},
- {"01.02.03.04.05.06", nil, "invalid MAC address"},
- {"01:02:03:04:05:06:", nil, "invalid MAC address"},
- {"x1:02:03:04:05:06", nil, "invalid MAC address"},
- {"01002:03:04:05:06", nil, "invalid MAC address"},
- {"01:02003:04:05:06", nil, "invalid MAC address"},
- {"01:02:03004:05:06", nil, "invalid MAC address"},
- {"01:02:03:04005:06", nil, "invalid MAC address"},
- {"01:02:03:04:05006", nil, "invalid MAC address"},
- {"01-02:03:04:05:06", nil, "invalid MAC address"},
- {"01:02-03-04-05-06", nil, "invalid MAC address"},
- {"0123:4567:89AF", nil, "invalid MAC address"},
- {"0123-4567-89AF", nil, "invalid MAC address"},
- {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
- {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
- {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
-}
-
-func match(err error, s string) bool {
- if s == "" {
- return err == nil
- }
- return err != nil && strings.Contains(err.Error(), s)
-}
-
-func TestParseMAC(t *testing.T) {
- for _, tt := range mactests {
- out, err := ParseMAC(tt.in)
- if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
- t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
- tt.err)
- }
- }
-}
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
index b08a9fb98e0..2c698304b21 100644
--- a/libgo/go/net/lookup_plan9.go
+++ b/libgo/go/net/lookup_plan9.go
@@ -76,7 +76,7 @@ func lookupProtocol(name string) (proto int, err error) {
}
func lookupHost(host string) (addrs []string, err error) {
- // Use /net/cs insead of /net/dns because cs knows about
+ // Use /net/cs instead of /net/dns because cs knows about
// host names in local network (e.g. from /lib/ndb/local)
lines, err := queryCS("tcp", host, "1")
if err != nil {
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 7b9ea844cd4..3a61dfb29c2 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -12,7 +12,7 @@ import (
"testing"
)
-var testExternal = flag.Bool("external", false, "allow use of external networks during test")
+var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
func TestGoogleSRV(t *testing.T) {
if testing.Short() || !*testExternal {
@@ -78,3 +78,40 @@ func TestGoogleDNSAddr(t *testing.T) {
t.Errorf("no results")
}
}
+
+var revAddrTests = []struct {
+ Addr string
+ Reverse string
+ ErrPrefix string
+}{
+ {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
+ {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
+ {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
+ {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
+ {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
+ {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1.2.3", "", "unrecognized address"},
+ {"1.2.3.4.5", "", "unrecognized address"},
+ {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
+ {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+}
+
+func TestReverseAddress(t *testing.T) {
+ for i, tt := range revAddrTests {
+ a, err := reverseaddr(tt.Addr)
+ if len(tt.ErrPrefix) > 0 && err == nil {
+ t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
+ continue
+ }
+ if len(tt.ErrPrefix) == 0 && err != nil {
+ t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
+ }
+ if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
+ t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
+ }
+ if a != tt.Reverse {
+ t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ }
+ }
+}
diff --git a/libgo/go/net/mac.go b/libgo/go/net/mac.go
new file mode 100644
index 00000000000..e0637d00b74
--- /dev/null
+++ b/libgo/go/net/mac.go
@@ -0,0 +1,84 @@
+// 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.
+
+// MAC address manipulations
+
+package net
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+)
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ var buf bytes.Buffer
+ for i, b := range a {
+ if i > 0 {
+ buf.WriteByte(':')
+ }
+ fmt.Fprintf(&buf, "%02x", b)
+ }
+ return buf.String()
+}
+
+// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
+// following formats:
+// 01:23:45:67:89:ab
+// 01:23:45:67:89:ab:cd:ef
+// 01-23-45-67-89-ab
+// 01-23-45-67-89-ab-cd-ef
+// 0123.4567.89ab
+// 0123.4567.89ab.cdef
+func ParseMAC(s string) (hw HardwareAddr, err error) {
+ if len(s) < 14 {
+ goto error
+ }
+
+ if s[2] == ':' || s[2] == '-' {
+ if (len(s)+1)%3 != 0 {
+ goto error
+ }
+ n := (len(s) + 1) / 3
+ if n != 6 && n != 8 {
+ goto error
+ }
+ hw = make(HardwareAddr, n)
+ for x, i := 0, 0; i < n; i++ {
+ var ok bool
+ if hw[i], ok = xtoi2(s[x:], s[2]); !ok {
+ goto error
+ }
+ x += 3
+ }
+ } else if s[4] == '.' {
+ if (len(s)+1)%5 != 0 {
+ goto error
+ }
+ n := 2 * (len(s) + 1) / 5
+ if n != 6 && n != 8 {
+ goto error
+ }
+ hw = make(HardwareAddr, n)
+ for x, i := 0, 0; i < n; i += 2 {
+ var ok bool
+ if hw[i], ok = xtoi2(s[x:x+2], 0); !ok {
+ goto error
+ }
+ if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok {
+ goto error
+ }
+ x += 5
+ }
+ } else {
+ goto error
+ }
+ return hw, nil
+
+error:
+ return nil, errors.New("invalid MAC address: " + s)
+}
diff --git a/libgo/go/net/mac_test.go b/libgo/go/net/mac_test.go
new file mode 100644
index 00000000000..3837e740cf9
--- /dev/null
+++ b/libgo/go/net/mac_test.go
@@ -0,0 +1,54 @@
+// 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 (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var mactests = []struct {
+ in string
+ out HardwareAddr
+ err string
+}{
+ {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""},
+ {"01.02.03.04.05.06", nil, "invalid MAC address"},
+ {"01:02:03:04:05:06:", nil, "invalid MAC address"},
+ {"x1:02:03:04:05:06", nil, "invalid MAC address"},
+ {"01002:03:04:05:06", nil, "invalid MAC address"},
+ {"01:02003:04:05:06", nil, "invalid MAC address"},
+ {"01:02:03004:05:06", nil, "invalid MAC address"},
+ {"01:02:03:04005:06", nil, "invalid MAC address"},
+ {"01:02:03:04:05006", nil, "invalid MAC address"},
+ {"01-02:03:04:05:06", nil, "invalid MAC address"},
+ {"01:02-03-04-05-06", nil, "invalid MAC address"},
+ {"0123:4567:89AF", nil, "invalid MAC address"},
+ {"0123-4567-89AF", nil, "invalid MAC address"},
+ {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+ {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+ {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+}
+
+func match(err error, s string) bool {
+ if s == "" {
+ return err == nil
+ }
+ return err != nil && strings.Contains(err.Error(), s)
+}
+
+func TestParseMAC(t *testing.T) {
+ for _, tt := range mactests {
+ out, err := ParseMAC(tt.in)
+ if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
+ t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
+ tt.err)
+ }
+ }
+}
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index 69d7ac87880..c1a90de0131 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -5,130 +5,12 @@
package net
import (
- "flag"
"io"
- "regexp"
"runtime"
"testing"
"time"
)
-var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
-
-type DialErrorTest struct {
- Net string
- Raddr string
- Pattern string
-}
-
-var dialErrorTests = []DialErrorTest{
- {
- "datakit", "mh/astro/r70",
- "dial datakit mh/astro/r70: unknown network datakit",
- },
- {
- "tcp", "127.0.0.1:☺",
- "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
- },
- {
- "tcp", "no-such-name.google.com.:80",
- "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
- },
- {
- "tcp", "no-such-name.no-such-top-level-domain.:80",
- "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
- },
- {
- "tcp", "no-such-name:80",
- `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
- },
- {
- "tcp", "mh/astro/r70:http",
- "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
- },
- {
- "unix", "/etc/file-not-found",
- "dial unix /etc/file-not-found: [nN]o such file or directory",
- },
- {
- "unix", "/etc/",
- "dial unix /etc/: ([pP]ermission denied|socket operation on non-socket|connection refused)",
- },
- {
- "unixpacket", "/etc/file-not-found",
- "dial unixpacket /etc/file-not-found: no such file or directory",
- },
- {
- "unixpacket", "/etc/",
- "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
- },
-}
-
-var duplicateErrorPattern = `dial (.*) dial (.*)`
-
-func TestDialError(t *testing.T) {
- if !*runErrorTest {
- t.Logf("test disabled; use --run_error_test to enable")
- return
- }
- for i, tt := range dialErrorTests {
- c, err := Dial(tt.Net, tt.Raddr)
- if c != nil {
- c.Close()
- }
- if err == nil {
- t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
- continue
- }
- s := err.Error()
- match, _ := regexp.MatchString(tt.Pattern, s)
- if !match {
- t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
- }
- match, _ = regexp.MatchString(duplicateErrorPattern, s)
- if match {
- t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
- }
- }
-}
-
-var revAddrTests = []struct {
- Addr string
- Reverse string
- ErrPrefix string
-}{
- {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
- {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
- {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
- {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
- {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
- {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
- {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
- {"1.2.3", "", "unrecognized address"},
- {"1.2.3.4.5", "", "unrecognized address"},
- {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
- {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
-}
-
-func TestReverseAddress(t *testing.T) {
- for i, tt := range revAddrTests {
- a, err := reverseaddr(tt.Addr)
- if len(tt.ErrPrefix) > 0 && err == nil {
- t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
- continue
- }
- if len(tt.ErrPrefix) == 0 && err != nil {
- t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
- }
- if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
- t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
- }
- if a != tt.Reverse {
- t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
- }
- }
-}
-
func TestShutdown(t *testing.T) {
if runtime.GOOS == "plan9" {
return
diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go
index 34f9ae317e2..f7abf21f157 100644
--- a/libgo/go/net/rpc/client.go
+++ b/libgo/go/net/rpc/client.go
@@ -140,7 +140,7 @@ func (client *Client) input() {
}
client.mutex.Unlock()
client.sending.Unlock()
- if err != io.EOF || !closing {
+ if err != io.EOF && !closing {
log.Println("rpc: client protocol error:", err)
}
}
diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go
index 920ae9137a6..1680e2f0d70 100644
--- a/libgo/go/net/rpc/server.go
+++ b/libgo/go/net/rpc/server.go
@@ -13,13 +13,19 @@
Only methods that satisfy these criteria will be made available for remote access;
other methods will be ignored:
- - the method name is exported, that is, begins with an upper case letter.
- - the method receiver is exported or local (defined in the package
- registering the service).
- - the method has two arguments, both exported or local types.
+ - the method is exported.
+ - the method has two arguments, both exported (or builtin) types.
- the method's second argument is a pointer.
- the method has return type error.
+ In effect, the method must look schematically like
+
+ func (t *T) MethodName(argType T1, replyType *T2) error
+
+ where T, T1 and T2 can be marshaled by encoding/gob.
+ These requirements apply even if a different codec is used.
+ (In future, these requirements may soften for custom codecs.)
+
The method's first argument represents the arguments provided by the caller; the
second argument represents the result parameters to be returned to the caller.
The method's return value, if non-nil, is passed back as a string that the client
@@ -36,10 +42,12 @@
call, a pointer containing the arguments, and a pointer to receive the result
parameters.
- Call waits for the remote call to complete; Go launches the call asynchronously
- and returns a channel that will signal completion.
+ The Call method waits for the remote call to complete while the Go method
+ launches the call asynchronously and signals completion using the Call
+ structure's Done channel.
- Package "gob" is used to transport the data.
+ Unless an explicit codec is set up, package encoding/gob is used to
+ transport the data.
Here is a simple example. A server wishes to export an object of type Arith:
@@ -256,6 +264,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
method := s.typ.Method(m)
mtype := method.Type
mname := method.Name
+ // Method must be exported.
if method.PkgPath != "" {
continue
}
@@ -267,7 +276,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
// First arg need not be a pointer.
argType := mtype.In(1)
if !isExportedOrBuiltinType(argType) {
- log.Println(mname, "argument type not exported or local:", argType)
+ log.Println(mname, "argument type not exported:", argType)
continue
}
// Second arg must be a pointer.
@@ -276,15 +285,17 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
log.Println("method", mname, "reply type not a pointer:", replyType)
continue
}
+ // Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
- log.Println("method", mname, "reply type not exported or local:", replyType)
+ log.Println("method", mname, "reply type not exported:", replyType)
continue
}
- // Method needs one out: error.
+ // Method needs one out.
if mtype.NumOut() != 1 {
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
continue
}
+ // The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
log.Println("method", mname, "returns", returnType.String(), "not error")
continue
@@ -301,10 +312,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
return nil
}
-// A value sent as a placeholder for the response when the server receives an invalid request.
-type InvalidRequest struct{}
-
-var invalidRequest = InvalidRequest{}
+// A value sent as a placeholder for the server's response value when the server
+// receives an invalid request. It is never decoded by the client since the Response
+// contains an error when it is used.
+var invalidRequest = struct{}{}
func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
resp := server.getResponse()
diff --git a/libgo/go/net/sockoptip_netbsd.go b/libgo/go/net/sockoptip_netbsd.go
new file mode 100644
index 00000000000..446d92aa343
--- /dev/null
+++ b/libgo/go/net/sockoptip_netbsd.go
@@ -0,0 +1,39 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP-level socket options for NetBSD
+
+package net
+
+import "syscall"
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ // TODO: Implement this
+ return nil, syscall.EAFNOSUPPORT
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EAFNOSUPPORT
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EAFNOSUPPORT
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index bae37c86b2e..ef350f0f946 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -40,7 +40,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
return
}
- if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 250*time.Millisecond {
+ if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
return
}
diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go
index 6ba762b1f78..ea5fad41a53 100644
--- a/libgo/go/net/udp_test.go
+++ b/libgo/go/net/udp_test.go
@@ -38,18 +38,18 @@ func testWriteToConn(t *testing.T, raddr string) {
_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
if err == nil {
- t.Fatal("WriteToUDP should be failed")
+ t.Fatal("WriteToUDP should fail")
}
if err != nil && err.(*OpError).Err != ErrWriteToConnected {
- t.Fatalf("WriteToUDP should be failed as ErrWriteToConnected: %v", err)
+ t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err)
}
_, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra)
if err == nil {
- t.Fatal("WriteTo should be failed")
+ t.Fatal("WriteTo should fail")
}
if err != nil && err.(*OpError).Err != ErrWriteToConnected {
- t.Fatalf("WriteTo should be failed as ErrWriteToConnected: %v", err)
+ t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
}
_, err = c.Write([]byte("Connection-oriented mode socket"))
@@ -82,6 +82,6 @@ func testWriteToPacketConn(t *testing.T, raddr string) {
_, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
if err == nil {
- t.Fatal("Write should be failed")
+ t.Fatal("Write should fail")
}
}
diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go
index ef857c0429f..6a531e0d74e 100644
--- a/libgo/go/os/doc.go
+++ b/libgo/go/os/doc.go
@@ -4,6 +4,8 @@
package os
+import "time"
+
// FindProcess looks for a running process by its pid.
// The Process it returns can be used to obtain information
// about the underlying operating system process.
@@ -11,6 +13,76 @@ func FindProcess(pid int) (p *Process, err error) {
return findProcess(pid)
}
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The os/exec package provides
+// higher-level interfaces.
+//
+// If there is an error, it will be of type *PathError.
+func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
+ return startProcess(name, argv, attr)
+}
+
+// Release releases any resources associated with the Process p,
+// rendering it unusable in the future.
+// Release only needs to be called if Wait is not.
+func (p *Process) Release() error {
+ return p.release()
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() error {
+ return p.kill()
+}
+
+// Wait waits for the Process to exit, and then returns a
+// ProcessState describing its status and an error, if any.
+// Wait releases any resources associated with the Process.
+func (p *Process) Wait() (*ProcessState, error) {
+ return p.wait()
+}
+
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) error {
+ return p.signal(sig)
+}
+
+// UserTime returns the user CPU time of the exited process and its children.
+func (p *ProcessState) UserTime() time.Duration {
+ return p.userTime()
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+func (p *ProcessState) SystemTime() time.Duration {
+ return p.systemTime()
+}
+
+// Exited returns whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.success()
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as syscall.WaitStatus on Unix, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.sys()
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Rusage on Unix, to access its contents.
+func (p *ProcessState) SysUsage() interface{} {
+ return p.sysUsage()
+}
+
// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err error) {
return hostname()
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
index 37a0051c5dc..531b87ca556 100644
--- a/libgo/go/os/exec.go
+++ b/libgo/go/os/exec.go
@@ -13,7 +13,7 @@ import (
type Process struct {
Pid int
handle uintptr
- done bool // process has been successfuly waited on
+ done bool // process has been successfully waited on
}
func newProcess(pid int, handle uintptr) *Process {
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index 1c9e2b997f8..41cc8c26f4c 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -11,10 +11,7 @@ import (
"time"
)
-// StartProcess starts a new process with the program, arguments and attributes
-// specified by name, argv and attr.
-// If there is an error, it will be of type *PathError.
-func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
@@ -40,7 +37,7 @@ func (note Plan9Note) String() string {
return string(note)
}
-func (p *Process) Signal(sig Signal) error {
+func (p *Process) signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
@@ -54,8 +51,7 @@ func (p *Process) Signal(sig Signal) error {
return e
}
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() error {
+func (p *Process) kill() error {
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
if e != nil {
return NewSyscallError("kill", e)
@@ -65,9 +61,7 @@ func (p *Process) Kill() error {
return e
}
-// Wait waits for the Process to exit or stop, and then returns a
-// ProcessState describing its status and an error, if any.
-func (p *Process) Wait() (ps *ProcessState, err error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
@@ -94,8 +88,7 @@ func (p *Process) Wait() (ps *ProcessState, err error) {
return ps, nil
}
-// Release releases any resources associated with the Process.
-func (p *Process) Release() error {
+func (p *Process) release() error {
// NOOP for Plan 9.
p.Pid = -1
// no need for a finalizer anymore
@@ -108,7 +101,7 @@ func findProcess(pid int) (p *Process, err error) {
return newProcess(pid, 0), nil
}
-// ProcessState stores information about process as reported by Wait.
+// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
pid int // The process's id.
status *syscall.Waitmsg // System-dependent status info.
@@ -119,40 +112,27 @@ func (p *ProcessState) Pid() int {
return p.pid
}
-// Exited returns whether the program has exited.
-func (p *ProcessState) Exited() bool {
+func (p *ProcessState) exited() bool {
return p.status.Exited()
}
-// Success reports whether the program exited successfully,
-// such as with exit status 0 on Unix.
-func (p *ProcessState) Success() bool {
+func (p *ProcessState) success() bool {
return p.status.ExitStatus() == 0
}
-// Sys returns system-dependent exit information about
-// the process. Convert it to the appropriate underlying
-// type, such as *syscall.Waitmsg on Plan 9, to access its contents.
-func (p *ProcessState) Sys() interface{} {
+func (p *ProcessState) sys() interface{} {
return p.status
}
-// SysUsage returns system-dependent resource usage information about
-// the exited process. Convert it to the appropriate underlying
-// type, such as *syscall.Waitmsg on Plan 9, to access its contents.
-func (p *ProcessState) SysUsage() interface{} {
+func (p *ProcessState) sysUsage() interface{} {
return p.status
}
-// UserTime returns the user CPU time of the exited process and its children.
-// It is always reported as 0 on Windows.
-func (p *ProcessState) UserTime() time.Duration {
+func (p *ProcessState) userTime() time.Duration {
return time.Duration(p.status.Time[0]) * time.Millisecond
}
-// SystemTime returns the system CPU time of the exited process and its children.
-// It is always reported as 0 on Windows.
-func (p *ProcessState) SystemTime() time.Duration {
+func (p *ProcessState) systemTime() time.Duration {
return time.Duration(p.status.Time[1]) * time.Millisecond
}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 4a75cb67fb5..70351cfb313 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -10,14 +10,17 @@ import (
"syscall"
)
-// StartProcess starts a new process with the program, arguments and attributes
-// specified by name, argv and attr.
-//
-// StartProcess is a low-level interface. The os/exec package provides
-// higher-level interfaces.
-//
-// If there is an error, it will be of type *PathError.
-func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+ // Double-check existence of the directory we want
+ // to chdir into. We can make the error clearer this way.
+ if attr != nil && attr.Dir != "" {
+ if _, err := Stat(attr.Dir); err != nil {
+ pe := err.(*PathError)
+ pe.Op = "chdir"
+ return nil, pe
+ }
+ }
+
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
@@ -37,12 +40,11 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
return newProcess(pid, h), nil
}
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() error {
+func (p *Process) kill() error {
return p.Signal(Kill)
}
-// ProcessState stores information about process as reported by Wait.
+// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
pid int // The process's id.
status syscall.WaitStatus // System-dependent status info.
@@ -54,28 +56,19 @@ func (p *ProcessState) Pid() int {
return p.pid
}
-// Exited returns whether the program has exited.
-func (p *ProcessState) Exited() bool {
+func (p *ProcessState) exited() bool {
return p.status.Exited()
}
-// Success reports whether the program exited successfully,
-// such as with exit status 0 on Unix.
-func (p *ProcessState) Success() bool {
+func (p *ProcessState) success() bool {
return p.status.ExitStatus() == 0
}
-// Sys returns system-dependent exit information about
-// the process. Convert it to the appropriate underlying
-// type, such as syscall.WaitStatus on Unix, to access its contents.
-func (p *ProcessState) Sys() interface{} {
+func (p *ProcessState) sys() interface{} {
return p.status
}
-// SysUsage returns system-dependent resource usage information about
-// the exited process. Convert it to the appropriate underlying
-// type, such as *syscall.Rusage on Unix, to access its contents.
-func (p *ProcessState) SysUsage() interface{} {
+func (p *ProcessState) sysUsage() interface{} {
return p.rusage
}
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 8d000e9ef15..ecfe5353bc1 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -13,9 +13,7 @@ import (
"time"
)
-// Wait waits for the Process to exit or stop, and then returns a
-// ProcessState describing its status and an error, if any.
-func (p *Process) Wait() (ps *ProcessState, err error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
if p.Pid == -1 {
return nil, syscall.EINVAL
}
@@ -36,8 +34,7 @@ func (p *Process) Wait() (ps *ProcessState, err error) {
return ps, nil
}
-// Signal sends a signal to the Process.
-func (p *Process) Signal(sig Signal) error {
+func (p *Process) signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
@@ -51,8 +48,7 @@ func (p *Process) Signal(sig Signal) error {
return nil
}
-// Release releases any resources associated with the Process.
-func (p *Process) Release() error {
+func (p *Process) release() error {
// NOOP for unix.
p.Pid = -1
// no need for a finalizer anymore
@@ -65,12 +61,10 @@ func findProcess(pid int) (p *Process, err error) {
return newProcess(pid, 0), nil
}
-// UserTime returns the user CPU time of the exited process and its children.
-func (p *ProcessState) UserTime() time.Duration {
+func (p *ProcessState) userTime() time.Duration {
return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond
}
-// SystemTime returns the system CPU time of the exited process and its children.
-func (p *ProcessState) SystemTime() time.Duration {
+func (p *ProcessState) systemTime() time.Duration {
return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond
}
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index dab0dc97571..5beca4a6509 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -12,9 +12,7 @@ import (
"unsafe"
)
-// Wait waits for the Process to exit or stop, and then returns a
-// ProcessState describing its status and an error, if any.
-func (p *Process) Wait() (ps *ProcessState, err error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
switch s {
case syscall.WAIT_OBJECT_0:
@@ -29,12 +27,22 @@ func (p *Process) Wait() (ps *ProcessState, err error) {
if e != nil {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
+ var u syscall.Rusage
+ e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
+ if e != nil {
+ return nil, NewSyscallError("GetProcessTimes", e)
+ }
p.done = true
- return &ProcessState{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil
+ // NOTE(brainman): It seems that sometimes process is not dead
+ // when WaitForSingleObject returns. But we do not know any
+ // other way to wait for it. Sleeping for a while seems to do
+ // the trick sometimes. So we will sleep and smell the roses.
+ defer time.Sleep(5 * time.Millisecond)
+ defer p.Release()
+ return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
}
-// Signal sends a signal to the Process.
-func (p *Process) Signal(sig Signal) error {
+func (p *Process) signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
@@ -46,8 +54,7 @@ func (p *Process) Signal(sig Signal) error {
return syscall.Errno(syscall.EWINDOWS)
}
-// Release releases any resources associated with the Process.
-func (p *Process) Release() error {
+func (p *Process) release() error {
if p.handle == uintptr(syscall.InvalidHandle) {
return syscall.EINVAL
}
@@ -85,14 +92,15 @@ func init() {
}
}
-// UserTime returns the user CPU time of the exited process and its children.
-// For now, it is always reported as 0 on Windows.
-func (p *ProcessState) UserTime() time.Duration {
- return 0
+func ftToDuration(ft *syscall.Filetime) time.Duration {
+ n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
+ return time.Duration(n*100) * time.Nanosecond
+}
+
+func (p *ProcessState) userTime() time.Duration {
+ return ftToDuration(&p.rusage.UserTime)
}
-// SystemTime returns the system CPU time of the exited process and its children.
-// For now, it is always reported as 0 on Windows.
-func (p *ProcessState) SystemTime() time.Duration {
- return 0
+func (p *ProcessState) systemTime() time.Duration {
+ return ftToDuration(&p.rusage.KernelTime)
}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 1c3d0172d34..4acf35d6755 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -25,7 +25,7 @@
// open file.go: no such file or directory
//
// The file's data can then be read into a slice of bytes. Read and
-// Write take their byte counts from the length of the artument slice.
+// Write take their byte counts from the length of the argument slice.
//
// data := make([]byte, 100)
// count, err := file.Read(data)
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index cff35fcef75..aa01669a5da 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -528,7 +528,6 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
if err != nil {
t.Fatalf("StartProcess: %v", err)
}
- defer p.Release()
w.Close()
var b bytes.Buffer
@@ -846,7 +845,6 @@ func run(t *testing.T, cmd []string) string {
if err != nil {
t.Fatal(err)
}
- defer p.Release()
w.Close()
var b bytes.Buffer
@@ -1012,3 +1010,38 @@ func TestNilProcessStateString(t *testing.T) {
t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
}
}
+
+func TestSameFile(t *testing.T) {
+ fa, err := Create("a")
+ if err != nil {
+ t.Fatalf("Create(a): %v", err)
+ }
+ defer Remove(fa.Name())
+ fa.Close()
+ fb, err := Create("b")
+ if err != nil {
+ t.Fatalf("Create(b): %v", err)
+ }
+ defer Remove(fb.Name())
+ fb.Close()
+
+ ia1, err := Stat("a")
+ if err != nil {
+ t.Fatalf("Stat(a): %v", err)
+ }
+ ia2, err := Stat("a")
+ if err != nil {
+ t.Fatalf("Stat(a): %v", err)
+ }
+ if !SameFile(ia1, ia2) {
+ t.Errorf("files should be same")
+ }
+
+ ib, err := Stat("b")
+ if err != nil {
+ t.Fatalf("Stat(b): %v", err)
+ }
+ if SameFile(ia1, ib) {
+ t.Errorf("files should be different")
+ }
+}
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index f468d33264b..cfe46981f13 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -139,6 +139,7 @@ func FromSlash(path string) string {
// SplitList splits a list of paths joined by the OS-specific ListSeparator,
// usually found in PATH or GOPATH environment variables.
+// Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
func SplitList(path string) []string {
if path == "" {
return []string{}
diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go
index 17b873f1a9b..cf028a75c52 100644
--- a/libgo/go/path/filepath/path_plan9.go
+++ b/libgo/go/path/filepath/path_plan9.go
@@ -17,7 +17,7 @@ func VolumeName(path string) string {
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go
index c5ac71efe21..305e307272f 100644
--- a/libgo/go/path/filepath/path_unix.go
+++ b/libgo/go/path/filepath/path_unix.go
@@ -19,7 +19,7 @@ func VolumeName(path string) string {
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go
index 9692fd978c5..1d1d23bfe7c 100644
--- a/libgo/go/path/filepath/path_windows.go
+++ b/libgo/go/path/filepath/path_windows.go
@@ -67,8 +67,7 @@ func VolumeName(path string) (v string) {
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
-// It ignores case while comparing.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
if strings.HasPrefix(p, prefix) {
return true
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 557fb8e843e..56744a514bc 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -629,6 +629,13 @@ type DeepEqualTest struct {
eq bool
}
+// Simple functions for DeepEqual tests.
+var (
+ fn1 func() // nil.
+ fn2 func() // nil.
+ fn3 = func() { fn1() } // Not nil.
+)
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{1, 1, true},
@@ -641,6 +648,7 @@ var deepEqualTests = []DeepEqualTest{
{Basic{1, 0.5}, Basic{1, 0.5}, true},
{error(nil), error(nil), true},
{map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+ {fn1, fn2, true},
// Inequalities
{1, 2, false},
@@ -658,6 +666,8 @@ var deepEqualTests = []DeepEqualTest{
{map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
{nil, 1, false},
{1, nil, false},
+ {fn1, fn3, false},
+ {fn3, fn3, false},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
@@ -1737,3 +1747,15 @@ func isValid(v Value) {
panic("zero Value")
}
}
+
+func TestAlias(t *testing.T) {
+ x := string("hello")
+ v := ValueOf(&x).Elem()
+ oldvalue := v.Interface()
+ v.SetString("world")
+ newvalue := v.Interface()
+
+ if oldvalue != "hello" || newvalue != "world" {
+ t.Errorf("aliasing: old=%q new=%q, want hello, world", oldvalue, newvalue)
+ }
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index df5ec0a6099..c12e90f36cc 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -108,6 +108,12 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
}
return true
+ case Func:
+ if v1.IsNil() && v2.IsNil() {
+ return true
+ }
+ // Can't do better than this:
+ return false
default:
// Normal equality suffices
return valueInterface(v1, false) == valueInterface(v2, false)
@@ -117,8 +123,8 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
// DeepEqual tests for deep equality. It uses normal == equality where possible
-// but will scan members of arrays, slices, and fields of structs. It correctly
-// handles recursive types.
+// but will scan members of arrays, slices, maps, and fields of structs. It correctly
+// handles recursive types. Functions are equal only if they are both nil.
func DeepEqual(a1, a2 interface{}) bool {
if a1 == nil || a2 == nil {
return a1 == a2
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 9568e41136f..b1dd0a1fecd 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -12,7 +12,7 @@
// for that type.
//
// See "The Laws of Reflection" for an introduction to reflection in Go:
-// http://blog.golang.org/2011/09/laws-of-reflection.html
+// http://golang.org/doc/articles/laws_of_reflection.html
package reflect
import (
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index ab56bdf56b6..b490e99f409 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -792,13 +792,15 @@ func (v Value) CanInterface() bool {
return v.flag&(flagMethod|flagRO) == 0
}
-// Interface returns v's value as an interface{}.
+// Interface returns v's current value as an interface{}.
+// It is equivalent to:
+// var i interface{} = (v's underlying value)
// If v is a method obtained by invoking Value.Method
// (as opposed to Type.Method), Interface cannot return an
// interface value, so it panics.
// It also panics if the Value was obtained by accessing
// unexported struct fields.
-func (v Value) Interface() interface{} {
+func (v Value) Interface() (i interface{}) {
return valueInterface(v, true)
}
@@ -834,6 +836,16 @@ func valueInterface(v Value, safe bool) interface{} {
var eface emptyInterface
eface.typ = v.typ.runtimeType()
eface.word = v.iword()
+
+ if v.flag&flagIndir != 0 && v.typ.size > ptrSize {
+ // eface.word is a pointer to the actual data,
+ // which might be changed. We need to return
+ // a pointer to unchanging data, so make a copy.
+ ptr := unsafe_New(v.typ)
+ memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
+ eface.word = iword(ptr)
+ }
+
return *(*interface{})(unsafe.Pointer(&eface))
}
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 099bb6a92f9..f67e8a8f9ae 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -20,8 +20,8 @@ import (
"text/tabwriter"
)
-// BUG(rsc): CPU profiling is broken on OS X, due to an Apple kernel bug.
-// For details, see http://code.google.com/p/go/source/detail?r=35b716c94225.
+// BUG(rsc): A bug in the OS X Snow Leopard 64-bit kernel prevents
+// CPU profiling from giving accurate results on that system.
// A Profile is a collection of stack traces showing the call sequences
// that led to instances of a particular event, such as allocation.
@@ -156,7 +156,7 @@ func (p *Profile) Count() int {
}
// Add adds the current execution stack to the profile, associated with value.
-// Add stores value in an internal map, so value must be suitable for use as
+// Add stores value in an internal map, so value must be suitable for use as
// a map key and will not be garbage collected until the corresponding
// call to Remove. Add panics if the profile already contains a stack for value.
//
diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go
index 5f128c01cf1..2dc7aef7e96 100644
--- a/libgo/go/runtime/pprof/pprof_test.go
+++ b/libgo/go/runtime/pprof/pprof_test.go
@@ -7,6 +7,7 @@ package pprof_test
import (
"bytes"
"hash/crc32"
+ "os/exec"
"runtime"
. "runtime/pprof"
"strings"
@@ -17,8 +18,16 @@ import (
func TestCPUProfile(t *testing.T) {
switch runtime.GOOS {
case "darwin":
- // see Apple Bug Report #9177434 (copied into change description)
- return
+ out, err := exec.Command("uname", "-a").CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ vers := string(out)
+ t.Logf("uname -a: %v", vers)
+ if strings.Contains(vers, "Darwin Kernel Version 10.8.0") && strings.Contains(vers, "root:xnu-1504.15.3~1/RELEASE_X86_64") {
+ t.Logf("skipping test on known-broken kernel (64-bit Snow Leopard)")
+ return
+ }
case "plan9":
// unimplemented
return
diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go
index 64ab84f4554..aa5e5607ca0 100644
--- a/libgo/go/strconv/extfloat.go
+++ b/libgo/go/strconv/extfloat.go
@@ -477,7 +477,7 @@ func (f *extFloat) ShortestDecimal(d *decimal, lower, upper *extFloat) bool {
// all data is known with a error estimate of ulpBinary*ε.
func adjustLastDigit(d *decimal, currentDiff, targetDiff, maxDiff, ulpDecimal, ulpBinary uint64) bool {
if ulpDecimal < 2*ulpBinary {
- // Appromixation is too wide.
+ // Approximation is too wide.
return false
}
for currentDiff+ulpDecimal/2+ulpBinary < targetDiff {
diff --git a/libgo/go/strings/example_test.go b/libgo/go/strings/example_test.go
index 0b583411331..daeb85ef6bb 100644
--- a/libgo/go/strings/example_test.go
+++ b/libgo/go/strings/example_test.go
@@ -41,6 +41,7 @@ func ExampleContainsAny() {
func ExampleCount() {
fmt.Println(strings.Count("cheese", "e"))
fmt.Println(strings.Count("five", "")) // before & after each rune
+
// Output:
// 3
// 5
diff --git a/libgo/go/sync/example_test.go b/libgo/go/sync/example_test.go
index 1424b1e79e6..15649240035 100644
--- a/libgo/go/sync/example_test.go
+++ b/libgo/go/sync/example_test.go
@@ -5,6 +5,7 @@
package sync_test
import (
+ "fmt"
"net/http"
"sync"
)
@@ -32,3 +33,22 @@ func ExampleWaitGroup() {
// Wait for all HTTP fetches to complete.
wg.Wait()
}
+
+func ExampleOnce() {
+ var once sync.Once
+ onceBody := func() {
+ fmt.Printf("Only once\n")
+ }
+ done := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go func() {
+ once.Do(onceBody)
+ done <- true
+ }()
+ }
+ for i := 0; i < 10; i++ {
+ <-done
+ }
+ // Output:
+ // Only once
+}
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index 3e7d9d3c8f4..0165b1ffb2b 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -11,21 +11,6 @@ import "sync/atomic"
// goroutines to wait for. Then each of the goroutines
// runs and calls Done when finished. At the same time,
// Wait can be used to block until all goroutines have finished.
-//
-// For example:
-//
-// for i := 0; i < n; i++ {
-// if !condition(i) {
-// continue
-// }
-// wg.Add(1)
-// go func() {
-// // Do something.
-// wg.Done()
-// }()
-// }
-// wg.Wait()
-//
type WaitGroup struct {
m Mutex
counter int32
diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go
index 7a2e95ca2a2..6d36e3985f3 100644
--- a/libgo/go/syscall/socket.go
+++ b/libgo/go/syscall/socket.go
@@ -217,6 +217,13 @@ func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
//sys getsockopt(s int, level int, name int, val uintptr, vallen *Socklen_t) (err error)
//getsockopt(s int, level int, name int, val *byte, vallen *Socklen_t) int
+func GetsockoptByte(fd, level, opt int) (value byte, err error) {
+ var n byte
+ vallen := Socklen_t(1)
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return n, err
+}
+
func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := Socklen_t(4)
@@ -254,6 +261,11 @@ func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
//sys setsockopt(s int, level int, name int, val *byte, vallen Socklen_t) (err error)
//setsockopt(s int, level int, optname int, val *byte, vallen Socklen_t) int
+func SetsockoptByte(fd, level, opt int, value byte) (err error) {
+ var n = byte(value)
+ return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), 1)
+}
+
func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), 4)
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index 7f8ff2d0541..671c798760b 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -19,7 +19,7 @@ type InternalExample struct {
Output string
}
-func RunExamples(examples []InternalExample) (ok bool) {
+func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
ok = true
var eg InternalExample
@@ -27,6 +27,14 @@ func RunExamples(examples []InternalExample) (ok bool) {
stdout, stderr := os.Stdout, os.Stderr
for _, eg = range examples {
+ matched, err := matchString(*match, eg.Name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
if *chatty {
fmt.Printf("=== RUN: %s\n", eg.Name)
}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index adc8c09f217..477d2ac23ae 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -99,7 +99,7 @@ var (
// Report as tests are run; default is silent for success.
chatty = flag.Bool("test.v", false, "verbose: print additional output")
- match = flag.String("test.run", "", "regular expression to select tests to run")
+ match = flag.String("test.run", "", "regular expression to select tests and examples to run")
memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
@@ -280,7 +280,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
before()
startAlarm()
testOk := RunTests(matchString, tests)
- exampleOk := RunExamples(examples)
+ exampleOk := RunExamples(matchString, examples)
if !testOk || !exampleOk {
fmt.Println("FAIL")
os.Exit(1)
diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go
index ae91f4a5419..10e0f7fc373 100644
--- a/libgo/go/text/template/doc.go
+++ b/libgo/go/text/template/doc.go
@@ -142,11 +142,6 @@ An argument is a simple value, denoted by one of the following.
.Field1.Key1.Method1.Field2.Key2.Method2
Methods can also be evaluated on variables, including chaining:
$x.Method1.Field
- - The name of a niladic function-valued struct field of the data,
- preceded by a period, such as
- .Function
- Function-valued fields behave like methods (of structs) but do not
- pass a receiver.
- The name of a niladic function, such as
fun
The result is the value of invoking the function, fun(). The return
@@ -155,6 +150,10 @@ An argument is a simple value, denoted by one of the following.
Arguments may evaluate to any type; if they are pointers the implementation
automatically indirects to the base type when required.
+If an evaluation yields a function value, such as a function-valued
+field of a struct, the function is not invoked automatically, but it
+can be used as a truth value for an if action and the like. To invoke
+it, use the call function, defined below.
A pipeline is a possibly chained sequence of "commands". A command is a simple
value (argument) or a function or method call, possibly with multiple arguments:
@@ -167,9 +166,6 @@ value (argument) or a function or method call, possibly with multiple arguments:
The result is the value of calling the method with the
arguments:
dot.Method(Argument1, etc.)
- .Function [Argument...]
- A function-valued field of a struct works like a method but does
- not pass the receiver.
functionName [Argument...]
The result is the value of calling the function associated
with the name:
@@ -257,6 +253,17 @@ Predefined global functions are named as follows.
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
+ call
+ Returns the result of calling the first argument, which
+ must be a function, with the remaining arguments as parameters.
+ Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
+ Y is a func-valued field, map entry, or the like.
+ The first argument must be the result of an evaluation
+ that yields a value of function type (as distinct from
+ a predefined function such as print). The function must
+ return either one or two result values, the second of which
+ is of type error. If the arguments don't match the function
+ or the returned error value is non-nil, execution stops.
html
Returns the escaped HTML equivalent of the textual
representation of its arguments.
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index af745286c0b..ad0118e4e68 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -421,11 +421,8 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
field := receiver.FieldByIndex(tField.Index)
if tField.PkgPath == "" { // field is exported
// If it's a function, we must call it.
- if field.Type().Kind() == reflect.Func {
- return s.evalCall(dot, field, fieldName, args, final)
- }
if hasArgs {
- s.errorf("%s is not a method or function but has arguments", fieldName)
+ s.errorf("%s has arguments but cannot be invoked as function", fieldName)
}
return field
}
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index 159cf5100d9..70ab39cad20 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -60,7 +60,9 @@ type T struct {
PSI *[]int
NIL *int
// Function (not method)
- Func func(...string) string
+ BinaryFunc func(string, string) string
+ VariadicFunc func(...string) string
+ VariadicFuncInt func(int, ...string) string
// Template to test evaluation of templates.
Tmpl *Template
}
@@ -120,7 +122,9 @@ var tVal = &T{
Err: errors.New("erroozle"),
PI: newInt(23),
PSI: newIntSlice(21, 22, 23),
- Func: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
+ BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
+ VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
+ VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
}
@@ -300,13 +304,26 @@ var execTests = []execTest{
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
"true", tVal, true},
- // Function call
- {".Func", "-{{.Func}}-", "-<>-", tVal, true},
- {".Func2", "-{{.Func `he` `llo`}}-", "-<he+llo>-", tVal, true},
+ // Function call builtin.
+ {".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
+ {".VariadicFunc0", "{{call .VariadicFunc}}", "<>", tVal, true},
+ {".VariadicFunc2", "{{call .VariadicFunc `he` `llo`}}", "<he+llo>", tVal, true},
+ {".VariadicFuncInt", "{{call .VariadicFuncInt 33 `he` `llo`}}", "33=<he+llo>", tVal, true},
+ {"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true},
+ {"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
+
+ // Erroneous function calls (check args).
+ {".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
+ {".BinaryFuncTooMany", "{{call .BinaryFunc `1` `2` `3`}}", "", tVal, false},
+ {".BinaryFuncBad0", "{{call .BinaryFunc 1 3}}", "", tVal, false},
+ {".BinaryFuncBad1", "{{call .BinaryFunc `1` 3}}", "", tVal, false},
+ {".VariadicFuncBad0", "{{call .VariadicFunc 3}}", "", tVal, false},
+ {".VariadicFuncIntBad0", "{{call .VariadicFuncInt}}", "", tVal, false},
+ {".VariadicFuncIntBad`", "{{call .VariadicFuncInt `x`}}", "", tVal, false},
// Pipelines.
{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
- {"pipeline func", "-{{.Func `llo` | .Func `he` }}-", "-<he+<llo>>-", tVal, true},
+ {"pipeline func", "-{{call .VariadicFunc `llo` | call .VariadicFunc `he` }}-", "-<he+<llo>>-", tVal, true},
// If.
{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go
index d6e4bf1a216..525179cb499 100644
--- a/libgo/go/text/template/funcs.go
+++ b/libgo/go/text/template/funcs.go
@@ -24,6 +24,7 @@ type FuncMap map[string]interface{}
var builtins = FuncMap{
"and": and,
+ "call": call,
"html": HTMLEscaper,
"index": index,
"js": JSEscaper,
@@ -151,6 +152,53 @@ func length(item interface{}) (int, error) {
return 0, fmt.Errorf("len of type %s", v.Type())
}
+// Function invocation
+
+// call returns the result of evaluating the the first argument as a function.
+// The function must return 1 result, or 2 results, the second of which is an error.
+func call(fn interface{}, args ...interface{}) (interface{}, error) {
+ v := reflect.ValueOf(fn)
+ typ := v.Type()
+ if typ.Kind() != reflect.Func {
+ return nil, fmt.Errorf("non-function of type %s", typ)
+ }
+ if !goodFunc(typ) {
+ return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
+ }
+ numIn := typ.NumIn()
+ var dddType reflect.Type
+ if typ.IsVariadic() {
+ if len(args) < numIn-1 {
+ return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
+ }
+ dddType = typ.In(numIn - 1).Elem()
+ } else {
+ if len(args) != numIn {
+ return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
+ }
+ }
+ argv := make([]reflect.Value, len(args))
+ for i, arg := range args {
+ value := reflect.ValueOf(arg)
+ // Compute the expected type. Clumsy because of variadics.
+ var argType reflect.Type
+ if !typ.IsVariadic() || i < numIn-1 {
+ argType = typ.In(i)
+ } else {
+ argType = dddType
+ }
+ if !value.Type().AssignableTo(argType) {
+ return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
+ }
+ argv[i] = reflect.ValueOf(arg)
+ }
+ result := v.Call(argv)
+ if len(result) == 2 {
+ return result[0].Interface(), result[1].Interface().(error)
+ }
+ return result[0].Interface(), nil
+}
+
// Boolean logic.
func truth(a interface{}) bool {
diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go
index f205e6be1b4..22dedc4f839 100644
--- a/libgo/go/text/template/multi_test.go
+++ b/libgo/go/text/template/multi_test.go
@@ -265,6 +265,12 @@ func TestRedefinition(t *testing.T) {
if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
t.Fatalf("parse 1: %v", err)
}
+ if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "redefinition") {
+ t.Fatalf("expected redefinition error; got %v", err)
+ }
if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil {
t.Fatal("expected error")
}
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index 35194f7dfdb..d67b3888085 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -193,6 +193,8 @@ func (t *Tree) add(treeSet map[string]*Tree) {
// IsEmptyTree reports whether this tree (node) is empty of everything but space.
func IsEmptyTree(n Node) bool {
switch n := n.(type) {
+ case nil:
+ return true
case *ActionNode:
case *IfNode:
case *ListNode:
diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go
index efa7d8be742..18c0a8b835e 100644
--- a/libgo/go/text/template/parse/parse_test.go
+++ b/libgo/go/text/template/parse/parse_test.go
@@ -287,6 +287,9 @@ var isEmptyTests = []isEmptyTest{
}
func TestIsEmpty(t *testing.T) {
+ if !IsEmptyTree(nil) {
+ t.Errorf("nil tree is not empty")
+ }
for _, test := range isEmptyTests {
tree, err := New("root").Parse(test.input, "", "", make(map[string]*Tree), nil)
if err != nil {
diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go
index 7494f9d8c45..82fc9e5e39d 100644
--- a/libgo/go/text/template/template.go
+++ b/libgo/go/text/template/template.go
@@ -178,10 +178,11 @@ func (t *Template) Parse(text string) (*Template, error) {
tmpl = t.New(name)
}
// Even if t == tmpl, we need to install it in the common.tmpl map.
- if err := t.associate(tmpl); err != nil {
+ if replace, err := t.associate(tmpl, tree); err != nil {
return nil, err
+ } else if replace {
+ tmpl.Tree = tree
}
- tmpl.Tree = tree
tmpl.leftDelim = t.leftDelim
tmpl.rightDelim = t.rightDelim
}
@@ -191,22 +192,23 @@ func (t *Template) Parse(text string) (*Template, error) {
// associate installs the new template into the group of templates associated
// with t. It is an error to reuse a name except to overwrite an empty
// template. The two are already known to share the common structure.
-func (t *Template) associate(new *Template) error {
+// The boolean return value reports wither to store this tree as t.Tree.
+func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
if new.common != t.common {
panic("internal error: associate not common")
}
name := new.name
if old := t.tmpl[name]; old != nil {
oldIsEmpty := parse.IsEmptyTree(old.Root)
- newIsEmpty := new.Tree != nil && parse.IsEmptyTree(new.Root)
- if !oldIsEmpty && !newIsEmpty {
- return fmt.Errorf("template: redefinition of template %q", name)
- }
+ newIsEmpty := parse.IsEmptyTree(tree.Root)
if newIsEmpty {
// Whether old is empty or not, new is empty; no reason to replace old.
- return nil
+ return false, nil
+ }
+ if !oldIsEmpty {
+ return false, fmt.Errorf("template: redefinition of template %q", name)
}
}
t.tmpl[name] = new
- return nil
+ return true, nil
}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index ef6f1f33514..ad52bab216f 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -6,14 +6,6 @@ package time
import "errors"
-const (
- numeric = iota
- alphabetic
- separator
- plus
- minus
-)
-
// These are predefined layouts for use in Time.Format.
// The standard time used in the layouts is:
// Mon Jan 2 15:04:05 MST 2006
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index e572b678419..440d3b42f12 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -120,8 +120,11 @@ func TestAfterTick(t *testing.T) {
t1 := Now()
d := t1.Sub(t0)
target := Delta * Count
- if d < target*9/10 || d > target*30/10 {
- t.Fatalf("%d ticks of %s took %s, expected %s", Count, Delta, d, target)
+ if d < target*9/10 {
+ t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target)
+ }
+ if !testing.Short() && d > target*30/10 {
+ t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target)
}
}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index 709a4226724..f7ded24d292 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -152,7 +152,7 @@ func (d Weekday) String() string { return days[d] }
// rely heavily on division and modulus by positive constants. For
// calendrical calculations we want these divisions to round down, even
// for negative values, so that the remainder is always positive, but
-// Go's division (like most hardware divison instructions) rounds to
+// Go's division (like most hardware division instructions) rounds to
// zero. We can still do those computations and then adjust the result
// for a negative numerator, but it's annoying to write the adjustment
// over and over. Instead, we can change to a different epoch so long
@@ -384,6 +384,15 @@ type Duration int64
// Common durations. There is no definition for units of Day or larger
// to avoid confusion across daylight savings time zone transitions.
+//
+// To count the number of units in a Duration, divide:
+// second := time.Second
+// fmt.Print(int64(second/time.Millisecond)) // prints 1000
+//
+// To convert an integer number of units to a Duration, multiply:
+// seconds := 10
+// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
+//
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
@@ -758,10 +767,6 @@ func (t Time) UnixNano() int64 {
return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
}
-type gobError string
-
-func (g gobError) Error() string { return string(g) }
-
const timeGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
diff --git a/libgo/runtime/go-main.c b/libgo/runtime/go-main.c
index 5871981f2b8..7e8bb9b234f 100644
--- a/libgo/runtime/go-main.c
+++ b/libgo/runtime/go-main.c
@@ -40,7 +40,7 @@ static void mainstart (void *);
int
main (int argc, char **argv)
{
- runtime_initsig ();
+ runtime_check ();
runtime_args (argc, (byte **) argv);
runtime_osinit ();
runtime_schedinit ();
diff --git a/libgo/runtime/lock_futex.c b/libgo/runtime/lock_futex.c
index cdc12d7c75c..9a533a577a4 100644
--- a/libgo/runtime/lock_futex.c
+++ b/libgo/runtime/lock_futex.c
@@ -118,8 +118,12 @@ runtime_notewakeup(Note *n)
void
runtime_notesleep(Note *n)
{
+ if(runtime_m()->profilehz > 0)
+ runtime_setprof(false);
while(runtime_atomicload(&n->key) == 0)
runtime_futexsleep(&n->key, 0, -1);
+ if(runtime_m()->profilehz > 0)
+ runtime_setprof(true);
}
void
@@ -135,14 +139,18 @@ runtime_notetsleep(Note *n, int64 ns)
if(runtime_atomicload(&n->key) != 0)
return;
+ if(runtime_m()->profilehz > 0)
+ runtime_setprof(false);
deadline = runtime_nanotime() + ns;
for(;;) {
runtime_futexsleep(&n->key, 0, ns);
if(runtime_atomicload(&n->key) != 0)
- return;
+ break;
now = runtime_nanotime();
if(now >= deadline)
- return;
+ break;
ns = deadline - now;
}
+ if(runtime_m()->profilehz > 0)
+ runtime_setprof(true);
}
diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c
index b2a8f53be41..8c4b3973bdc 100644
--- a/libgo/runtime/lock_sema.c
+++ b/libgo/runtime/lock_sema.c
@@ -159,7 +159,11 @@ runtime_notesleep(Note *n)
return;
}
// Queued. Sleep.
+ if(m->profilehz > 0)
+ runtime_setprof(false);
runtime_semasleep(-1);
+ if(m->profilehz > 0)
+ runtime_setprof(true);
}
void
@@ -185,12 +189,16 @@ runtime_notetsleep(Note *n, int64 ns)
return;
}
+ if(m->profilehz > 0)
+ runtime_setprof(false);
deadline = runtime_nanotime() + ns;
for(;;) {
// Registered. Sleep.
if(runtime_semasleep(ns) >= 0) {
// Acquired semaphore, semawakeup unregistered us.
// Done.
+ if(m->profilehz > 0)
+ runtime_setprof(true);
return;
}
@@ -203,6 +211,9 @@ runtime_notetsleep(Note *n, int64 ns)
ns = deadline - now;
}
+ if(m->profilehz > 0)
+ runtime_setprof(true);
+
// Deadline arrived. Still registered. Semaphore not acquired.
// Want to give up and return, but have to unregister first,
// so that any notewakeup racing with the return does not
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 23641e8298f..3fde250af3b 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -277,6 +277,7 @@ runtime_mallocinit(void)
uintptr arena_size, bitmap_size;
extern byte end[];
byte *want;
+ uintptr limit;
runtime_sizeof_C_MStats = sizeof(MStats);
@@ -291,10 +292,12 @@ runtime_mallocinit(void)
runtime_InitSizes();
+ limit = runtime_memlimit();
+
// Set up the allocation arena, a contiguous area of memory where
// allocated data will be found. The arena begins with a bitmap large
// enough to hold 4 bits per allocated word.
- if(sizeof(void*) == 8) {
+ if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
// On a 64-bit machine, allocate from a single contiguous reservation.
// 16 GB should be big enough for now.
//
@@ -343,6 +346,10 @@ runtime_mallocinit(void)
// of address space, which is probably too much in a 32-bit world.
bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
arena_size = 512<<20;
+ if(limit > 0 && arena_size+bitmap_size > limit) {
+ bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
+ arena_size = bitmap_size * 8;
+ }
// SysReserve treats the address we ask for, end, as a hint,
// not as an absolute requirement. If we ask for the end
@@ -359,6 +366,8 @@ runtime_mallocinit(void)
p = runtime_SysReserve(want, bitmap_size + arena_size);
if(p == nil)
runtime_throw("runtime: cannot reserve arena virtual address space");
+ if((uintptr)p & (((uintptr)1<<PageShift)-1))
+ runtime_printf("runtime: SysReserve returned unaligned address %p; asked for %p", p, (void*)(bitmap_size+arena_size));
}
if((uintptr)p & (((uintptr)1<<PageShift)-1))
runtime_throw("runtime: SysReserve returned unaligned address");
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index d852946cdbb..4aa7c45dcb3 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -654,14 +654,6 @@ markfin(void *v)
scanblock(v, size);
}
-struct root_list {
- struct root_list *next;
- struct root {
- void *decl;
- size_t size;
- } roots[];
-};
-
static struct root_list* roots;
void
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
index 79359d9dfca..6bf38aa9934 100644
--- a/libgo/runtime/mheap.c
+++ b/libgo/runtime/mheap.c
@@ -326,7 +326,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
}
// Release (part of) unused memory to OS.
-// Goroutine created in runtime_schedinit.
+// Goroutine created at startup.
// Loop forever.
void
runtime_MHeap_Scavenger(void* dummy)
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index d0ae09c45a0..31e8287e704 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -416,8 +416,6 @@ runtime_schedinit(void)
// Can not enable GC until all roots are registered.
// mstats.enablegc = 1;
m->nomemprof--;
-
- scvg = __go_go(runtime_MHeap_Scavenger, nil);
}
extern void main_init(void) __asm__ ("__go_init_main");
@@ -435,6 +433,7 @@ runtime_main(void)
// to preserve the lock.
runtime_LockOSThread();
runtime_sched.init = true;
+ scvg = __go_go(runtime_MHeap_Scavenger, nil);
main_init();
runtime_sched.init = false;
if(!runtime_sched.lockmain)
@@ -548,7 +547,7 @@ mcommoninit(M *m)
m->mcache = runtime_allocmcache();
runtime_callers(1, m->createstack, nelem(m->createstack));
-
+
// Add to runtime_allm so garbage collector doesn't free m
// when it is just in a register or thread-local storage.
m->alllink = runtime_allm;
@@ -791,10 +790,11 @@ top:
mput(m);
}
- // Look for deadlock situation: one single active g which happens to be scvg.
- if(runtime_sched.grunning == 1 && runtime_sched.gwait == 0) {
- if(scvg->status == Grunning || scvg->status == Gsyscall)
- runtime_throw("all goroutines are asleep - deadlock!");
+ // Look for deadlock situation.
+ if((scvg == nil && runtime_sched.grunning == 0) ||
+ (scvg != nil && runtime_sched.grunning == 1 && runtime_sched.gwait == 0 &&
+ (scvg->status == Grunning || scvg->status == Gsyscall))) {
+ runtime_throw("all goroutines are asleep - deadlock!");
}
m->nextg = nil;
@@ -1135,6 +1135,9 @@ runtime_entersyscall(void)
{
uint32 v;
+ if(m->profilehz > 0)
+ runtime_setprof(false);
+
// Leave SP around for gc and traceback.
#ifdef USING_SPLIT_STACK
g->gcstack = __splitstack_find(NULL, NULL, &g->gcstack_size,
@@ -1205,6 +1208,9 @@ runtime_exitsyscall(void)
#endif
gp->gcnext_sp = nil;
runtime_memclr(gp->gcregs, sizeof gp->gcregs);
+
+ if(m->profilehz > 0)
+ runtime_setprof(true);
return;
}
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
index 7c8c436deeb..78c865ba175 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime.c
@@ -184,6 +184,21 @@ runtime_fastrand1(void)
return x;
}
+static struct root_list runtime_roots =
+{ NULL,
+ { { &syscall_Envs, sizeof syscall_Envs },
+ { &os_Args, sizeof os_Args },
+ { NULL, 0 } },
+};
+
+void
+runtime_check(void)
+{
+ __go_register_gc_roots(&runtime_roots);
+
+ runtime_initsig ();
+}
+
int64
runtime_cputicks(void)
{
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 113bb7163c5..40c59a82777 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -427,6 +427,8 @@ void runtime_osyield(void);
void runtime_LockOSThread(void) __asm__("libgo_runtime.runtime.LockOSThread");
void runtime_UnlockOSThread(void) __asm__("libgo_runtime.runtime.UnlockOSThread");
+uintptr runtime_memlimit(void);
+
// If appropriate, ask the operating system to control whether this
// thread should receive profiling signals. This is only necessary on OS X.
// An operating system should not deliver a profiling signal to a
@@ -441,3 +443,16 @@ void runtime_time_scan(void (*)(byte*, int64));
void runtime_setsig(int32, bool, bool);
#define runtime_setitimer setitimer
+
+void runtime_check(void);
+
+// A list of global variables that the garbage collector must scan.
+struct root_list {
+ struct root_list *next;
+ struct root {
+ void *decl;
+ size_t size;
+ } roots[];
+};
+
+void __go_register_gc_roots(struct root_list*);
diff --git a/libgo/runtime/thread-linux.c b/libgo/runtime/thread-linux.c
index 8dd5fc4b481..6a69fb429a4 100644
--- a/libgo/runtime/thread-linux.c
+++ b/libgo/runtime/thread-linux.c
@@ -3,6 +3,16 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "defs.h"
+
+// Linux futex.
+//
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
#include <errno.h>
#include <string.h>
diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c
index 748a62d59f5..12d009926e3 100644
--- a/libgo/runtime/thread.c
+++ b/libgo/runtime/thread.c
@@ -4,6 +4,8 @@
#include <errno.h>
#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include "runtime.h"
#include "go-assert.h"
@@ -138,6 +140,7 @@ runtime_minit(void)
byte* stack;
size_t stacksize;
stack_t ss;
+ sigset_t sigs;
// Initialize signal handling.
runtime_m()->gsignal = runtime_malg(32*1024, &stack, &stacksize); // OS X wants >=8K, Linux >=2K
@@ -146,4 +149,34 @@ runtime_minit(void)
ss.ss_size = stacksize;
if(sigaltstack(&ss, nil) < 0)
*(int *)0xf1 = 0xf1;
+ if (sigemptyset(&sigs) != 0)
+ runtime_throw("sigemptyset");
+ sigprocmask(SIG_SETMASK, &sigs, nil);
+}
+
+uintptr
+runtime_memlimit(void)
+{
+ struct rlimit rl;
+ uintptr used;
+
+ if(getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
}